当前位置: 移动技术网 > IT编程>移动开发>Android > Android XImageLoader框架知识详解

Android XImageLoader框架知识详解

2018年09月13日  | 移动技术网IT编程  | 我要评论

笑话电影,家好月圆小说,十二星战v1.1

1.前言

在做android也有一段时间了,在以往的习惯中或者说作为初学者的开发者来说,在项目周期很紧张的情况之下,迫于周期总是喜欢直接在网上找别人写的项目或者框架来用,但是一旦出问题总是看着别人的代码是很头痛得事情,在此种种的情况之下,萌生自己写框架的想法,这样自己维护自己的框架那么就没那么痛苦了,想到目前app项目中用得最多的也是图片异步加载,那么就决定此次对图片加载进行开刀,说实在的对于图片加载框架目前已经有很多框架了比如imageloader、picasso、glide、fresco;这几种目前是用得最多的图片加载框架了;就个人习惯总觉得有点不是很习惯吧;当然只是个人习惯哈,目前支持gif图片加载和普通图片都支持的加载glide、fresco、并且还要支持图片的gif自定义形状的估计也就少了吧;目前自己写的框架支持gif图片和普通图片加载,并且可以显示圆角、圆形图片,支持自定图片形状,其中gif图片加载对android drawable gif开源框架的基础上修改部分;支持okhttp 3.0网络框架下载,通知支持自定网络工具自定义。

2.框架设计

这里写图片描述

框架中需要储备知识点:

executorservice 线程池管理线程 semaphore 信号量操作,在图片加载实现队列式加载,你可以直接写队列,不一定要用这个。 lrucache 图片缓存,关于关于图片缓存你如果不用android的类,你可以用softreference(软应用)自己写,缓存的目的是避免图片的大量加载的时候会出现oom。

handler 异步处理图片显示问题

以上知识点了解清楚之后就可以开工写框架了,当然我这里只是我框架设计这么写,你自己有想法就按照自己的设计方案来写自己的框架。知识点解释完了,我就直接上代码了,我这个人比较直接。

3框架使用


普通图片和gif图片同时可以加载:ximageloader_with_gif 下载

只支持普通不支持gif图片加载 : ximageloader_without_gif 下载


jar配置方法:

jar文件下载后,androidstudio中复制到app/libs/, jnilibs文件夹直接复制到app/src/main/,values中文件复制到项目中,

对jar文件右键,选择”add as library…..”。

arr配置方法:

arr文件复制到app/libs/,在app/build.gradle 中dependencies里面配置: compile(name: ‘ximageloader’, ext: ‘aar’)

- xml view使用

(1)只是加载普通的图片,没有gif图片:

 
(2)加载图片有普通的图片和gif图片,并且不知道是不是gif图片还是普通图片
 

- 加载图片方法
(1)普通加载方式

/**
 * 显示图片
 *
 * @param target 图片view
 * @param resources 网络地址、本地地址、assets文件夹下面的文件名
*/
ximageloader.show(iv_target, resource);

(2)用默认图片的加载方式

/**
 * 显示图片
 *
 * @param target 图片view
 * @param resources 网络地址、本地地址、assets文件夹下面的文件名
 * @param defaultresid 默认图片资源id
*/
ximageloader.show(iv_target, resource,r.drawable.ic_default)

(3)圆角图片加载

/**
 * 显示图片
 *
 * @param target 图片view
 * @param resources 网络地址、本地地址、assets文件夹下面的文件名
 * @param defaultresid 默认图片资源id
 * @param transform 自定义图片显示形状,需要实现imagetransform接口
 */
ximageloader.show(holder.iv_target, resource, r.mipmap.ic_launcher, new imagecornerradiustransform(8));

(4)圆形图片加载

/**
 * 显示图片
 *
 * @param target 图片view
 * @param resources 网络地址、本地地址、assets文件夹下面的文件名
 * @param defaultresid 默认图片资源id
 * @param transform 自定义图片显示形状,需要实现imagetransform接口
 */
