图片加载框架Picasso解析
picasso是Square公司开源的一个Android图形缓存库
主要有以下一些特性:
在adapter中回收和取消当前的下载;
使用最少的内存完成复杂的图形转换操作;
自动的内存和硬盘缓存;
图形转换操作,如变换大小,旋转等,提供了接口来让用户可以自定义转换操作;
加载载网络或本地资源;
Picasso.class
他有一个内部类,一般是通过他来创建实例的:
downloader(Downloader downloader) :
容许使用自定义的下载器,可以用okhttp或者volley,必须实现Downloader接口。
executor(ExecutorService executorService):
容许使用自己的线程池来进行下载
memoryCache(Cache memoryCache):
容许使用自己的缓存类,必须实现Cache接口。
requestTransformer(RequestTransformer transformer):
listener(Listener listener):
addRequestHandler(RequestHandler requestHandler):
indicatorsEnabled(boolean enabled):设置图片来源的指示器。
loggingEnabled(boolean enabled):
再来看build()方法:
- /** Create the {@link Picasso} instance. */
- public Picasso build() {
- Context context = this.context;
- if (downloader == null) {
- downloader = Utils.createDefaultDownloader(context);
- }
- if (cache == null) {
- cache = new LruCache(context);
- }
- if (service == null) {
- service = new PicassoExecutorService();
- }
- if (transformer == null) {
- transformer = RequestTransformer.IDENTITY;
- }
- Stats stats = new Stats(cache);
- Dispatcher dispatcher = new Dispatcher(context, service, HANDLER, downloader, cache, stats);
- return new Picasso(context, dispatcher, cache, listener, transformer,
- requestHandlers, stats, indicatorsEnabled, loggingEnabled);
- }
这里会使用默认的下载器,缓存类,线程池,并将这些对象封装到了分发器Dispatcher里。然后在返回一个Picasso对象。
一般情况下,如果不需要自定义bulid里的这些方法,可以使用Picasso.with(context)默认方法来获得单例对象:
- public static Picasso with(Context context) {
- if (singleton == null) {
- synchronized (Picasso.class) {
- if (singleton == null) {
- singleton = new Builder(context).build();
- }
- }
- }
- return singleton;
- }
如果需要自定义一些对象:
- public class SamplePicassoFactory {
- private static Picasso sPicasso;
- public static Picasso getPicasso(Context context) {
- if (sPicasso == null) {
- sPicasso = new Picasso.Builder(context)
- .downloader(new OkHttpDownloader(context, ConfigConstants.MAX_DISK_CACHE_SIZE))
- .memoryCache(new LruCache(ConfigConstants.MAX_MEMORY_CACHE_SIZE))
- .build();
- }
- return sPicasso;
- }
- }
通过上面的方法,获得sPicasso对象后就设置成了单例,但是最好设置成双重校验锁模式。
如果通过以上方法获得对象后,还可以通过Picasso.setSingletonInstance(Picasso picasso)方法设置对象到Picasso中,这样以后还是通过Picasso.with(context)来调用。
接着就可以通过以下方式设置加载源:
可以是uri地址,file文件,res资源drawable。
最终都是通过以下方法来创建一个RequestCreator对象:
- public RequestCreator load(Uri uri) {
- return new RequestCreator(this, uri, 0);
- }
- RequestCreator(Picasso picasso, Uri uri, int resourceId) {
- if (picasso.shutdown) {
- throw new IllegalStateException(
- "Picasso instance already shut down. Cannot submit new requests.");
- }
- this.picasso = picasso;
- this.data = new Request.Builder(uri, resourceId);
- }
RequestCreator对象是用来设置一系列属性的,如:
noPlaceholder():设置没有加载等待图片
placeholder(int placeholderResId):设置加载等待图片
placeholder(Drawable placeholderDrawable):设置加载等待图片
error(int errorResId):设置加载出错的图片。
error(Drawable errorDrawable):设置加载出错的图片。
tag(Object tag):设置标记
fit():自适应,下载的图片有多少像素就显示多少像素
resizeDimen(int targetWidthResId, int targetHeightResId):设置图片显示的像素。
resize(int targetWidth, int targetHeight):设置图片显示的像素。
centerCrop():设置ImageView的ScaleType属性.
centerInside():设置ImageView的ScaleType属性.
rotate(float degrees):设置旋转角度。
rotate(float degrees, float pivotX, float pivotY):设置以某个中心点设置某个旋转角度。
config(Bitmap.Config config):设置Bitmap的Config属性
priority(Priority priority):设置请求的优先级。
transform(Transformation transformation):
skipMemoryCache():跳过内存缓存
memoryPolicy(MemoryPolicy policy, MemoryPolicy... additional):
networkPolicy(NetworkPolicy policy, NetworkPolicy... additional):
noFade():没有淡入淡出效果
get():获得bitmap对象
fetch():
设置完以上一系列属性之后,最关键的就是into方法,现在以into(ImageView target)举例:
- public void into(ImageView target) {
- into(target, null);
- }
他实际调用的是:
- public void into(ImageView target, Callback callback) {
- long started = System.nanoTime();
- checkMain();
- if (target == null) {
- throw new IllegalArgumentException("Target must not be null.");
- }
- if (!data.hasImage()) {
- picasso.cancelRequest(target);
- if (setPlaceholder) {
- setPlaceholder(target, getPlaceholderDrawable());
- }
- return;
- }
- if (deferred) {
- if (data.hasSize()) {
- throw new IllegalStateException("Fit cannot be used with resize.");
- }
- int width = target.getWidth();
- int height = target.getHeight();
- if (width == 0 || height == 0) {
- if (setPlaceholder) {
- setPlaceholder(target, getPlaceholderDrawable());
- }
- picasso.defer(target, new DeferredRequestCreator(this, target, callback));
- return;
- }
- data.resize(width, height);
- }
- Request request = createRequest(started);
- String requestKey = createKey(request);
- if (shouldReadFromMemoryCache(memoryPolicy)) {
- Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
- if (bitmap != null) {
- picasso.cancelRequest(target);
- setBitmap(target, picasso.context, bitmap, MEMORY, noFade, picasso.indicatorsEnabled);
- if (picasso.loggingEnabled) {
- log(OWNER_MAIN, VERB_COMPLETED, request.plainId(), "from " + MEMORY);
- }
- if (callback != null) {
- callback.onSuccess();
- }
- return;
- }
- }
- if (setPlaceholder) {
- setPlaceholder(target, getPlaceholderDrawable());
- }
- Action action =
- new ImageViewAction(picasso, target, request, memoryPolicy, networkPolicy, errorResId,
- errorDrawable, requestKey, tag, callback, noFade);
- picasso.enqueueAndSubmit(action);
- }
- checkMain();
首先检查是否是主线程
- if (target == null) {
- throw new IllegalArgumentException("Target must not be null.");
- }
检查目标view是否存在
- if (!data.hasImage()) {
- picasso.cancelRequest(target);
- if (setPlaceholder) {
- setPlaceholder(target, getPlaceholderDrawable());
- }
- return;
- }
如果没有设置uri或者resDrawable,就停止请求,如果设置了加载等待的图片就设置,然后就return
- if (deferred) {
- if (data.hasSize()) {
- throw new IllegalStateException("Fit cannot be used with resize.");
- }
- int width = target.getWidth();
- int height = target.getHeight();
- if (width == 0 || height == 0) {
- if (setPlaceholder) {
- setPlaceholder(target, getPlaceholderDrawable());
- }
- picasso.defer(target, new DeferredRequestCreator(this, target, callback));
- return;
- }
- data.resize(width, height);
- }
如果设置fit自适应:如果已经设置了图片像素大小就抛异常,如果目标view的长宽等于0,就在设置等待图片后延期处理,如果不等于0就设置size到Request.Builder的data里。
- Request request = createRequest(started);
- String requestKey = createKey(request);
接着就创建Request,并生成一个String类型的requestKey。
- /** Create the request optionally passing it through the request transformer. */
- private Request createRequest(long started) {
- int id = nextId.getAndIncrement();
- Request request = data.build();
- request.id = id;
- request.started = started;
- boolean loggingEnabled = picasso.loggingEnabled;
- if (loggingEnabled) {
- log(OWNER_MAIN, VERB_CREATED, request.plainId(), request.toString());
- }
- Request transformed = picasso.transformRequest(request);
- if (transformed != request) {
- // If the request was changed, copy over the id and timestamp from the original.
- transformed.id = id;
- transformed.started = started;
- if (loggingEnabled) {
- log(OWNER_MAIN, VERB_CHANGED, transformed.logId(), "into " + transformed);
- }
- }
- return transformed;
- }
在以上代码可以看出,这里调用picasso.transformRequest(request);来给使用者提供一个可以更改request的机会,他最终调用的是Picasso.Build里面的通过requestTransformer(RequestTransformer transformer)方法传进去的RequestTransformer 接口:
- public interface RequestTransformer {
- /**
- * Transform a request before it is submitted to be processed.
- *
- * @return The original request or a new request to replace it. Must not be null.
- */
- Request transformRequest(Request request);
- /** A {@link RequestTransformer} which returns the original request. */
- RequestTransformer IDENTITY = new RequestTransformer() {
- @Override public Request transformRequest(Request request) {
- return request;
- }
- };
- }
默认使用的是IDENTITY。这里没有做任何的修改,如果有需要可以自己设置接口以达到修改Request的目的。
- if (shouldReadFromMemoryCache(memoryPolicy)) {
- Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
- if (bitmap != null) {
- picasso.cancelRequest(target);
- setBitmap(target, picasso.context, bitmap, MEMORY, noFade, picasso.indicatorsEnabled);
- if (picasso.loggingEnabled) {
- log(OWNER_MAIN, VERB_COMPLETED, request.plainId(), "from " + MEMORY);
- }
- if (callback != null) {
- callback.onSuccess();
- }
- return;
- }
- }
接着要判断是否需要从缓存中读取图片,如果需要,就要根据requestKey从缓存中读取:
- Bitmap quickMemoryCacheCheck(String key) {
- Bitmap cached = cache.get(key);
- if (cached != null) {
- stats.dispatchCacheHit();
- } else {
- stats.dispatchCacheMiss();
- }
- return cached;
- }
这里的cache用的是LruCache内存缓存类,这个内存缓存类,实现了Cache接口,最后调用的是:
- @Override public Bitmap get(String key) {
- if (key == null) {
- throw new NullPointerException("key == null");
- }
- Bitmap mapValue;
- synchronized (this) {
- mapValue = map.get(key);
- if (mapValue != null) {
- hitCount++;
- return mapValue;
- }
- missCount++;
- }
- return null;
- }
这里的map是LinkedHashMap<String, Bitmap>:
- this.map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true);
缓存的策略稍后分析,现在先回到前面,如果从缓存中拿到的bitmap不等于null,就调用picasso.cancelRequest(target)来删除请求,然后通过
- setBitmap(target, picasso.context, bitmap, MEMORY, noFade, picasso.indicatorsEnabled);
设置图片,然后如果设置了callback回调,再回掉callback.onSuccess();方法,然后就return。
如果没有设置内存缓存,或者缓存中的图片已经不存在:
- if (setPlaceholder) {
- setPlaceholder(target, getPlaceholderDrawable());
- }
- Action action =
- new ImageViewAction(picasso, target, request, memoryPolicy, networkPolicy, errorResId,
- errorDrawable, requestKey, tag, callback, noFade);
- picasso.enqueueAndSubmit(action);
接着就设置等待加载图片,然后封装一个action,然后将action加入到分发器中:
- void enqueueAndSubmit(Action action) {
- Object target = action.getTarget();
- if (target != null && targetToAction.get(target) != action) {
- // This will also check we are on the main thread.
- cancelExistingRequest(target);
- targetToAction.put(target, action);
- }
- submit(action);
- }
- void submit(Action action) {
- dispatcher.dispatchSubmit(action);
- }
然后调用了dispatcher的performSubmit()方法:
- void performSubmit(Action action) {
- performSubmit(action, true);
- }
- void performSubmit(Action action, boolean dismissFailed) {
- if (pausedTags.contains(action.getTag())) {
- pausedActions.put(action.getTarget(), action);
- if (action.getPicasso().loggingEnabled) {
- log(OWNER_DISPATCHER, VERB_PAUSED, action.request.logId(),
- "because tag '" + action.getTag() + "' is paused");
- }
- return;
- }
- BitmapHunter hunter = hunterMap.get(action.getKey());
- if (hunter != null) {
- hunter.attach(action);
- return;
- }
- if (service.isShutdown()) {
- if (action.getPicasso().loggingEnabled) {
- log(OWNER_DISPATCHER, VERB_IGNORED, action.request.logId(), "because shut down");
- }
- return;
- }
- hunter = forRequest(action.getPicasso(), this, cache, stats, action);
- hunter.future = service.submit(hunter);
- hunterMap.put(action.getKey(), hunter);
- if (dismissFailed) {
- failedActions.remove(action.getTarget());
- }
- if (action.getPicasso().loggingEnabled) {
- log(OWNER_DISPATCHER, VERB_ENQUEUED, action.request.logId());
- }
- }
这里通过 hunter = forRequest(action.getPicasso(), this, cache, stats, action);获得一个BitmapHunter对象,接着就提交到线程池中 hunter.future = service.submit(hunter);:
接着线程池就会调用hunter 的run方法,因为这实现了Runnable对象:
- @Override public void run() {
- try {
- updateThreadName(data);
- if (picasso.loggingEnabled) {
- log(OWNER_HUNTER, VERB_EXECUTING, getLogIdsForHunter(this));
- }
- result = hunt();
- if (result == null) {
- dispatcher.dispatchFailed(this);
- } else {
- dispatcher.dispatchComplete(this);
- }
- } catch (Downloader.ResponseException e) {
- if (!e.localCacheOnly || e.responseCode != 504) {
- exception = e;
- }
- dispatcher.dispatchFailed(this);
- } catch (NetworkRequestHandler.ContentLengthException e) {
- exception = e;
- dispatcher.dispatchRetry(this);
- } catch (IOException e) {
- exception = e;
- dispatcher.dispatchRetry(this);
- } catch (OutOfMemoryError e) {
- StringWriter writer = new StringWriter();
- stats.createSnapshot().dump(new PrintWriter(writer));
- exception = new RuntimeException(writer.toString(), e);
- dispatcher.dispatchFailed(this);
- } catch (Exception e) {
- exception = e;
- dispatcher.dispatchFailed(this);
- } finally {
- Thread.currentThread().setName(Utils.THREAD_IDLE_NAME);
- }
- }
接着调用hunt()方法:
- Bitmap hunt() throws IOException {
- Bitmap bitmap = null;
- if (shouldReadFromMemoryCache(memoryPolicy)) {
- bitmap = cache.get(key);
- if (bitmap != null) {
- stats.dispatchCacheHit();
- loadedFrom = MEMORY;
- if (picasso.loggingEnabled) {
- log(OWNER_HUNTER, VERB_DECODED, data.logId(), "from cache");
- }
- return bitmap;
- }
- }
- data.networkPolicy = retryCount == 0 ? NetworkPolicy.OFFLINE.index : networkPolicy;
- RequestHandler.Result result = requestHandler.load(data, networkPolicy);
- if (result != null) {
- loadedFrom = result.getLoadedFrom();
- exifRotation = result.getExifOrientation();
- bitmap = result.getBitmap();
- // If there was no Bitmap then we need to decode it from the stream.
- if (bitmap == null) {
- InputStream is = result.getStream();
- try {
- bitmap = decodeStream(is, data);
- } finally {
- Utils.closeQuietly(is);
- }
- }
- }
- if (bitmap != null) {
- if (picasso.loggingEnabled) {
- log(OWNER_HUNTER, VERB_DECODED, data.logId());
- }
- stats.dispatchBitmapDecoded(bitmap);
- if (data.needsTransformation() || exifRotation != 0) {
- synchronized (DECODE_LOCK) {
- if (data.needsMatrixTransform() || exifRotation != 0) {
- bitmap = transformResult(data, bitmap, exifRotation);
- if (picasso.loggingEnabled) {
- log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId());
- }
- }
- if (data.hasCustomTransformations()) {
- bitmap = applyCustomTransformations(data.transformations, bitmap);
- if (picasso.loggingEnabled) {
- log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId(), "from custom transformations");
- }
- }
- }
- if (bitmap != null) {
- stats.dispatchBitmapTransformed(bitmap);
- }
- }
- }
- return bitmap;
- }
这里如果从内存缓存中渠道bitmap对象,就直接返回了;否则通过requestHandler.load(data, networkPolicy);来发起网络请求(这个是NetworkRequestHandler类型的):
- @Override public Result load(Request request, int networkPolicy) throws IOException {
- Response response = downloader.load(request.uri, request.networkPolicy);
- if (response == null) {
- return null;
- }
- Picasso.LoadedFrom loadedFrom = response.cached ? DISK : NETWORK;
- Bitmap bitmap = response.getBitmap();
- if (bitmap != null) {
- return new Result(bitmap, loadedFrom);
- }
- InputStream is = response.getInputStream();
- if (is == null) {
- return null;
- }
- // Sometimes response content length is zero when requests are being replayed. Haven't found
- // root cause to this but retrying the request seems safe to do so.
- if (loadedFrom == DISK && response.getContentLength() == 0) {
- Utils.closeQuietly(is);
- throw new ContentLengthException("Received response with 0 content-length header.");
- }
- if (loadedFrom == NETWORK && response.getContentLength() > 0) {
- stats.dispatchDownloadFinished(response.getContentLength());
- }
- return new Result(is, loadedFrom);
- }
这里调用了downloader.load(request.uri, request.networkPolicy)方法,这是一个UrlConnectionDownloader类型的对象,调用的是UrlConnectionDownloader的load()方法:
- @Override public Response load(Uri uri, int networkPolicy) throws IOException {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
- installCacheIfNeeded(context);
- }
- HttpURLConnection connection = openConnection(uri);
- connection.setUseCaches(true);
- if (networkPolicy != 0) {
- String headerValue;
- if (NetworkPolicy.isOfflineOnly(networkPolicy)) {
- headerValue = FORCE_CACHE;
- } else {
- StringBuilder builder = CACHE_HEADER_BUILDER.get();
- builder.setLength(0);
- if (!NetworkPolicy.shouldReadFromDiskCache(networkPolicy)) {
- builder.append("no-cache");
- }
- if (!NetworkPolicy.shouldWriteToDiskCache(networkPolicy)) {
- if (builder.length() > 0) {
- builder.append(',');
- }
- builder.append("no-store");
- }
- headerValue = builder.toString();
- }
- connection.setRequestProperty("Cache-Control", headerValue);
- }
- int responseCode = connection.getResponseCode();
- if (responseCode >= 300) {
- connection.disconnect();
- throw new ResponseException(responseCode + " " + connection.getResponseMessage(),
- networkPolicy, responseCode);
- }
- long contentLength = connection.getHeaderFieldInt("Content-Length", -1);
- boolean fromCache = parseResponseSourceHeader(connection.getHeaderField(RESPONSE_SOURCE));
- return new Response(connection.getInputStream(), fromCache, contentLength);
- }
如果系统版本是4.0以上,就使用installCacheIfNeeded(context)来启动data\data\包名\cacha下的某个目录的磁盘缓存:
- private static void installCacheIfNeeded(Context context) {
- // DCL + volatile should be safe after Java 5.
- if (cache == null) {
- try {
- synchronized (lock) {
- if (cache == null) {
- cache = ResponseCacheIcs.install(context);
- }
- }
- } catch (IOException ignored) {
- }
- }
- }
- private static class ResponseCacheIcs {
- static Object install(Context context) throws IOException {
- File cacheDir = Utils.createDefaultCacheDir(context);
- HttpResponseCache cache = HttpResponseCache.getInstalled();
- if (cache == null) {
- long maxSize = Utils.calculateDiskCacheSize(cacheDir);
- cache = HttpResponseCache.install(cacheDir, maxSize);
- }
- return cache;
- }
但是如果要是用这个磁盘缓存,就要在HttpURLConnection的响应头上加上缓存的控制头"Cache-Control"!
最后返回new Response(connection.getInputStream(), fromCache, contentLength)请求结果。
接着回到上面的hunt()方法的流程继续:
- if (result != null) {
- loadedFrom = result.getLoadedFrom();
- exifRotation = result.getExifOrientation();
- bitmap = result.getBitmap();
- // If there was no Bitmap then we need to decode it from the stream.
- if (bitmap == null) {
- InputStream is = result.getStream();
- try {
- bitmap = decodeStream(is, data);
- } finally {
- Utils.closeQuietly(is);
- }
- }
- }
- if (bitmap != null) {
- if (picasso.loggingEnabled) {
- log(OWNER_HUNTER, VERB_DECODED, data.logId());
- }
- stats.dispatchBitmapDecoded(bitmap);
- if (data.needsTransformation() || exifRotation != 0) {
- synchronized (DECODE_LOCK) {
- if (data.needsMatrixTransform() || exifRotation != 0) {
- bitmap = transformResult(data, bitmap, exifRotation);
- if (picasso.loggingEnabled) {
- log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId());
- }
- }
- if (data.hasCustomTransformations()) {
- bitmap = applyCustomTransformations(data.transformations, bitmap);
- if (picasso.loggingEnabled) {
- log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId(), "from custom transformations");
- }
- }
- }
- if (bitmap != null) {
- stats.dispatchBitmapTransformed(bitmap);
- }
- }
- }
- return bitmap;
然后bitmap返回到run()方法里面的result应用上:
- if (result == null) {
- dispatcher.dispatchFailed(this);
- } else {
- dispatcher.dispatchComplete(this);
- }
如果result有结果就分发完成消息,最后将会调用到Picasso里面:
- static final Handler HANDLER = new Handler(Looper.getMainLooper()) {
- @Override public void handleMessage(Message msg) {
- switch (msg.what) {
- case HUNTER_BATCH_COMPLETE: {
- @SuppressWarnings("unchecked") List<BitmapHunter> batch = (List<BitmapHunter>) msg.obj;
- //noinspection ForLoopReplaceableByForEach
- for (int i = 0, n = batch.size(); i < n; i++) {
- BitmapHunter hunter = batch.get(i);
- hunter.picasso.complete(hunter);
- }
- break;
- }
- void complete(BitmapHunter hunter) {
- Action single = hunter.getAction();
- List<Action> joined = hunter.getActions();
- boolean hasMultiple = joined != null && !joined.isEmpty();
- boolean shouldDeliver = single != null || hasMultiple;
- if (!shouldDeliver) {
- return;
- }
- Uri uri = hunter.getData().uri;
- Exception exception = hunter.getException();
- Bitmap result = hunter.getResult();
- LoadedFrom from = hunter.getLoadedFrom();
- if (single != null) {
- deliverAction(result, from, single);
- }
- if (hasMultiple) {
- //noinspection ForLoopReplaceableByForEach
- for (int i = 0, n = joined.size(); i < n; i++) {
- Action join = joined.get(i);
- deliverAction(result, from, join);
- }
- }
- if (listener != null && exception != null) {
- listener.onImageLoadFailed(this, uri, exception);
- }
- }
接着分发action:
- private void deliverAction(Bitmap result, LoadedFrom from, Action action) {
- if (action.isCancelled()) {
- return;
- }
- if (!action.willReplay()) {
- targetToAction.remove(action.getTarget());
- }
- if (result != null) {
- if (from == null) {
- throw new AssertionError("LoadedFrom cannot be null.");
- }
- action.complete(result, from);
- if (loggingEnabled) {
- log(OWNER_MAIN, VERB_COMPLETED, action.request.logId(), "from " + from);
- }
- } else {
- action.error();
- if (loggingEnabled) {
- log(OWNER_MAIN, VERB_ERRORED, action.request.logId());
- }
- }
- }
然后调用的是ImageViewAction里面的action.complete(result, from)方法:
- @Override public void complete(Bitmap result, Picasso.LoadedFrom from) {
- if (result == null) {
- throw new AssertionError(
- String.format("Attempted to complete action with no result!\n%s", this));
- }
- ImageView target = this.target.get();
- if (target == null) {
- return;
- }
- Context context = picasso.context;
- boolean indicatorsEnabled = picasso.indicatorsEnabled;
- PicassoDrawable.setBitmap(target, context, result, from, noFade, indicatorsEnabled);
- if (callback != null) {
- callback.onSuccess();
- }
- }
最后一步通过PicassoDrawable.setBitmap来设置,就算大功完成了。
附上部分流程图:
图片加载框架Picasso解析的更多相关文章
- Android 图片加载框架Picasso基本使用和源码完全解析(巨细无比)
写在之前 原本打算是每周更新一篇博文,同时记录一周的生活状态,但是稍微工作忙一点就顾不上写博客了.悲催 还是说下最近的状况,最近两周一直在接公司申请的计费点, 沃商店,银贝壳,微信等等,然后就是不停的 ...
- Android图片加载框架Picasso最全使用教程4
通过前几篇的学习,我们已经对Picasso的加载图片的用法有了很深的了解,接下来我们开始分析Picasso为我们提供的其他高级功能及内存分析,Let’sGo ! Picasso进行图片的旋转(Rota ...
- Android图片加载框架Picasso最全使用教程3
前面我们对Picasso的用法有了一定得了解,下面就分析一下一些特殊情况下,Picasso的用法. 调用.noFade() Picasso的默认图片加载方式有一个淡入的效果,如果调用了noFade() ...
- Android图片加载框架Picasso最全使用教程2
前言 前面我们已经介绍了Picasso的基本用法及如何将一张图片加载到ImageView中,下面我们就利用Picasso在ListView中加载图片;Let’s Go! 一个ListView的简单应用 ...
- Android图片加载框架Picasso最全使用教程1
Picasso介绍 Picasso是Square公司开源的一个Android图形缓存库 A powerful image downloading and caching library for And ...
- 第一次源码分析: 图片加载框架Picasso源码分析
使用: Picasso.with(this) .load("http://imgstore.cdn.sogou.com/app/a/100540002/467502.jpg") . ...
- 源码分析: 图片加载框架Picasso源码分析
使用: Picasso.with(this) .load("http://imgstore.cdn.sogou.com/app/a/100540002/467502.jpg") . ...
- Android图片加载框架Picasso最全使用教程5
在之前的四篇博客中,我们学习了所有的关于Picasso的主要方法,我们也对这个Picasso有了一个很深的认识,下面就主要对Picasso自身进行分析,这样的话,会让我们更了解Picasso的核心方法 ...
- Android图片加载框架之Picasso
相信做Android开发的对Square公司一定不会陌生,大名鼎鼎的网络请求框架Retrofit就来源于它,今天学习的是该公司出品的图片加载框架Picasso. 项目地址 https://github ...
随机推荐
- 视频分享:过五关斩六将——我要做IT面霸!
这是我在某网站分享的网络直播课程,现在博客园分享给大家! 本视频适合以下朋友观看: 1)在校计算机及相关专业学生,希望你了解应聘的要求后来改善你的学习: 2)正在求职或打算跳槽的人士: 3)HR或公司 ...
- JAVA中的枚举小结
枚举 将一组有限集合创建为一种新的类型,集合里面的值可以作为程序组件使用: 枚举基本特性 以下代码是枚举的简单使用: 使用values方法返回enum实例的数组 使用ordinal方法返回每个enum ...
- Storm系列(二):使用Csharp创建你的第一个Storm拓扑(wordcount)
WordCount在大数据领域就像学习一门语言时的hello world,得益于Storm的开源以及Storm.Net.Adapter,现在我们也可以像Java或Python一样,使用Csharp创建 ...
- Servlet/JSP-06 Session
一. 概述 Session 指客户端(浏览器)与服务器端之间保持状态的解决方案,有时候也用来指这种解决方案的存储结构. 当服务器端程序要为客户端的请求创建一个 Session 时,会首先检查这个请求里 ...
- JVM探索之——内存管理(一)
本系列的第一篇文章,预计本系列最后面会有两三个案例. Java与C.C++不一样Java不需要Coder进行手动内存管理,而这一切都交给JVM进行自动内存管理,这从某种程度上来说也减轻了我们Coder ...
- GacUI学习(二)
GacUI学习(一)之高仿系统记事本(二) 转载请注明来源:http://www.cnblogs.com/lyfh/p/6107614.html 上篇<GacUI学习(一)之高仿系统记事本(一) ...
- Android getevent
详细用法如下: 源码复制打印? Usage: getevent [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] ...
- android xml 布局错误(黑掉了)Missing styles. Is the correct theme chosen for this layout?
发现在调整页面的时候 ,老是报以下错误,导致无法静态显示ui效果. Missing styles. Is the correct theme chosen for this layout? Use t ...
- 利用apply和arguments复用方法
首先,有个单例对象,它上面挂了很多静态工具方法.其中有一个是each,用来遍历数组或对象. var nativeForEach = [].forEach var nativeMap = [].map ...
- python可分组字典
# -*- encoding: UTF-8 -*- from collections import defaultdict class News(object): def __init__(self, ...