您的位置:首页 > 移动开发 > Android开发

android 已省内存方式把图片加载到内存

2014-12-12 15:57 183 查看
这里,有个异步处理图片的方法,我直接把我这个类复制粘贴进来。注意内存要及时回收。android内存比较局限。

<span style="font-size:14px;">package com.commons.utils.image;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.*;
import android.os.Build;
import android.util.Log;
import com.commons.config.GlobalConfig;
import com.commons.utils.memory.MemoryUtils;

import java.io.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 从DrawableUtil类中分离出来这个类,为了使代码看起来更加简洁明了
 * 用于Bitmap处理的一些方法
 */
public class BitmapUtils {
    public static final int ARGB8888_MODEL=4;//ARGB8888模式下消耗内存,为像素数乘以4个字节.
    public static final int RGB565_MODEL=2;//RGB565模式下消耗内存,为像素数乘以4个字节.
    /**
     * 获取APP剩余可申请内存,判断是否够大,以手机分辨率为基础,进行计算图片处理所需要消耗的内存.
     * @return
     *
     * !!!这里获取的不是手机的剩余内存而是APP的
     */
    public static boolean isBigSurpluseMemory(Context context)
    {
        boolean isbig=true;//默认
        long appsurplusMe= MemoryUtils.getAppSurplusMe();//这里单位是Byte
        long phonesurplusMe= MemoryUtils.getPhoneSurplusMe(context);//这里单位是Byte
        long bitmapoptNeedmemory=GlobalConfig.scrwid*GlobalConfig.scrhei*ARGB8888_MODEL;//单位依旧是Byte
        //在进行图片处理的时候会把图片分辨率缩小到屏幕分辨率大小,所以这里消耗内存的计算是以屏幕分辨率所谓基础的.
        if(bitmapoptNeedmemory*2 > appsurplusMe)//为了其他考虑,剩余内存应该大于所需要内存的两倍
        {
            return false;
        }

        if(bitmapoptNeedmemory*2>phonesurplusMe)
        {
            return  false;
        }//这里一定要判断手机剩余内存,上面的判断只是app的理论上的内存限制,而如果手机本身就已经没有内存了,
        // 会有两种情况 1.自动清理一些内存  来给当前app用,2.本身就是内存太小,现在占内存的应用都是系统级别的清理不掉,那就坑了
        // 举个例子:125M内存的手机上就会发生当手机时,我发现内存不够的时候,android的自动杀进程的机制就没法用了
        //请看如下的我在410M的手机上运行的结果

        return isbig;
    }
    /**
     12-11 16:52:35.260      441-441/com.jsdx.zqysypt D/MemoryUtils.printMemoryInfo()﹕ 常规应用最大内存限制:64M 流氓应用最大内存限制:128M
     12-11 16:52:35.270      441-441/com.jsdx.zqysypt D/MemoryUtils.printMemoryInfo()﹕ APP当前内存状态: 最大可申请内存:128MB 已申请内存:21MB 空闲内存:4MB
     12-11 16:52:35.270      441-441/com.jsdx.zqysypt D/MemoryUtils.printMemoryInfo()﹕ 手机剩余内存:70.12109MB 手机总内存:410.54297MB
     这里可以明显看出app剩余可申请的内存要大于手机的剩余内存的.当申请更多内存的时候android就会自动清理
     */