ximageloader.show(holder.iv_target, resource, r.mipmap.ic_launcher, new imagecircletransform(8, color.cyan));

-图片下载网络方式

ximageloader是以okhttp网络访问下载图片为基础的,如果你项目是httpurlconnect或者你不喜欢用okhttp的话就继承imagetask类,重写download()方法就行了。

import android.util.log;

import com.android.image.loader.imagehandler;
import com.android.image.loader.imageholder;
import com.android.image.loader.imagetask;

import java.io.file;
import java.io.fileoutputstream;
import java.io.ioexception;
import java.io.inputstream;

import okhttp3.okhttpclient;
import okhttp3.request;
import okhttp3.response;


/**
 * created by relin
 * on 2018-06-25.
 * okhttp网络请求方式下载图片
 * 如果你希望利用urlhttpconnect下载图片
 * 请继承imagetask此类来写对应的文件下载
 * 具体的操作请看imagetask操作类的说明。
 */

public class okhttpimagetask extends imagetask {

 /**
  * 构造方法
  *
  * @param imageholder  图片数据对象
  * @param imagehandler
  */
 public okhttpimagetask(imageholder imageholder, imagehandler imagehandler) {
  super(imageholder, imagehandler);
 }

 @override
 protected void download(string url, file file) {
  request request = new request.builder().url(url).build();
  okhttpclient okhttpclient = new okhttpclient();
  response response = null;
  try {
response = okhttpclient.newcall(request).execute();
  } catch (ioexception e) {
e.printstacktrace();
  }
  if (response.issuccessful()) {
inputstream is = null;
byte[] buf = new byte[2048];
int len = 0;
fileoutputstream fos = null;
try {
 is = response.body().bytestream();
 long total = response.body().contentlength();
 fos = new fileoutputstream(file);
 long sum = 0;
 while ((len = is.read(buf)) != -1) {
  fos.write(buf, 0, len);
  sum += len;
  int progress = (int) (sum * 1.0f / total * 100);
 }
 fos.flush();
} catch (exception e) {
 log.e(this.getclass().getsimplename(), "exception " + e.tostring());
} finally {
 try {
  if (is != null)
is.close();
  if (fos != null) {
fos.close();
  }
 } catch (ioexception e) {
  log.e(this.getclass().getsimplename(), "ioexception " + e.tostring());
 }
}
  } else {
log.e(this.getclass().getsimplename(), "response is not successful");
  }
 }

}

4.框架实现

imageholder(图片数据类)

承载图片的主要数据的类,包含图片的加载对象、图片的形状、资源地址、线程信号量……

import android.content.context;
import android.graphics.bitmap;
import android.widget.imageview;

import com.android.image.transforms.imagetransform;

import java.io.file;
import java.util.concurrent.semaphore;

/**
 * created by relin
 * on 2018-06-27.
 */

public class imageholder {

 private context context;

 /**
  * 图片网络地址
  */
 private string url;
 /**
  * 图片显示view
  */
 private imageview target;
 /**
  * 图片缓存文件夹
  */
 private string cachefolder;
 /**
  * 图片默认资源文件id
  */
 private int defaultresid = 0;
 /**
  * 图片默认资源bitmap
  */
 private bitmap defaultbitmap;
 /**
  * 图片文件
  */
 private file file;
 /**
  * 线程信号量
  */
 private semaphore semaphore;
 /**
  * 图片处理标志
  */
 private int imagehandlerwhat;
 /**
  * 图片参数
  */
 private imageoptions imageoptions;
 /**
  * 图片形状[接口]
  */
 private imagetransform imagetransform;

 /**
  * 获取图片地址
  *
  * @return
  */
 public string geturl() {
  return url;
 }

 /**
  * 设置图片地址
  *
  * @param url
  */
 public void seturl(string url) {
  this.url = url;
 }

