码迷,mamicode.com
首页 > 其他好文 > 详细

imageloader详解

时间:2015-07-22 16:28:21      阅读:162      评论:0      收藏:0      [点我收藏+]

标签:

最近在做相册管理的时候遇到了gridview中加在大量本地图片的情况,第一次只是很简单的用了gridview 没有添加任何的其他加速功能,因为加载的速度慢的真心可以。虽然功能是实现了,但是无法让人感到愉快。

百度了一下找到了imageloader这个开源框架,可以大大提升加载的速度因为本身其使用了异步加载的方法。

它基本可以做到一下几点:

  1. 多线程下载图片,图片可以来源于网络,文件系统,项目文件夹assets中以及drawable中等
  2. 支持随意的配置ImageLoader,例如线程池,图片下载器,内存缓存策略,硬盘缓存策略,图片显示选项以及其他的一些配置
  3. 支持图片的内存缓存,文件系统缓存或者SD卡缓存
  4. 支持图片下载过程的监听
  5. 根据控件(ImageView)的大小对Bitmap进行裁剪,减少Bitmap占用过多的内存
  6. 较好的控制图片的加载过程,例如暂停图片加载,重新开始加载图片,一般使用在ListView,GridView中,滑动过程中暂停加载图片,停止滑动的时候去加载图片
  7. 提供在较慢的网络下对图片进行加载
这个是在github上面的imageloader的项目https://github.com/nostra13/Android-Universal-Image-Loader。



接下来就是如何使用的问题:

1、如果是需要从网上下载图片的话,那么就需要设置权限了 首先要在androidmanifest中获得权限

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
这两句是分别是获得网络权限和SD卡的读写权限。

然后初始化imageloader需要自己写一个application来进行初始化
package com.example.administrator.first;

import android.app.Application;

import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;

/**
 * Created by Administrator on 2015/7/16.
 */
public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        ImageLoaderConfiguration configuration = ImageLoaderConfiguration
                .createDefault(this);
        ImageLoader.getInstance().init(configuration);
    }
}

这里我使用的是默认初始化的,如果自己需要设定的话可以自己选择。
File cacheDir = StorageUtils.getCacheDirectory(context);//获得缓存的默认地址
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
        .memoryCacheExtraOptions(480, 800) // 设置每个缓存文件的大小
        .diskCacheExtraOptions(480, 800, null)//设置每个硬盘缓存文件的大小
        .taskExecutor(...)
        .taskExecutorForCachedImages(...)
        .threadPoolSize(3) <span><span class="comment">// 线程池内加载的数量</span><span>  </span></span>
        .threadPriority(Thread.NORM_PRIORITY - 2) <span><span class="comment">// 线程优先级</span></span>
        .tasksProcessingOrder(QueueProcessingType.FIFO) // default
        .denyCacheImageMultipleSizesInMemory()
        .memoryCache(new LruMemoryCache(2 * 1024 * 1024))
        .memoryCacheSize(2 * 1024 * 1024)
        .memoryCacheSizePercentage(13) // default
        .diskCache(new UnlimitedDiscCache(cacheDir)) // 硬盘缓存的方法
        .diskCacheSize(50 * 1024 * 1024)//<span><span class="comment">硬盘缓存50MB</span><span></span></span>
        .diskCacheFileCount(100)<span><span></span><span class="comment">//缓存的File数量</span></span>
        .diskCacheFileNameGenerator(new HashCodeFileNameGenerator()) <span><span></span><span class="comment">//将保存的时候的URI名称用HASHCODE加密</span><span> </span></span>
        .imageDownloader(new BaseImageDownloader(context)) // default
        .imageDecoder(new BaseImageDecoder()) // default
        .defaultDisplayImageOptions(DisplayImageOptions.createSimple()) // default
        .writeDebugLogs()
        .build();

因为默认的也差不多可以使用所以没怎么选,如果需要选择的话可以百度相应的选项的意思。
还需要在androidmanifest中在运行APP的时候先运行初始化的application。
<application android:name="MyApplication">假如这句话就会让这个先进行初始化。


