android+gallery+优化,Android--从系统Camera和Gallery获取图片优化
发布日期:2022-02-19 00:02:14 浏览次数:7 分类:技术文章

本文共 4916 字,大约阅读时间需要 16 分钟。

前言

之前有两篇博客讲解了如何从系统内已有的Camera和Gallery应用中获取图片的例子,看到评论里有朋友说有时候会报错,导致程序崩溃的 问题。本篇博客主要就这个问题分析讲解一下,最后将以一个简单的Demo演示。关于从系统内已有的Camera和Gallery应用中获取图片还不了解的 朋友,可以先看看另外两篇博客:Android--调用系统照相机拍照与摄像、Android--从系统Gallery获取图片。

分析出错原因

之前讲到的从系统现有的Camera和Gallery应用中获取图片的Demo中,均直接使用系统应用返回的Uri,通过 ImageView.setImageURI(Uri)方法显示在界面上。而对于Android设备来说,向内存中加载一张图片,消耗的内存并不受图片的 大小而影响,影响它的是图片的分辨率,图片的分辨率越大加载到内存所占用的内存将越多。使用ImageView.setImageURI(Uri)方法将 导致了一个严重的错误,虽然ImageView直接引用图片的Uri,它会对图片进行一部分优化,使得它可以正常显示,但是这种办法不利于Bitmap资 源的回收。所以在重复操作之后,经历过多次的GC,也没有办法回收出足够加载图片的内存,导致应用崩溃。

解决方案

既然已经知道导致程序崩溃的原因是内存溢出导致的,那么只需要维护好Uri所代表的图片内存即可。具体优化流程如下:

1、系统中现有的Camera和Gallery应用获取图片返回的都是一个Uri类型的数据,它是一个内容提供者的路径,可以使用ContentResolver获取它,这个以前有讲过,不了解的朋友可以看看另外一篇博客:Android--ContentProvider。而在Context中,可以使用getContentResolver()方法获取到当前的内容解析者,并通过它的openInputStream()方法获取到图片的输入流,通过输入流可以获取到一个Bitmap对象。

2、上面提到,Android中加载图片到内存中所占内存的大小取决于图片的分辨率,所有得到Bitmap还不能直接使用它,必须对其进行优 化,以最大适应当前设备的屏幕分辩率又不会导致加载过多像素而导致内存不足的情况。关于加载大分辨率到内存还不了解的朋友可以参见另外一篇博客:Android--加载大分辨率图片到内存。

3、得到了优化过后的图片还需要在使用过后进行回收,Bitmap提供了两个方法用于判断是否已经回收它以及强制Bitmap回收自己。以下是它们的完整签名:

boolean isRecycled():返回Bitmap对象是否已经被回收。

void recycle():强制一个Bitmap对象回收自己。

优化后的Demo

上面讲到的两个demo,从Gallery中获取图片比较简单,代码量小,那么就在这个基础之上进行代码的优化。从Gallery中获取图片的Uri并不直接使用,而是把它转化为一个Bitmap,并且优化它以达到适应屏幕分辨率的效果。

package cn.bgxt.sysgallerydemo;

import java.io.InputStream;

import android.net.Uri;

import android.os.Bundle;

import android.util.Log;

import android.view.View;

import android.view.WindowManager;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.ImageView;

import android.widget.Toast;

import android.app.Activity;

import android.content.Intent;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.BitmapFactory.Options;

import android.graphics.Matrix;

import android.graphics.Paint;

public class MainActivity extends Activity {

private Button btn_getImage;

private ImageView iv_image;

private final static String TAG = "main";

private WindowManager wm;

private Bitmap bitmap;

private Bitmap blankBitmap;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

// 得到应用窗口管理器

wm = getWindowManager();

btn_getImage = (Button) findViewById(R.id.btn_getImage);

iv_image = (ImageView) findViewById(R.id.iv_image);

btn_getImage.setOnClickListener(getImage);

}

private View.OnClickListener getImage = new OnClickListener() {

@Override

public void onClick(View v) {

// 设定action和miniType

Intent intent = new Intent();

intent.setAction(Intent.ACTION_PICK);

intent.setType("image/*");

// 以需要返回值的模式开启一个Activity

startActivityForResult(intent, 0);

}

};

@Override