 /**
  * 显示图片的控件
  *
  * @return
  */
 public imageview gettarget() {
  return target;
 }

 /**
  * 设置图片控件
  *
  * @param target
  */
 public void settarget(imageview target) {
  this.target = target;
 }

 /**
  * 获取缓存文件夹[带路径]
  *
  * @return
  */
 public string getcachefolder() {
  return cachefolder;
 }

 /**
  * 设置缓存文件夹[带路径]
  *
  * @param cachefolder
  */
 public void setcachefolder(string cachefolder) {
  this.cachefolder = cachefolder;
 }

 /**
  * 获取图片文件
  *
  * @return
  */
 public file getfile() {
  return file;
 }

 /**
  * 设置图片文件
  *
  * @param file
  */
 public void setfile(file file) {
  this.file = file;
 }

 public semaphore getsemaphore() {
  return semaphore;
 }

 /**
  * 请求信号量
  */
 public void acquiresemaphore() {
  if (semaphore != null) {
try {
 semaphore.acquire();
} catch (interruptedexception e) {
 e.printstacktrace();
}
  }
 }

 /**
  * 释放信号量
  */
 public void releasesemaphore() {
  if (semaphore != null) {
semaphore.release();
  }
 }

 /**
  * 设置信号量
  *
  * @param semaphore
  */
 public void setsemaphore(semaphore semaphore) {
  this.semaphore = semaphore;
 }

 /**
  * 获取默认图片资源id
  *
  * @return
  */
 public int getdefaultresid() {
  return defaultresid;
 }

 /**
  * 设置默认图片资源id
  *
  * @param defaultresid
  */
 public void setdefaultresid(int defaultresid) {
  this.defaultresid = defaultresid;
 }

 /**
  * 获取默认的图片bitmap对象
  *
  * @return
  */
 public bitmap getdefaultbitmap() {
  return defaultbitmap;
 }

 /**
  * 设置默认的图片bitmap对象
  *
  * @param defaultbitmap
  */
 public void setdefaultbitmap(bitmap defaultbitmap) {
  this.defaultbitmap = defaultbitmap;
 }

 /**
  * 获取处理图片显示方式的标志
  *
  * @return
  */
 public int getimagehandlerwhat() {
  return imagehandlerwhat;
 }

 /**
  * 设置处理图片显示方式的标志
  *
  * @return
  */
 public void setimagehandlerwhat(int imagehandlerwhat) {
  this.imagehandlerwhat = imagehandlerwhat;
 }

 /**
  * 获取图片参数
  *
  * @return
  */
 public imageoptions getimageoptions() {
  return imageoptions;
 }

 /**
  * 设置图片参数
  *
  * @param imageoptions
  */
 public void setimageoptions(imageoptions imageoptions) {
  this.imageoptions = imageoptions;
 }

 /**
  * 获取图片形状接口
  *
  * @return
  */
 public imagetransform getimagetransform() {
  return imagetransform;
 }

 /**
  * 设置图片形状接口
  *
  * @param imagetransform
  */
 public void setimagetransform(imagetransform imagetransform) {
  this.imagetransform = imagetransform;
 }

 public context getcontext() {
  return context;
 }

 public void setcontext(context context) {
  this.context = context;
 }
}

imagetask (图片下载任务类)

该类实现了对图片的下载任务继承runable方便线程池管理和线程启动,此类是一个抽象类,如果用户觉得okhttp网络框架和自己项目违背,那么只需要继承该类,实现downlod()方法就行了,在download()方法中写自己网络下载图片的方式就ok!

import android.graphics.bitmap;
import android.os.environment;
import android.os.message;

import com.android.image.gifdrawable;
import com.android.image.transforms.imagetransform;

import java.io.file;
import java.io.ioexception;

import static android.os.environment.directory_documents;

/**
 * created by relin
 * on 2018-06-28.
 * 图片下载任务基本类
 * 在不修改下载方式的情况下,可以不管
 * 如果你需要修改下载的网络访问方式,请集成改类
 * 在downlod()方法中写下载的文件就行了,其余的逻辑
 * 完全不用你管。
 */

