Glide源码学习-生命周期
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;
}
一、Glide生命周期
1.查看Activity和Fragment的生命周期
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,这样就可以利用它的生命周期的监听,做一些操作
2.读取生命周期相关源码
经过查看源码,在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");
}
}
二、Glide内存检测
在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加载图片,即使是网络断开了,在重新链接上,也会加载出来图片,这是因为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
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;
}