protected void onActivityResult(int requestCode, int resultCode, Intent data) {

// 如果获取成功,resultCode为-1

Log.i(TAG, "resultCode:" + resultCode);

if (requestCode == 0 && resultCode == -1) {

// 获取原图的Uri,它是一个内容提供者的地址

Uri uri = data.getData();

Log.i(TAG, "uri:" + data.getData().toString());

try {

// 从ContentResolver中获取到Uri的输入流

InputStream is = getContentResolver().openInputStream(uri);

// 得到屏幕的宽和高

int windowWidth = wm.getDefaultDisplay().getWidth();

int windowHeight = wm.getDefaultDisplay().getHeight();

// 实例化一个Options对象

BitmapFactory.Options opts = new BitmapFactory.Options();

// 指定它只读取图片的信息而不加载整个图片

opts.inJustDecodeBounds = true;

// 通过这个Options对象,从输入流中读取图片的信息

BitmapFactory.decodeStream(is, null, opts);

// 得到Uri地址的图片的宽和高

int bitmapWidth = opts.outWidth;

int bitmapHeight = opts.outHeight;

// 分析图片的宽高比,用于进行优化

if (bitmapHeight > windowHeight || bitmapWidth > windowWidth) {

int scaleX = bitmapWidth / windowWidth;

int scaleY = bitmapHeight / windowHeight;

if (scaleX > scaleY) {

opts.inSampleSize = scaleX;

} else {

opts.inSampleSize = scaleY;

}

} else {

opts.inSampleSize = 1;

}

// 设定读取完整的图片信息

opts.inJustDecodeBounds = false;

is = getContentResolver().openInputStream(uri);

// 如果没有被系统回收,就强制回收它

if (blankBitmap != null && !bitmap.isRecycled()) {

bitmap.recycle();

}

bitmap = BitmapFactory.decodeStream(is, null, opts);

// 如果没有被系统回收,就强制回收它

if (blankBitmap != null && !blankBitmap.isRecycled()) {

blankBitmap.recycle();

}

// 在内存中创建一个可以操作的Bitmap对象

blankBitmap = Bitmap.createBitmap(bitmap.getWidth(),

bitmap.getHeight(), Bitmap.Config.ARGB_8888);

// 为图片添加一个画板

Canvas canvas = new Canvas(blankBitmap);

// 把读取的图片画到新创建的Bitmap对象中

canvas.drawBitmap(bitmap, new Matrix(), new Paint());

Paint paint = new Paint();

paint.setColor(Color.RED);

paint.setTextSize(30);

// 通过创建的画笔,在Bitmap上写入水印

canvas.drawText("我是水印", 10, 50, paint);

iv_image.setImageBitmap(blankBitmap);

} catch (Exception e) {

Toast.makeText(MainActivity.this, "获取图片失败", 0).show();

}

}

super.onActivityResult(requestCode, resultCode, data);

}

}

效果展示:

cfca90e344d59a613e282945cf29f186.png

06dedcb69ac9ed2bcdef03293b1b1f94.png

7cab4c6962789639b09ddacb37c6d8ed.png

总结

其实对于这两个简单的Demo而言,只需要针对分辨率进行优化即可,一般而言因为功能简单,系统配置只要还过的去,都是可以被正常GC的,但是 对于一些经常操作图片的应用来说,还是显式的通过代码的方式来管理Bitmap的内存。最后加入Canvas进行渲染水印,不是必须的,只是加了个功能而 已,直接使用bitmap对象也可以。

转载地址:https://blog.csdn.net/weixin_34236334/article/details/117659991 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:android okhttp3 底层,Android okhttp3 SSL握手底层实现追踪
下一篇:html十六进制在线转义,javascript转义unicode十六进制编码且带有反斜杠后的html-站长资讯中心...

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2024年03月24日 21时19分18秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

matlab里inline定义矩阵,Matlab中的inline函数_matlab中inline函数 2019-04-21
php html标签自定义属性,浅谈JS读取DOM对象(标签)的自定义属性 2019-04-21
如何使用matlab的siso,利用Matlab内建程式SISODesignTool完成系统分析(Matlab61)开启.PDF... 2019-04-21
php 实现 model层,Thinkhphp5控制器调用的Model层的方法总结 2019-04-21
matlab6.0序列号,MFC软件获取USB设备的制造商、产品、序列号 2019-04-21
matlab中多边形滤波器,几种常见空间滤波器MATLAB实现 2019-04-21
matlab fminimax 例子,Matlab应用实例(8)—fminimax 2019-04-21
php://filter利用条件,浅谈php://filter技巧 2019-04-21
mplayer-php,mplayer+smplayer 前后端播放器安装 2019-04-21
oracle昨日时间,。。今日,昨日,上周,本月,本年,按时间统计总金额 2019-04-21
php验证卡号,PHP验证信用卡卡号是否正确函数 2019-04-21
mpvue微信小程序动画_推荐两个微信小程序开发框架 2019-04-21
固态硬盘分为哪几种_零基础玩转固态硬盘 深度排雷 买SSD掌握这些就够了 2019-04-21
调python返回图片_Python异常处理,3个好习惯分享给你 2019-04-21
15拆解_收藏:15款劲芯微芯片无线充产品拆解 2019-04-21
弹出u盘_都说:U盘直接拔出不会丢失文件,“安全弹出”形同虚设,对吗? 2019-04-21
怎么查看elementui版本_2021新年 Vue3.0 + Element UI 尝鲜小记 2019-04-21
adreno630gpu参数_小米8搭载Adreno 630图形处理器 比荣耀play上的GPU Turbo更成熟 2019-04-21
带bitlocker解密的pe_如何在PE下解锁bitlocker 2019-04-21
lj245a引脚功能图_谁找到74254,74LS245芯片引脚的功能和功能图啊? 2019-04-21