Glide优缺点
优点:
1、多样化媒体加载
2、生命周期集成
3、高效缓存策略
4、内存开销小
缺点:
使用方法复杂
由于其功能强大,所以使用的方法非常多,源码比较复杂,比较大
Glide加载本质也是调用系统的网络控件HttpURLConnection去下载图片资源,然后转换成Bitmap然后调取系统setImageBitmap方法去加载网络图片,详细步骤如下:
1、开启网络子线程请求网络 HttpUrlConnection 2 、渲染UI,切换到主线程 3 、将流转换成bitmap 4 、bitmap设置到image
相关代码:
public void getImage(View view) { String url = "https://img2.baidu.com/it/u=3542803101,6620711&fm=26&fmt=auto&gp=0.jpg"; // Glide.with(this).load(url).into(mImage); //加载图片 new Thread(new Runnable() { @Override public void run() { Bitmap bitmap = getImageBitmap(url); runOnUiThread(new Runnable() { @Override public void run() { mImage.setImageBitmap(bitmap); } }); } }).start(); } private Bitmap getImageBitmap(String url){ Bitmap bitmap = null; try { URL imgUrl = new URL(url); HttpURLConnection coon = (HttpURLConnection) imgUrl.openConnection(); coon.connect(); InputStream is = coon.getInputStream(); //bitma工程类 转化成bitmap bitmap = BitmapFactory.decodeStream(is); is.close(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return bitmap; }
activity中动态加载一个fragment,并且打印他们所有生命周期
//动态加载fragment FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); fragmentTransaction.replace(android.R.id.content,new Fragment1()); fragmentTransaction.commit();
当activity启动时:
onAttcah:和activity关联之后调用
当activity关闭时时:先走fragment生命周期,再走activity的生命周期
具体关联流程:
经过测试,fragment注释掉onCreateView创建视图方法,依然可以调用,相当于一个透明的fragment,这样就可以利用它的生命周期的监听,做一些操作
经过查看源码,在Glide的源码中with的方法调用里面,也会创建一个fragment并绑定它的生命周期,不过只绑定了onStart,onStop,onDestory
//Glide源码 @NonNull public RequestManager get(@NonNull FragmentActivity activity) { if (Util.isOnBackgroundThread()) { return get(activity.getApplicationContext()); } else { assertNotDestroyed(activity); frameWaiter.registerSelf(activity); FragmentManager fm = activity.getSupportFragmentManager(); return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity)); } } @NonNull private RequestManager supportFragmentGet( @NonNull Context context, @NonNull FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) { SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint); RequestManager requestManager = current.getRequestManager(); if (requestManager == null) { // TODO(b/27524013): Factor out this Glide.get() call. Glide glide = Glide.get(context); requestManager = factory.build( glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context); // This is a bit of hack, we're going to start the RequestManager, but not the // corresponding Lifecycle. It's safe to start the RequestManager, but starting the // Lifecycle might trigger memory leaks. See b/154405040 if (isParentVisible) { requestManager.onStart(); } current.setRequestManager(requestManager); } return requestManager; }
SupportRequestManagerFragment就是加载到当前activity的fragment
在 SupportRequestManagerFragment有lifecycle方法,说明有生命周期绑定
@VisibleForTesting @SuppressLint("ValidFragment") public SupportRequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) { this.lifecycle = lifecycle; }
在ActivityFragmentLifecycle查看发现在如下方法:说明Glide绑定了fragment的相关三个方法
void onStart() { isStarted = true; for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) { lifecycleListener.onStart(); } } void onStop() { isStarted = false; for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) { lifecycleListener.onStop(); } } void onDestroy() { isDestroyed = true; for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) { lifecycleListener.onDestroy(); } } }
在SupportRequestManagerFragment中查看:
@Override public void onStart() { super.onStart(); lifecycle.onStart(); } @Override public void onStop() { super.onStop(); lifecycle.onStop(); } @Override public void onDestroy() { super.onDestroy(); lifecycle.onDestroy(); unregisterFragmentWithRoot(); }
在RequestManager实现相关几个方法,做相关操作
/** * Lifecycle callback that registers for connectivity events (if the * android.permission.ACCESS_NETWORK_STATE permission is present) and restarts failed or paused * requests. */ @Override public synchronized void onStart() { resumeRequests(); targetTracker.onStart(); } /** * Lifecycle callback that unregisters for connectivity events (if the * android.permission.ACCESS_NETWORK_STATE permission is present) and pauses in progress loads. */ @Override public synchronized void onStop() { pauseRequests(); targetTracker.onStop(); } /** * Lifecycle callback that cancels all in progress requests and clears and recycles resources for * all completed requests. */ @Override public synchronized void onDestroy() { targetTracker.onDestroy(); for (Target<?> target : targetTracker.getAll()) { clear(target); } targetTracker.clear(); requestTracker.clearRequests(); lifecycle.removeListener(this); lifecycle.removeListener(connectivityMonitor); Util.removeCallbacksOnUiThread(addSelfToLifecycle); glide.unregisterRequestManager(this); }
总结:
在onStart方法中,调取url链接,计算图片宽高,使用httpurlconnection下载图片并加载
如果页面关闭的时候:
先调用onstop暂停各种资源加载
在调用onDestroy释放资源,移除各种加载方法,清除内存中图片资源,下次在加载同一张图片,会去从硬盘文件中读取这张图片,如果没有,才会请求网络下载,如同同一个链接返回不同的图片,glide加载还是旧的图片,因为硬盘地址中存的key是链接的地址,地址没有变化,所以从本地读取的图片还是以前的。
当activity调取onDestroy销毁的时候,fragment先调取onDestroy方法。
Glide.with(this).load(url).into(mImage),中的context不能传 getApplicationContext()这个方法,因为 getApplicationContext()这个方法是整个应用阶段都会保留,这样fragment绑定的就不是activity,而是application。
Glide.with(this).load(url).into(mImage);这段代码不能在子线程执行,因为通过源码发现,如果运行不在主线程,直接抛异常,如下:
public static void assertMainThread() { if (!isOnMainThread()) { throw new IllegalArgumentException("You must call this method on the main thread"); } }
在anctivity中会回调这个方法:当内存严重不足是,会回调这个方法,去清理内存
void onTrimMemory(@TrimMemoryLevel int level); public void onTrimMemory(int level) { if (DEBUG_LIFECYCLE) Slog.v(TAG, "onTrimMemory " + this + ": " + level); mCalled = true; mFragments.dispatchTrimMemory(level); }
在FirstFrameAndAfterTrimMemoryWaiter类中查到了,内存检测的方法:
@Override public void onTrimMemory(int level) {} @Override public void onLowMemory() { onTrimMemory(TRIM_MEMORY_UI_HIDDEN); }
这个方法的实现方法,会去注册传入的activity
在Glide源码的Glide类中,回调了两个内存检测方法:处理相关内存不足的逻辑
//内存不足 @Override public void onTrimMemory(int level) { trimMemory(level); } public void trimMemory(int level) { // Engine asserts this anyway when removing resources, fail faster and consistently Util.assertMainThread(); // Request managers need to be trimmed before the caches and pools, in order for the latter to // have the most benefit. synchronized (managers) { for (RequestManager manager : managers) { manager.onTrimMemory(level); } } // memory cache needs to be trimmed before bitmap pool to trim re-pooled Bitmaps too. See #687. memoryCache.trimMemory(level); bitmapPool.trimMemory(level); arrayPool.trimMemory(level); } //内存严重不足 @Override public void onLowMemory() { clearMemory(); } public void clearMemory() { // Engine asserts this anyway when removing resources, fail faster and consistently Util.assertMainThread(); // memory cache needs to be cleared before bitmap pool to clear re-pooled Bitmaps too. See #687. memoryCache.clearMemory(); bitmapPool.clearMemory(); arrayPool.clearMemory(); }
Glide加载图片,即使是网络断开了,在重新链接上,也会加载出来图片,这是因为Glide内部有网络监听机制
在RequestManager中有个网络监听的内部类,做相关处理,如果断网就重新请求,点击onConnectivityChanged这个方法,会跳转到广播注册,监听网络
private class RequestManagerConnectivityListener implements ConnectivityMonitor.ConnectivityListener { @GuardedBy("RequestManager.this") private final RequestTracker requestTracker; RequestManagerConnectivityListener(@NonNull RequestTracker requestTracker) { this.requestTracker = requestTracker; } @Override public void onConnectivityChanged(boolean isConnected) { if (isConnected) { synchronized (RequestManager.this) { requestTracker.restartRequests(); } } } } public void restartRequests() { for (Request request : Util.getSnapshot(requests)) { if (!request.isComplete() && !request.isCleared()) { request.clear(); if (!isPaused) { //断网重新请求 request.begin(); } else { // Ensure the request will be restarted in onResume. pendingRequests.add(request); } } } }
然后在DefaultConnectivityMonitor注册广播,然后监测网络
//注册广播 private final BroadcastReceiver connectivityReceiver = new BroadcastReceiver() { @Override public void onReceive(@NonNull Context context, Intent intent) { boolean wasConnected = isConnected; isConnected = isConnected(context); if (wasConnected != isConnected) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "connectivity changed, isConnected: " + isConnected); } listener.onConnectivityChanged(isConnected); } } }; //isConnected查看当前网络状态并且返回 @SuppressWarnings("WeakerAccess") @Synthetic // Permissions are checked in the factory instead. @SuppressLint("MissingPermission") boolean isConnected(@NonNull Context context) { ConnectivityManager connectivityManager = Preconditions.checkNotNull( (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE)); NetworkInfo networkInfo; try { networkInfo = connectivityManager.getActiveNetworkInfo(); } catch (RuntimeException e) { // #1405 shows that this throws a SecurityException. // b/70869360 shows that this throws NullPointerException on APIs 22, 23, and 24. // b/70869360 also shows that this throws RuntimeException on API 24 and 25. if (Log.isLoggable(TAG, Log.WARN)) { Log.w(TAG, "Failed to determine connectivity status when connectivity changed", e); } // Default to true; return true; } return networkInfo != null && networkInfo.isConnected(); }
Glide中永远只有一个fragment,便于复用和生命周期管理
每次加载图片的时候,with传入context,后获取绑定fragment,这时候拿fragment先去从tag拿,tag没有,就回去拿缓存的,如果缓存的fragment也没有,就会去创建fragment并且前加到集合中,并且发了个handler消息,移除了以前的fragment
final Map<FragmentManager, SupportRequestManagerFragment> pendingSupportRequestManagerFragments = new HashMap<>(); @NonNull private SupportRequestManagerFragment getSupportRequestManagerFragment( @NonNull final FragmentManager fm, @Nullable Fragment parentHint) { SupportRequestManagerFragment current = (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG); if (current == null) { current = pendingSupportRequestManagerFragments.get(fm); if (current == null) { current = new SupportRequestManagerFragment(); current.setParentFragmentHint(parentHint); pendingSupportRequestManagerFragments.put(fm, current); fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss(); handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget(); } } return current; }
每次缓存fragment都会移除上一个fragment
@Override public boolean handleMessage(Message message) { boolean handled = true; Object removed = null; Object key = null; switch (message.what) { case ID_REMOVE_FRAGMENT_MANAGER: android.app.FragmentManager fm = (android.app.FragmentManager) message.obj; key = fm; removed = pendingRequestManagerFragments.remove(fm); break; case ID_REMOVE_SUPPORT_FRAGMENT_MANAGER: FragmentManager supportFm = (FragmentManager) message.obj; key = supportFm; //移除上一个 removed = pendingSupportRequestManagerFragments.remove(supportFm); break; default: handled = false; break; } if (handled && removed == null && Log.isLoggable(TAG, Log.WARN)) { Log.w(TAG, "Failed to remove expected request manager fragment, manager: " + key); } return handled; }