ion学习
它所依赖的库
- androidasync.jar
- gson.jar
- android-support-v4.jar
- application/x-www-form-urlencoded
- multipart/form-data
- application/json
- text/xml
特点
- 自动回调UI线程
- 灵活的api
- 缓存
- 管理activity 和service的生命周期
- 所有操作返回Futures(可取消)
关于图片
- 支持ListView回收,缓存
- 继承自 UrlimageViewHelper
ion的几种网络请求
-
基本回调
Ion.with(context) .load("http://api.example.com")
-
参数
- json
.setJsonObjectBody()
-
url 编码
.setBosyparameter("foo","bar")
- 上传文件
.setMultipartParameter("goop","noop") .setMultipartParameter("filename.zip",new File("/sd/file"))
- json
-
进度
.uploadProgressBar(bar) .progressBar(bar) .progressDialog(progressDialog) .progress(new callback())
- 头信息
setHeader("foo","bar")
- img -> ImageView
.withBitmap() .placeholder(resId) .error(resId) .animateLoad(Animation) .animateIn(Animation) .intoImageView(imageview)
- 设置返回类型
.asJsonObject() .asString() .write(new File("/"))
-
future
All operations return a custom Future that allows you to specify a callback that runs on completion.- 回调
setCallBack(new FutureCallback<T>(){});
- 阻塞调用
get();
- 取消
.cancel(); .cancelall(tag)
- 返回头信息
.withResponse()
- 回调
- 阻塞
JsonObject json = Ion.with(context) .load("http://example.com/thing.json").asJsonObject().get();
分包
-
src
- bitmap
- builder
- conscrypt
- cookie
- future
- gif
- gson
- loader
AsserLoader
BitmapCallback 图片回调类, 4个子类
BitmapFetcher 图片处理?类()
BitmapInfoToBitmap
ContextReference
DeferredLoadBitmap
加载图片
Load an image into an ImageView_
// This is the "long" way to do build an ImageView request... it allows you to set headers, etc.
Ion.with(context)
.load("http://example.com/image.png")
.withBitmap()
.placeholder(R.drawable.placeholder_image)
.error(R.drawable.error_image)
.animateLoad(spinAnimation)
.animateIn(fadeInAnimation)
.intoImageView(imageView);
// but for brevity, use the ImageView specific builder...
Ion.with(imageView)
.placeholder(R.drawable.placeholder_image)
.error(R.drawable.error_image)
.animateLoad(spinAnimation)
.animateIn(fadeInAnimation)
.load("http://example.com/image.png");
The Ion Image load API has the following features: Disk and memory caching Bitmaps are held via weak references so memory is managed very effeciently ListView Adapter recycling support Bitmap transformations via the .transform(Transform) Animate loading and loaded ImageView states DeepZoom for extremely large images
流程
-
LoadBuilder<Builders.Any.B> Ion.with(Context)
Get the default Ion object instance and begin building a request
Builders.Any.B load(java.lang.String uri) //*返回IonRequestBuilder实现*
uri - Uri to load. This may be a http(s), file, or content uri.
Builders.Any.B load(java.lang.String method, java.lang.String url)
method - HTTP method such as GET or POST.
url - Url to load.Builders.Any.B load(java.io.File file)
file - File to load.
Builders.Any.BF<? extends Builders.Any.BF<?>> withBitmap() //继承自builder.FutureBuilder
Use the request as a Bitmap which can then be modified and/or applied to an ImageView.
-
Builders.IV.F<? extends Builders.IV.F<?>> Ion.with(ImageView) // 实现类IonImageViewRequestBuilder
Create a ImageView bitmap request builder
Builders.Any.BF<? extends Builders.Any.BF<?>>
Builders.IV.F<? extends Builders.IV.F<?>>
都是和image bitmap 相关的接口 -
ImageViewBuilder<I extends ImageViewBuilder<?>> 对 imageView 进行设置
.placeHolder() .error .animateLoad() .animateIn() 返回 I 可以重复调用
-
- 设置ImageView
ImageViewFuture .intoimageView() //ImageViewFutureBuilder 实现IonBitmapRequestBuilder, IonImageViewRequestBuilder, IonRequestBuilder
- 设置 uri
ImageViewFuture .load(url) //LoadImageViewFutureBuilder 实现IonImageViewRequestBuilder
- 设置ImageView
- 得到ImageViewFuture(com.koushikdutta.async.future.Cancellable, java.util.concurrent.Future<ImageView>) 实现:IonDrawable.ImageViewFutureImpl
限定符和类型 方法和说明
com.koushikdutta.async.future.Future<ImageViewBitmapInfo> withBitmapInfo()
从接口继承的方法 com.koushikdutta.async.future.Future
setCallback, then
从接口继承的方法 com.koushikdutta.async.future.Cancellable
cancel, isCancelled, isDone
从接口继承的方法 java.util.concurrent.Future
cancel, get, get, isCancelled, isDone
Ion
public class Ion {
public static LoadBuilder<Builders.Any.B> with(Context context) {
return getDefault(context).build(context);
}
public static Ion getDefault(Context context) {
return getInstance(context, "ion");
}
public LoadBuilder<Builders.Any.B> build(Context context) {
return new IonRequestBuilder(ContextReference.fromContext(context), this);
}
}
IonRequestBuilder
LoadBuilder<Builders.Any.B> Ion.with(Context)
LoadBuilder<Builders.Any.B>的唯一实现类IonRequestBuilder
Builders.Any.B .load(java.lang.String uri)
返回自己,Builders.Any.B的唯一实现类IonRequestBuilder
Builders.Any.BF<? extends Builders.Any.BF<?>> withBitmap()
返回IonImageViewRequestBuilder,Builders.Any.BF<? extends Builders.Any.BF<?>>两个实现类
IonBitmapRequestBuilder, IonImageViewRequestBuilder
class IonRequestBuilder implements Builders.Any.B LoadBuilder<Builders.Any.B> {
public IonRequestBuilder load(String url) {
return loadInternal(AsyncHttpGet.METHOD, url);
}
private IonRequestBuilder loadInternal(String method, String url) {
this.method = method;
if (!TextUtils.isEmpty(url) && url.startsWith("/"))
url = new File(url).toURI().toString();
this.uri = url;
return this;
}
public IonImageViewRequestBuilder withBitmap() {
return new IonImageViewRequestBuilder(this);
}
}
IonImageViewRequestBuilder
class IonImageViewRequestBuilder extends IonBitmapRequestBuilder implements Builders.Any.BF<? extends Builders.Any.BF<?>>{
public IonImageViewRequestBuilder(IonRequestBuilder builder) {
super(builder);
}
@Override
public ImageViewFuture intoImageView(ImageView imageView) {
assert Thread.currentThread() == Looper.getMainLooper().getThread();
if (imageView == null)
throw new NullPointerException("imageView");
// no uri? just set a placeholder and bail
if (builder.uri == null) {
setIonDrawable(imageView, null, 0).cancel();
return FUTURE_IMAGEVIEW_NULL_URI;
}
// executeCache the request, see if we get a bitmap from cache.
BitmapFetcher bitmapFetcher = executeCache();//
if (bitmapFetcher.info != null) {
doAnimation(imageView, null, 0);
IonDrawable drawable = setIonDrawable(imageView, bitmapFetcher.info, Loader.LoaderEmitter.LOADED_FROM_MEMORY);
drawable.cancel();
IonDrawable.ImageViewFutureImpl imageViewFuture = drawable.getFuture();
imageViewFuture.reset();
imageViewFuture.setComplete(bitmapFetcher.info.exception, imageView);
return imageViewFuture;
}
IonDrawable drawable = setIonDrawable(imageView, null, 0);
doAnimation(imageView, loadAnimation, loadAnimationResource);
IonDrawable.ImageViewFutureImpl imageViewFuture = drawable.getFuture();
imageViewFuture.reset();
drawable.register(ion, bitmapFetcher.bitmapKey);
// nothing from cache, check to see if there's too many imageview loads
// already in progress
if (BitmapFetcher.shouldDeferImageView(ion)) {
bitmapFetcher.defer();
}
else {
bitmapFetcher.execute();
}
return imageViewFuture;
}
private IonDrawable setIonDrawable(ImageView imageView, BitmapInfo info, int loadedFrom) {
IonDrawable ret = IonDrawable.getOrCreateIonDrawable(imageView)
.ion(ion)
.setBitmap(info, loadedFrom)
.setSize(resizeWidth, resizeHeight)
.setError(errorResource, errorDrawable)
.setPlaceholder(placeholderResource, placeholderDrawable)
.setInAnimation(inAnimation, inAnimationResource)
.setDisableFadeIn(disableFadeIn);
imageView.setImageDrawable(ret);
return ret;
}
}
IonDrawable
class IonDrawble extends Drawable {
static IonDrawable getOrCreateIonDrawable(ImageView imageView) {
Drawable current = imageView.getDrawable();
IonDrawable ret;
if (current == null || !(current instanceof IonDrawable))
ret = new IonDrawable(imageView.getResources(), imageView);
else
ret = (IonDrawable)current;
// invalidate self doesn't seem to trigger the dimension check to be called by imageview.
// are drawable dimensions supposed to be immutable?
imageView.setImageDrawable(null);
return ret;
}
public IonDrawable(Resources resources, ImageView imageView) {
this.resources = resources;
paint = new Paint(DEFAULT_PAINT_FLAGS);
callback = new IonDrawableCallback(this, imageView);
}
public void register(Ion ion, String bitmapKey) {
String previousKey = callback.bitmapKey;
if (TextUtils.equals(previousKey, bitmapKey))
return;
callback.bitmapKey = bitmapKey;
ion.bitmapsPending.add(bitmapKey, callback);
unregister(ion, previousKey, callback);
}
}
// create an internal static class that can act as a callback.
// dont let it hold strong references to anything.
static class IonDrawableCallback implements FutureCallback<BitmapInfo> {
private WeakReference<IonDrawable> ionDrawableRef;
private ContextReference.ImageViewContextReference imageViewRef;
private String bitmapKey;
private ImageViewFutureImpl imageViewFuture = new ImageViewFutureImpl();
private Animation inAnimation;
private int inAnimationResource;
public IonDrawableCallback(IonDrawable drawable, ImageView imageView) {
ionDrawableRef = new WeakReference<IonDrawable>(drawable);
imageViewRef = new ContextReference.ImageViewContextReference(imageView);
}
@Override
public void onCompleted(Exception e, BitmapInfo result) {
assert Thread.currentThread() == Looper.getMainLooper().getThread();
assert result != null;
// see if the imageview is still alive and cares about this result
ImageView imageView = imageViewRef.get();
if (imageView == null)
return;
IonDrawable drawable = ionDrawableRef.get();
if (drawable == null)
return;
if (imageView.getDrawable() != drawable)
return;
imageView.setImageDrawable(null);
drawable.setBitmap(result, result.loadedFrom);
imageView.setImageDrawable(drawable);
IonBitmapRequestBuilder.doAnimation(imageView, inAnimation, inAnimationResource);
if (null != imageViewRef.isAlive()) {
imageViewFuture.cancelSilently();
return;
}
imageViewFuture.setComplete(e, imageView);
}
}
IonBitmapRequestBuilder
class IonBitmapRequestBuilder {
BitmapFetcher executeCache() {
final String downloadKey = computeDownloadKey();
String bitmapKey = computeBitmapKey(downloadKey);
// TODO: eliminate this allocation?
BitmapFetcher ret = new BitmapFetcher();
ret.downloadKey = downloadKey;
ret.bitmapKey = bitmapKey;
ret.hasTransforms = hasTransforms();
ret.resizeWidth = resizeWidth;
ret.resizeHeight = resizeHeight;
ret.builder = builder;
ret.transforms = transforms;
ret.animateGif = animateGif;
ret.deepZoom = deepZoom;
ret.postProcess = postProcess;
// see if this request can be fulfilled from the cache
if (!builder.noCache) {
BitmapInfo bitmap = builder.ion.bitmapCache.get(bitmapKey);
if (bitmap != null) {
ret.info = bitmap;
return ret;
}
}
return ret;
}
}
BitmapFetcher
class BitmapFetcher implements IonRequestBuilder.LoadRequestCallback{
public static boolean shouldDeferImageView(Ion ion) {
if (ion.bitmapsPending.keySet().size() <= MAX_IMAGEVIEW_LOAD)
return false;
int loadCount = 0;
for (String key: ion.bitmapsPending.keySet()) {
Object owner = ion.bitmapsPending.tag(key);
if (owner instanceof LoadBitmapBase) {
loadCount++;
if (loadCount > MAX_IMAGEVIEW_LOAD)
return true;
}
}
return false;
}
public DeferredLoadBitmap defer() {
DeferredLoadBitmap ret = new DeferredLoadBitmap(builder.ion, downloadKey, this);
executeTransforms(builder.ion);
return ret;
}
public void execute() {
final Ion ion = builder.ion;
// bitmaps that were transformed are put into the FileCache to prevent
// subsequent retransformation. See if we can retrieve the bitmap from the disk cache.
// See TransformBitmap for where the cache is populated.
FileCache fileCache = ion.responseCache.getFileCache();
if (!builder.noCache && hasTransforms && fileCache.exists(bitmapKey) && !deepZoom) {
TransformBitmap.getBitmapSnapshot(ion, bitmapKey, postProcess);
return;
}
// Perform a download as necessary.
if (ion.bitmapsPending.tag(downloadKey) == null && !fastLoad(builder.uri)) {
builder.setHandler(null);
builder.loadRequestCallback = this;
if (!deepZoom) {
IonRequestBuilder.EmitterTransform<ByteBufferList> emitterTransform = builder.execute(new ByteBufferListParser(), new Runnable() {
@Override
public void run() {
AsyncServer.post(Ion.mainHandler, new Runnable() {
@Override
public void run() {
ion.bitmapsPending.remove(downloadKey);
}
});
}
});
emitterTransform.setCallback(new LoadBitmap(ion, downloadKey, !hasTransforms, resizeWidth, resizeHeight, animateGif, emitterTransform));
}
else {
// System.out.println("downloading file for deepZoom");
File file = fileCache.getTempFile();
IonRequestBuilder.EmitterTransform<File> emitterTransform = builder.write(file);
LoadDeepZoom loadDeepZoom = new LoadDeepZoom(ion, downloadKey, animateGif, emitterTransform, fileCache) {
@Override
public void onCompleted(Exception e, File file) {
super.onCompleted(e, file);
}
};
emitterTransform.setCallback(loadDeepZoom);
}
}
executeTransforms(ion);
}
}