public abstract class imagetask implements runnable {

 /**
  * 图片数据
  */
 private imageholder holder;
 /**
  * 图片最终处理
  */
 private imagehandler handler;

 /**
  * 构造方法
  *
  * @param holder  图片对象类
  * @param handler 图片处理类
  */
 public imagetask(imageholder holder, imagehandler handler) {
  this.holder = holder;
  this.handler = handler;
  createcachefolder(null);
 }

 /**
  * 构造方法
  *
  * @param holder图片对象类
  * @param handler  图片处理类
  * @param cachefolder 缓存文件夹-带路径的
  */
 public imagetask(imageholder holder, imagehandler handler, string cachefolder) {
  this.holder = holder;
  this.handler = handler;
  createcachefolder(cachefolder);
 }

 /**
  * 创建缓存文件夹
  *
  * @param folder
  */
 private void createcachefolder(string folder) {
  file file = new file(folder == null  (environment.getexternalstoragepublicdirectory(directory_documents).getparent() + file.separator + "ximageloader") : folder);
  if (!file.exists()) {
file.mkdirs();
  }
  holder.setcachefolder(file.getabsolutepath());
 }

 /**
  * 通过url获取文件名称
  *
  * @param url
  * @return
  */
 private string namefromurl(string url) {
  return url.substring(url.lastindexof("/") + 1);
 }

 @override
 public void run() {
  //请求信号量
  holder.acquiresemaphore();
  //通过数据类获取对应的资源路径、缓存文件夹、加载图片的类型、图片参数
  string url = holder.geturl();
  string folder = holder.getcachefolder();
  int what = holder.getimagehandlerwhat();
  imageoptions options = holder.getimageoptions();
  imagetransform transform = holder.getimagetransform();
  //操作处理对应类型的图片
  switch (what) {
case imagehandler.show_internet_image:
 dohttpimage(url, folder, options, transform);
 break;
case imagehandler.show_local_image:
 dolocalimage(url, options, transform);
 break;
case imagehandler.show_assets_image:
 doassetsimage(url, folder, options, transform);
 break;
case imagehandler.show_gif_image:
 doassetsimage(url, folder, options, transform);
 break;
  }
  sendmsgshowimage(what);
 }

 /**
  * 实现对图片的下载操作
  *
  * @param url  图片网络地址
  * @param file 图片缓存的地址
  */
 protected abstract void download(string url, file file);

 /**
  * 处理网络图片
  *
  * @param url  网络地址
  * @param folder  缓存文件夹
  * @param options 图片参数
  */
 private void dohttpimage(string url, string folder, imageoptions options, imagetransform transform) {
  //储存下载文件的目录
  file folderfile = new file(folder);
  if (!folderfile.exists()) {
folderfile.mkdirs();
  }
  file file = new file(holder.getcachefolder(), namefromurl(holder.geturl()));
  if (!file.exists()) {
try {
 file.createnewfile();
} catch (ioexception e) {
 e.printstacktrace();
}
download(url, file);
  }
  holder.setfile(file);
  if (imageutils.isgif(url)) {
dogifimage(url, file);
  } else {
bitmap bitmap = imageutils.decodesampledbitmap(file, options.getwidth(), options.getheight());
if (transform != null) {
 bitmap = transform.ondrawbitmap(options.getrect(), bitmap);
}
imagecache.getinstance().addcache(url, bitmap);
  }
 }

 /**
  * 处理本地图片
  *
  * @param path 图片路径
  * @param options 图片参数
  */
 private void dolocalimage(string path, imageoptions options, imagetransform transform) {
  file file = new file(path);
  holder.setfile(file);
  if (imageutils.isgif(path)) {
dogifimage(path, file);
  } else {
bitmap localbitmap = imageutils.decodesampledbitmap(new file(path), options.getwidth(), options.getheight());
if (transform != null) {
 localbitmap = transform.ondrawbitmap(options.getrect(), localbitmap);
}
imagecache.getinstance().addcache(path, localbitmap);
  }
 }