然后是在你需要使用的使用初始化DisplayImageOptions对象
DisplayImageOptions options = new DisplayImageOptions.Builder()  
        // 设置图片在下载期间显示的图片  
                .showImageOnLoading(R.drawable.ic_stub)  
                // 设置图片Uri为空或是错误的时候显示的图片  
                .showImageForEmptyUri(R.drawable.ic_stub)  
                // 设置图片加载/解码过程中错误时候显示的图片  
                .showImageOnFail(R.drawable.ic_error)  
                // 设置下载的图片是否缓存在内存中  
                .cacheInMemory(false)  
                // 设置下载的图片是否缓存在SD卡中  
                .cacheOnDisc(true)  
                // 保留Exif信息  
                .considerExifParams(true)  
                // 设置图片以如何的编码方式显示  
                .imageScaleType(ImageScaleType.EXACTLY_STRETCHED)  
                // 设置图片的解码类型  
                .bitmapConfig(Bitmap.Config.RGB_565)  
                // .decodingOptions(android.graphics.BitmapFactory.Options  
                // decodingOptions)//设置图片的解码配置  
                .considerExifParams(true)  
                // 设置图片下载前的延迟  
                .delayBeforeLoading(100)// int  
                // delayInMillis为你设置的延迟时间  
                // 设置图片加入缓存前,对bitmap进行设置  
                // .preProcessor(BitmapProcessor preProcessor)  
                .resetViewBeforeLoading(true)// 设置图片在下载前是否重置,复位  
                // .displayer(new RoundedBitmapDisplayer(20))//是否设置为圆角,弧度为多少  
                .displayer(new FadeInBitmapDisplayer(100))// 淡入  
                .build();  



这是XML的布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Gallery
        android:id="@+id/myGallery"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:spacing="3px" />

</LinearLayout>
.java代码
package com.example.administrator.text;

import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Gallery;
import android.widget.Toast;

import com.nostra13.universalimageloader.core.download.ImageDownloader;

import java.io.File;
import java.util.ArrayList;

public class MainActivity extends Activity {
    private Gallery myGallery;
    private ArrayList<String>array = null;
    private String []url;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))//查看当前的SD是不是存在
        {
            String path = Environment.getExternalStorageDirectory() + "/DCIM/Camera/";//获得照片的文件夹
            array = readlist(path);//获得照片的URL
            url = new String[array.size()];
            for(int i = 0;i < array.size();i++)
            {
                url[i] = ImageDownloader.Scheme.FILE.wrap(array.get(i));
            }
            myGallery = (Gallery) findViewById(R.id.myGallery);
            myGallery.setAdapter(new ImageGalleryAdapter(this,url));
            myGallery.setOnItemClickListener(new OnItemClickListenerImpl());
        }
        else
        {
            Toast.makeText(this,"无SD卡请插入",Toast.LENGTH_LONG);
        }
    }

    private class OnItemClickListenerImpl implements AdapterView.OnItemClickListener {//设置选择了其中的响应

        public void onItemClick(AdapterView<?> parent, View view, int position,
                                long id) {
            Toast.makeText(MainActivity.this, String.valueOf(position),
                    Toast.LENGTH_SHORT).show();
        }
    }



        @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    private ArrayList<String> readlist(String path)//获得文件夹中的照片的URL
    {
        ArrayList<String> list = new ArrayList<String>();
        File file = new File(path);
        File []files = file.listFiles();
        if(files != null)
        {
            for(File f : files)
            {
                String filename = f.getName();
                if(filename.lastIndexOf(".") > 0 && filename.substring(filename.lastIndexOf(".")+1,filename.length()).equals("jpg"))
                {
                    list.add(f.getPath());
                }
            }
        }
        return list;
    }
}

适配器代码:
package com.example.administrator.text;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;

import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;

/**
 * Created by Administrator on 2015/7/17.
 */
public class ImageGalleryAdapter extends BaseAdapter {
    private Context context;
    private String []url;
    private DisplayImageOptions options;

    public ImageGalleryAdapter(Context context,String []s) {
        this.context = context;
        this.url = s;
        options = new DisplayImageOptions.Builder()//使用imageloader的方法进行初始化
                .showStubImage(R.drawable.ic_stub)
                .showImageForEmptyUri(null)
                .showImageOnFail(R.drawable.ic_error)
                .cacheInMemory()
                .cacheOnDisc()
                .build();
    }


    public int getCount() { // 取得要显示内容的数量
        return url.length;
    }

