一 认识Universal_Image_Loader
Android应用必定会涉及异步任务下载图片,如果不做图片的缓存的话,每次打开应用都从服务器下载数据,势必消耗用户大量的流量,烧客户流量的钱必定会引起用户的反感,另一方面如果没有网了,不能回顾之前下载过的图片,还加载不出了界面,体验感极其不好,所以做图片的缓存,更新就非常有必要了。而如果开发设计这个缓存要考虑很多方面问题:多线程下载,内存溢出,缓存不能更新等诸多问题,这时安卓强大的开源功能开始展露头角了:一系列的图片的加载框架应用而生,而Universal_Image_Loader 就是使用非常普遍,正如其名所表达的了
。
特点:
1 多线程下载图片
2 强大的配置功能:通过构建者设计模式,可以设计线程池大小,缓存策略,图片显示等
3 三级缓存机制:内存 ,文件系统,sd卡缓存
4 可以对下载过程监听 ,实施操作:可以停止下载,重新下载等操作
二 案例演示:一步一步详细操作
1 在Android 项目中:在dependence 的编译添加
dependencies {
..
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
}
点击 sync编译自动下载
universal-image-loader
架包到工程中
2 在清单文件中添加网络请求的权限和读写存储的权限
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
3 新建一个类ImageLoadUtil维护ImageLoad的使用
public class ImageLoadUtils {
public static final int MAX_DISK_CACHE = 1024 * 1024 * 50;//最大的空间大小
public static final int MAX_MEMORY_CACHE = 1024 * 1024 * 10;//最大的内存大小
private static ImageLoader imageLoader;
/**
* 单例设计模式
* @return
*/
public static ImageLoader getImageLoader(){
if (imageLoader == null){
synchronized (ImageLoadUtils.class){
if (imageLoader == null){
imageLoader = ImageLoader.getInstance();
}
}
}
return imageLoader;
}
public static void initImageLoader(Context context){
ImageLoaderConfiguration.Builder config = new ImageLoaderConfiguration.Builder(context);
config.threadPoolSize(4);//线程池的大小
config.threadPriority(Thread.NORM_PRIORITY);//设置线程的优先级
config.memoryCacheSize(MAX_MEMORY_CACHE);//设置最大缓存容量
config.denyCacheImageMultipleSizesInMemory();//设置图片的尺寸只有一种
config.diskCacheFileNameGenerator(new Md5FileNameGenerator());//创建Md5方式为文件命名
config.diskCacheSize(MAX_DISK_CACHE);
config.tasksProcessingOrder(QueueProcessingType.LIFO);
config.diskCache(new UnlimitedDiskCache
(new File(Environment.getExternalStorageDirectory()+"/ImageLoader/cache")));
if (BuildConfig.DEBUG){
config.writeDebugLogs();
}
getImageLoader().init(config.build());
}
public static void displayImage(String url, ImageView target, DisplayImageOptions options){
imageLoader.displayImage(url,target,options);
}
}
4 新建一个类MyApp继承Application,确保ImageLoader只初始化一次
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
initImageLoader(getApplicationContext());
}
}
并在清单文件中为Application注册该Application的名字为MyApp
<application
android:name=".MyApp"
.....
/>
5 定义布局:
activity_main:放一个ListView展示图片
<ListView
android:id="@+id/list_view_main_lv"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
为listItem设置布局:新建布局文件image_item_loader
<ImageView
android:id="@+id/image"
android:layout_width="72dp"
android:layout_height="72dp"
android:layout_margin="3dp"
android:adjustViewBounds="true"
android:scaleType="centerCrop" />
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:layout_marginLeft="20dp"
android:textSize="22sp" />
6 在MainActivity中加载图片
public class MainActivity extends AppCompatActivity {
public static final String[] IMAGES = new String[] {
"http://www.1688wan.com/allimgs/img_iapp/201609/_1473225269861.png",
"http://www.1688wan.com/allimgs/img_iapp/201608/_1470736124114.png",
"http://www.1688wan.com/allimgs/img_iapp/201609/_1473225269861.png",
"http://www.1688wan.com/allimgs/img_iapp/201608/_1470736124114.png",
"http://www.1688wan.com/allimgs/img_iapp/201609/_1473225269861.png",
"http://www.1688wan.com/allimgs/img_iapp/201608/_1470736124114.png",
"http://www.1688wan.com/allimgs/img_iapp/201609/_1473225269861.png",
"http://www.1688wan.com/allimgs/img_iapp/201608/_1470736124114.png",
"http://www.1688wan.com/allimgs/img_iapp/201609/_1473225269861.png",
"http://www.1688wan.com/allimgs/img_iapp/201608/_1470736124114.png",
"http://img.zcool.cn/community/03378c3554c7a5e00000158fc5f68ad.jpg"
};
private ListView mListView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
mListView = (ListView) findViewById(R.id.list_view_main_lv);
mListView.setAdapter(new ImageAdapter(this));
}
/**
* 当活动销毁时,清除缓存,停止ImageLoader中的线程任务
*/
@Override
protected void onDestroy() {
super.onDestroy();
AnimateFirstDisplayListener.displayedImages.clear();
ImageLoader.getInstance().clearMemoryCache();
ImageLoader.getInstance().stop();
}
static class ImageAdapter extends BaseAdapter{
private static final String[] IMAGE_URLS = MainActivity.IMAGES;
private LayoutInflater inflater;
private ImageLoadingListener animateFirstListener = new AnimateFirstDisplayListener();
private DisplayImageOptions options;
ImageAdapter(Context context) {
inflater = LayoutInflater.from(context);
options = new DisplayImageOptions.Builder()
.showImageOnLoading(R.drawable.hint)//设置图片在下载期间显示的图片
.showImageForEmptyUri(R.drawable.no)//设置图片Uri为空或是错误的时候显示的图片
.showImageOnFail(R.drawable.yes)//设置图片加载/解码过程中错误时候显示的图片
.delayBeforeLoading(100)//设置延时多少时间后开始下载
.cacheInMemory(true)//设置下载的图片是否缓存在内存中
.cacheOnDisk(true)// 设置下载的资源是否缓存在SD卡中
.considerExifParams(true)// 是否考虑JPEG图像EXIF参数(旋转,翻转)
.imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2)//设置图片以何种编码方式显示
.bitmapConfig(Bitmap.Config.RGB_565) // 设置图片的解码类型
.displayer(new RoundedBitmapDisplayer(20))//是否设置为圆角,弧度为多少
.displayer(new FadeInBitmapDisplayer(1000))//是否图片加载好后渐入的动画时间
.build();
}
@Override
public int getCount() {
return IMAGE_URLS.length;
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view = convertView;
final ViewHolder holder;
if (convertView == null) {
view = inflater.inflate(R.layout.item_image_loader, parent, false);
holder = new ViewHolder();
holder.image = (ImageView) view.findViewById(R.id.image);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
ImageLoader.getInstance().displayImage(IMAGE_URLS[position], holder.image, options, animateFirstListener);
return view;
}
}
static class ViewHolder {
ImageView image;
}
private static class AnimateFirstDisplayListener extends SimpleImageLoadingListener {
static final List<String> displayedImages = Collections.synchronizedList(new LinkedList<String>());
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
if (loadedImage != null) {
ImageView imageView = (ImageView) view;
boolean firstDisplay = !displayedImages.contains(imageUri);
if (firstDisplay) {
FadeInBitmapDisplayer.animate(imageView, 500);
displayedImages.add(imageUri);
}
}
}
}
}
运行后,成功加载图片,即使没有网了依然可以看到图片,说明成功缓存了。