    /**
     * 创建倒影图片
     * @throws IOException
     */
    public static Bitmap createReflectedBitmap(Bitmap srcBitmap) {
        if (null == srcBitmap) {
            return null;
        }

        // The gap between the reflection bitmap and original bitmap.
        final int REFLECTION_GAP = 4;

        int srcWidth = srcBitmap.getWidth();
        int srcHeight = srcBitmap.getHeight();
        int reflectionWidth = srcBitmap.getWidth();
        int reflectionHeight = srcBitmap.getHeight() / 2;

        if (0 == srcWidth || srcHeight == 0) {
            return null;
        }

        // The matrix
        Matrix matrix = new Matrix();
        matrix.preScale(1, -1);

        try {
            // The reflection bitmap, width is same with original's, height is half of original's.
            Bitmap reflectionBitmap = Bitmap.createBitmap(
                    srcBitmap,
                    0,
                    srcHeight / 2,
                    srcWidth,
                    srcHeight / 2,
                    matrix,
                    false);

            if (null == reflectionBitmap) {
                return null;
            }

            // Create the bitmap which contains original and reflection bitmap.
            Bitmap bitmapWithReflection = Bitmap.createBitmap(
                    reflectionWidth,
                    srcHeight + reflectionHeight + REFLECTION_GAP,
                    Bitmap.Config.ARGB_8888);

            if (null == bitmapWithReflection) {
                return null;
            }

            // Prepare the canvas to draw stuff.
            Canvas canvas = new Canvas(bitmapWithReflection);

            // Draw the original bitmap.
            canvas.drawBitmap(srcBitmap, 0, 0, null);

            // Draw the reflection bitmap.
            canvas.drawBitmap(reflectionBitmap, 0, srcHeight + REFLECTION_GAP, null);

            Paint paint = new Paint();
            paint.setAntiAlias(true);
            LinearGradient shader = new LinearGradient(
                    0,
                    srcHeight,
                    0,
                    bitmapWithReflection.getHeight() + REFLECTION_GAP,
                    0x70FFFFFF,
                    0x00FFFFFF,
                    Shader.TileMode.MIRROR);
            paint.setShader(shader);
            paint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.DST_IN));

            // Draw the linear shader.
            canvas.drawRect(
                    0,
                    srcHeight,
                    srcWidth,
                    bitmapWithReflection.getHeight() + REFLECTION_GAP,
                    paint);