    public Object getItem(int position) { // 每个资源的位置
        return position;
    }

    public long getItemId(int position) { // 取得每个项的ID
        return position;
    }

    // 将资源设置到一个组件之中,很明显这个组件是ImageView
    public View getView(int position, View convertView, ViewGroup parent) {
        View view;
        view = convertView;
        ImageView imageView;
        if (convertView == null) {
            view = LayoutInflater.from(context).inflate(R.layout.item_list_image, null);
            imageView = (ImageView) view.findViewById(R.id.image);
            view.setTag(imageView);
        }
        else {
            imageView = (ImageView) view.getTag();
        }
        ImageLoader.getInstance().displayImage(url[position], imageView, options);
        ImageLoader.getInstance().displayImage(url[position],imageView);
        return view;
    }
}

item_list_imame.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" >
    
    <ImageView
        android:layout_width="80dip"
        android:layout_height="70dip"
        android:id="@+id/image"
        android:scaleType="centerCrop"
        android:adjustViewBounds="true"
        android:layout_marginLeft = "5dp"/>

</LinearLayout>

经过以上的测试,发现和正常的加载速度快了很多,如果不使用异步和这个框架的话,那么打开的开始就是白屏等好久才会出现,有了这个的话会慢慢的跳出来,如果存在了缓存
那么就是更加快。

最重要的是这样可以保证内存不会炸。因为如果同时加在所有的图片的话同时图片有几千张,内存直接炸。

如何还存在内存不够,我们则需要在初始化的时候进行一些调整 .threadPoolSize(// default  使用的线程数目减少

或者是在使用
DisplayImageOptions的时候不添加缓存就可以

  1.   .cacheInMemory(false// default  
  2.         .cacheOnDisk(false// default 

或者是在DisplayImageOptions选项中配置bitmapConfig为Bitmap.Config.RGB_565,因为默认是ARGB_8888, 使用RGB_565会比使用ARGB_8888少消耗2倍的内存
这样就是初步的减少内存爆炸的可能性。

在内存缓存方面:

1. 只使用的是强引用缓存 

  • LruMemoryCache(这个类就是这个开源框架默认的内存缓存类,缓存的是bitmap的强引用,下面我会从源码上面分析这个类)

2.使用强引用和弱引用相结合的缓存有

  • UsingFreqLimitedMemoryCache(如果缓存的图片总量超过限定值,先删除使用频率最小的bitmap)
  • LRULimitedMemoryCache(这个也是使用的lru算法,和LruMemoryCache不同的是,他缓存的是bitmap的弱引用)
  • FIFOLimitedMemoryCache(先进先出的缓存策略,当超过设定值,先删除最先加入缓存的bitmap)
  • LargestLimitedMemoryCache(当超过缓存限定值,先删除最大的bitmap对象)
  • LimitedAgeMemoryCache(当 bitmap加入缓存中的时间超过我们设定的值,将其删除)

3.只使用弱引用缓存

  • WeakMemoryCache(这个类缓存bitmap的总大小没有限制,唯一不足的地方就是不稳定,缓存的图片容易被回收掉)
我们可以在初始化的时候选择自己想用的
    ImageLoaderConfiguration configuration = new ImageLoaderConfiguration.Builder(this)  
            .memoryCache(new WeakMemoryCache())  
            .build();  

<strong>在硬盘缓存方面:</strong><ul><li>FileCountLimitedDiscCache(可以设定缓存图片的个数,当超过设定值,删除掉最先加入到硬盘的文件)</li><li>LimitedAgeDiscCache(设定文件存活的最长时间,当超过这个值,就删除该文件)</li><li>TotalSizeLimitedDiscCache(设定缓存bitmap的最大值,当超过这个值,删除最先加入到硬盘的文件)</li><li>UnlimitedDiscCache(这个缓存类没有任何的限制)</li></ul><strong>
</strong>
 ImageLoaderConfiguration configuration = new ImageLoaderConfiguration.Builder(this)  
            .diskCache(new UnlimitedDiscCache(cacheDir))
            .build();  


版权声明:本文为博主原创文章,未经博主允许不得转载。

imageloader详解

标签:

原文地址:http://blog.csdn.net/yj1499945/article/details/47001967

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!