 /**
  * 处理assets文件
  *
  * @param name assets文件名: 例如ic_test.png
  * @param folder  缓存文件夹,此处的用做拷贝数据到缓存文件夹
  * @param options 图片参数
  */
 private void doassetsimage(string name, string folder, imageoptions options, imagetransform transform) {
  file assetsfile = imageutils.decodeassetsbitmap(folder, name);
  holder.setfile(assetsfile);
  if (imageutils.isgif(name)) {
dogifimage(name, assetsfile);
return;
  }
  bitmap assetsbitmap = imageutils.decodesampledbitmap(assetsfile, options.getwidth(), options.getheight());
  if (transform != null) {
assetsbitmap = transform.ondrawbitmap(options.getrect(), assetsbitmap);
  }
  imagecache.getinstance().addcache(name, assetsbitmap);
 }

 private void dogifimage(string url, file file) {
  try {
gifdrawable gifdrawable = new gifdrawable(file);
imagecache.getinstance().addgifcache(url, gifdrawable);
  } catch (ioexception e) {
e.printstacktrace();
  }
 }

 /**
  * 显示图片
  *
  * @param what 图片类型
  */
 protected void sendmsgshowimage(int what) {
  message msg = handler.obtainmessage();
  msg.what = what;
  msg.obj = holder;
  handler.sendmessage(msg);
 }

}

imagecache(图片缓存)

图片缓存主要是继承android的类,实现对bitmap和gifdrawable的缓存,给图片加载节省时间的同时防止oom发生。

import android.graphics.bitmap;
import android.util.lrucache;

import com.android.image.gifdrawable;

/**
 * created by relin
 * on 2018-06-28.
 * 图片的缓存类,此类主要用作图片一级
 * 缓存,在考虑内存不足的情况下回oom。
 * 当然你可以使用softreference类实现,
 * 只是你是android程序员不是java后台人员,
 * 有android写好的算法你不用,那我就没办法了。
 */

public class imagecache extends lrucache {

 /**
  * 图片缓存对象
  */
 public static imagecache imagecache;

 /**
  * 获取图片缓存的单例对象
  * @return imagecache
  */
 public static imagecache getinstance() {
  if (imagecache == null) {
int maxmemory = (int) (runtime.getruntime().totalmemory() / 1024);
int cachesize = maxmemory / 8;
imagecache = new imagecache(cachesize);
  }
  return imagecache;
 }

 /**
  * @param maxsize for caches that do not override {@link #sizeof}, this is
  * the maximum number of entries in the cache. for all other caches,
  * this is the maximum sum of the sizes of the entries in this cache.
  */
 public imagecache(int maxsize) {
  super(maxsize);
 }


 /**
  * add bitmap to cache
  *
  * @param url
  * @param bitmap
  */
 public void addcache(string url, bitmap bitmap) {
  if (url == null || bitmap == null) {
return;
  }
  put(url, bitmap);
 }

 /**
  * get cache from memory
  *
  * @param url
  * @return
  */
 public bitmap getcache(string url) {
  if (url == null) {
return null;
  }
  return (bitmap) get(url);
 }

 /**
  * add bitmap to cache
  *
  * @param url
  * @param drawable
  */
 public void addgifcache(string url, gifdrawable drawable) {
  if (url == null || drawable == null) {
return;
  }
  put(url, drawable);
 }

 /**
  * get cache from memory
  *
  * @param url
  * @return
  */
 public gifdrawable getgifcache(string url) {
  if (url == null) {
return null;
  }
  return (gifdrawable) get(url);
 }

}
imagehandler(图片显示处理)
import android.graphics.bitmap;
import android.os.handler;
import android.os.message;
import android.view.viewtreeobserver;
import android.widget.imageview;

import com.android.image.gifdrawable;
import com.android.image.gifimageview;
import com.android.image.transforms.imagetransform;

import java.io.file;
import java.io.ioexception;
import java.util.concurrent.semaphore;

/**
 * created by relin
 * on 2018-06-27.
 */

public class imagehandler extends handler {

 /**
  * 显示网络图片标志
  */
 public static final int show_internet_image = 0x002;
 /**
  * 显示本地图片标志
  */
 public static final int show_local_image = 0x001;
 /**
  * 显示assets文件夹图片标志
  */
 public static final int show_assets_image = 0x003;

 /**
  * 显示gif图片标志
  */
 public static final int show_gif_image = 0x004;


 @override
 public void handlemessage(message msg) {
  super.handlemessage(msg);
  //获取对应图片信息
  imageholder holder = (imageholder) msg.obj;
  //显示图片
  showbitmap(holder, msg);
 }

 /**
  * 显示图片
  *
  * @param holder 图片数据类
  * @param msg 显示图片的消息
  */
 private void showbitmap(imageholder holder, message msg) {
  string tag = (string) holder.gettarget().gettag();
  string url = holder.geturl();
  file file = holder.getfile();
  imageview target = holder.gettarget();
  semaphore semaphore = holder.getsemaphore();
  string folder = holder.getcachefolder();
  imageoptions options = holder.getimageoptions();
  imagetransform transform = holder.getimagetransform();
  //判断是否是对应图片的对应路径
  if (!url.equals(tag)) {
semaphore.release();
return;
  }
  if (isgif(url)) {
loadgifimage(url, target, file, transform);
semaphore.release();
return;
  } else {
bitmap cachebitmap = imagecache.getinstance().getcache(url);
if (cachebitmap != null) {
 load(target, url, file, transform, options);
 semaphore.release();
 return;
}
  }
  switch (msg.what) {
case show_internet_image://网络图片
 load(target, url, file, transform, options);
 break;
case show_local_image://本地图片
 load(target, url, file, transform, options);
 break;
case show_assets_image://assets文件夹下的图片
 load(target, url, file, transform, options);
 break;
  }
  semaphore.release();
 }

 /**
  * 是否是gif图片
  *
  * @param url
  * @return
  */
 private boolean isgif(string url) {
  return url.endswith(".gif");
 }

 /**
  * 加载gif图片
  *
  * @param url gif资源地址
  * @param target gif显示控件
  * @param filegif图片文件
  * @param transform gif图片现状接口
  */
 private void loadgifimage(string url, imageview target, file file, imagetransform transform) {
  gifdrawable drawable = imagecache.getinstance().getgifcache(url);
  if (target instanceof gifimageview) {
if (drawable != null) {
 gifimageview gifimageview = (gifimageview) target;
 gifimageview.setimagedrawable(drawable);
} else {
 try {
  drawable = new gifdrawable(file);
 } catch (ioexception e) {
  e.printstacktrace();
 }
}
if (transform != null) {
 drawable.settransform(transform);
}
gifimageview gifimageview = (gifimageview) target;
gifimageview.setimagedrawable(drawable);
  }
 }


 /**
  * 加载图片
  *
  * @param target 显示图片的view
  * @param url 图片地址
  * @param file图片文件
  * @param transform 图片形状
  * @param options图片参数
  */
 private void load(imageview target, string url, file file, imagetransform transform, imageoptions options) {

  if (isgif(url)) {
loadgifimage(url, target, file, transform);
  } else {
bitmap bitmap = imageutils.decodesampledbitmap(file, options.getwidth(), options.getheight());
//判断是否自定显示图片形状
if (transform != null) {
 bitmap = transform.ondrawbitmap(options.getrect(), bitmap);
}
//显示图片
target.setimagebitmap(bitmap);
//加入缓存
imagecache.getinstance().addcache(url, bitmap);
  }
 }

}

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网