            return bitmapWithReflection;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public static Bitmap revitionImageSize(String path, int max_w, int max_h) throws IOException {
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(
                new File(path)));
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(in, null, options);
        in.close();
        int i = 0;
        Bitmap bitmap = null;
        while (true) {
            if ((options.outWidth >> i <= max_w)
                    && (options.outHeight >> i <= max_h)) {
                in = new BufferedInputStream(
                        new FileInputStream(new File(path)));
                options.inSampleSize = (int) Math.pow(2.0D, i);
                options.inJustDecodeBounds = false;
                bitmap = BitmapFactory.decodeStream(in, null, options);
                break;
            }
            i += 1;
        }
        return bitmap;
    }

    /**
     *将Bitmap保存到本地
     * @param bitmap
     * @param imgurl imgurl   不带file了开头的路径,如:  /strange/sdcard/asdasd.jpg
     */
    public static void savePictureToLocal(Bitmap bitmap, String imgurl) {
        FileOutputStream b = null;
        File file = new File(imgurl);
        file.getParentFile().mkdirs();// 创建文件夹

        //对图片质量进行压缩,这样保存的图片就变小了
        int yasuolv = 60;
        try {
            b = new FileOutputStream(imgurl);
            bitmap.compress(Bitmap.CompressFormat.JPEG, yasuolv, b);// 把数据写入文件
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                b.flush();
                b.close();
                //bitmap.recycle();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 得到本地或者网络上的bitmap url - 网络或者本地图片的绝对路径,比如:
     * <p/>
     * A.网络路径: url="http://blog.foreverlove.us/girl2.png" ;
     * <p/>
     * B.本地路径:url="mnt/sdcard/photo/image.png";  不带 file: 头
     * <p/>
     * C.支持的图片格式 ,png, jpg,bmp,gif等等
     *
     * @param path
     * @return
     */
    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
    public static Bitmap GetLocalOrNetBitmap(String path) {
        final String  TAG="GetLocalOrNetBitmap";
        Bitmap bitmap = null;
        try {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            bitmap = BitmapFactory.decodeFile(path, options); //此时返回 bm 为空
            options.inJustDecodeBounds = false; //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
            int hi = (int) (options.outHeight / (float) GlobalConfig.scrhei);//以屏幕高度作为显示依据
            int wi = (int) (options.outWidth / (float) GlobalConfig.scrwid);//以屏幕高度作为显示依据

            int be = 0;
            if (wi > hi)
                be = hi;
            else
                be = wi;

            Log.d(TAG, "缩放比:"+be); //缩放之后
            Log.d(TAG, "原图宽高:"+options.outWidth+" "+options.outHeight); //缩放之后

            if (be <= 0)
                be = 1;
            options.inSampleSize = be; //重新读入图片,注意此时已经把 options.inJustDecodeBounds 设回 false 了
            options.inPreferredConfig = Bitmap.Config.RGB_565;//使用RGB_565后会是内存降低一半但是,不适合decode带有透明区域的PNG
            bitmap = BitmapFactory.decodeFile(path, options);
            int w = bitmap.getWidth();
            int h = bitmap.getHeight();
            Log.d(TAG, "缩放后:宽"+w + " 高" + h); //缩放之后
            Log.d(TAG, "RGB_565格式内存:"+bitmap.getByteCount() / 1024 + "KB");
        }
        catch (Exception ex)
        {
            if(bitmap!=null&&!bitmap.isRecycled())
                bitmap.recycle();
            System.gc();  //提醒系统及时回收
        }
        return bitmap;
    }

    //同上,最后一个参数可选,配置是否返回高色彩的Bitmap
    //本地路径  不带 file: 头
    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
    public static Bitmap GetLocalOrNetBitmap(String path, boolean isRGb_565) {
        final String  TAG="GetLocalOrNetBitmap";
        Bitmap bitmap = null;
        try {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            bitmap = BitmapFactory.decodeFile(path, options); //此时返回 bm 为空
            options.inJustDecodeBounds = false; //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
            int hi = (int) (options.outHeight / (float) GlobalConfig.scrhei);//以屏幕高度作为显示依据
            int wi = (int) (options.outWidth / (float) GlobalConfig.scrwid);//以屏幕高度作为显示依据

            int be = 0;
            if (wi > hi)
                be = hi;
            else
                be = wi;

            Log.d(TAG, "缩放比:"+be); //缩放之后
            Log.d(TAG, "原图宽高:"+options.outWidth+" "+options.outHeight); //缩放之后

            if (be <= 0)
                be = 1;
            options.inSampleSize = be; //重新读入图片,注意此时已经把 options.inJustDecodeBounds 设回 false 了
            if(isRGb_565)
                options.inPreferredConfig = Bitmap.Config.RGB_565;//使用RGB_565后会是内存降低一半但是,不适合decode带有透明区域的PNG
            bitmap = BitmapFactory.decodeFile(path, options);
            int w = bitmap.getWidth();
            int h = bitmap.getHeight();
            Log.d(TAG, "缩放后:宽" + w + " 高" + h); //缩放之后
            Log.d(TAG, "RGB_565格式内存:"+bitmap.getByteCount() / 1024 + "KB");
        }
        catch (Exception ex)
        {
            if(bitmap!=null&&!bitmap.isRecycled())
                bitmap.recycle();
            System.gc();  //提醒系统及时回收
        }
        return bitmap;
    }

    //同上,最后一个参数可选,配置是否返回高色彩的Bitmap
    //本地路径  不带 file: 头
    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
    public static Bitmap GetLocalOrNetBitmap(String path, boolean isRGb_565,int maxwidth,int maxheight) {
        final String  TAG="GetLocalOrNetBitmap";
        Bitmap bitmap = null;
        try {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            Log.d("GetLocalOrNetBitmap",path);

            bitmap = BitmapFactory.decodeFile(path, options); //此时返回 bm 为空
            options.inJustDecodeBounds = false; //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
            int hi = (int) (options.outHeight / (float) maxwidth);//以指定宽度作为显示依据
            int wi = (int) (options.outWidth / (float) maxheight);//以指定高度作为显示依据

            int be = 0;
            if (wi < hi)
                be = hi;
            else
                be = wi;

            Log.d(TAG, "缩放比:"+be); //缩放之后
            Log.d(TAG, "原图宽高:"+options.outWidth+" "+options.outHeight); //缩放之后

            if (be <= 0)
                be = 1;
            options.inSampleSize = be; //重新读入图片,注意此时已经把 options.inJustDecodeBounds 设回 false 了
            if(isRGb_565)
                options.inPreferredConfig = Bitmap.Config.RGB_565;//使用RGB_565后会是内存降低一半但是,不适合decode带有透明区域的PNG
            bitmap = BitmapFactory.decodeFile(path, options);
            int w = bitmap.getWidth();
            int h = bitmap.getHeight();
            Log.d(TAG, "缩放后:宽" + w + " 高" + h); //缩放之后
            Log.d(TAG, "RGB_565格式内存:"+bitmap.getByteCount() / 1024 + "KB");
        }
        catch (Exception ex)
        {
            if(bitmap!=null&&!bitmap.isRecycled())
                bitmap.recycle();
            System.gc();  //提醒系统及时回收
        }
        return bitmap;
    }

    public static void createPath(String path) {
        File file = new File(path);
        if (!file.exists()) {
            file.mkdir();
        }
    }

    //传递两个参数即可 第一个是bitmap  第二个是目录名称,第二个参数为空时  保存在SD卡上
    public static void saveMyBitmap(Bitmap bmp, String directory, String filename) {
        String direc = "";
        if (directory.length() < 1) {
            direc = GlobalConfig.sdPath + "/";
        } else {
            direc = GlobalConfig.sdPath + "/" + directory + "/";
            createPath(direc);
        }
        File f = null;
        if (filename.length() < 1) {
            try {
                Date date = new Date();
                DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH_mm_ss_");
                filename = "www.njoki.com__" + format.format(date);
            } catch (Exception e) {
                filename = "未知";
            }
            f = new File(direc + filename + ".png");
        } else {
            f = new File(direc + filename + ".png");
        }

        FileOutputStream fOut = null;
        try {
            f.createNewFile();
            fOut = new FileOutputStream(f);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //Bitmap bitmap = ((BitmapDrawable)mImageView.getDrawable()).getBitmap();
        //bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);
        bmp.compress(Bitmap.CompressFormat.PNG, 100, fOut);
        try {
            fOut.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            fOut.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}</span>


//上log

12-11 10:10:18.429 9782-9782/com.oki.lyw.activity D/lessenUriImage﹕ 缩放比:3

12-11 10:10:18.429 9782-9782/com.oki.lyw.activity D/lessenUriImage﹕ 原图宽高:3920 2204

12-11 10:10:18.870 9782-9782/com.oki.lyw.activity D/lessenUriImage﹕ 缩放后:宽1960 高1102

12-11 10:10:18.870 9782-9782/com.oki.lyw.activity D/lessenUriImage﹕ 内存:8437KB

12-11 10:14:39.684 12101-12101/com.oki.lyw.activity D/lessenUriImage﹕ 缩放比:3

12-11 10:14:39.684 12101-12101/com.oki.lyw.activity D/lessenUriImage﹕ 原图宽高:3920 2204

12-11 10:14:40.115 12101-12101/com.oki.lyw.activity D/lessenUriImage﹕ 缩放后:宽1960 高1102

12-11 10:14:40.115 12101-12101/com.oki.lyw.activity D/lessenUriImage﹕ RGB_565格式内存:4218KB

12-11 10:14:40.635 12101-12101/com.oki.lyw.activity D/imageloader消耗内存﹕ 4218KB

//从上面可以看出使用imageloader和我的这个方法消耗的内存是一致的

//上图

while(true) {

Runtime rt = Runtime.getRuntime();

try {

bitlist.add(BitmapUtils.lessenUriImage(input));

bitlist.add(BitmapUtils.lessenUriImage(input));

Log.d("TAG", "系统当前内存状态:已申请内存:" + rt.totalMemory() / 1024 + "KB 最大可申请内存:" + rt.maxMemory() / 1024 + "KB");

} catch (OutOfMemoryError error) {



Log.d("TAG", "系统当前内存状态:已申请内存:" + rt.totalMemory() / 1024 + "KB 最大可申请内存:" + rt.maxMemory() / 1024 + "KB"+" 空闲内存:"+rt.freeMemory()/1024+"KB");

Log.d("内存", "OOM了");

break;



}

};

bitlist=null;

System.gc();

if(true)

return ;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: