最近在做相册管理的时候遇到了gridview中加在大量本地图片的情况,第一次只是很简单的用了gridview 没有添加任何的其他加速功能,因为加载的速度慢的真心可以。虽然功能是实现了,但是无法让人感到愉快。
百度了一下找到了imageloader这个开源框架,可以大大提升加载的速度因为本身其使用了异步加载的方法。
它基本可以做到一下几点:
- 多线程下载图片,图片可以来源于网络,文件系统,项目文件夹assets中以及drawable中等
- 支持随意的配置ImageLoader,例如线程池,图片下载器,内存缓存策略,硬盘缓存策略,图片显示选项以及其他的一些配置
- 支持图片的内存缓存,文件系统缓存或者SD卡缓存
- 支持图片下载过程的监听
- 根据控件(ImageView)的大小对Bitmap进行裁剪,减少Bitmap占用过多的内存
- 较好的控制图片的加载过程,例如暂停图片加载,重新开始加载图片,一般使用在ListView,GridView中,滑动过程中暂停加载图片,停止滑动的时候去加载图片
- 提供在较慢的网络下对图片进行加载
这个是在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的时候不添加缓存就可以
- .cacheInMemory(false) // default
- .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();
版权声明:本文为博主原创文章,未经博主允许不得转载。