前言
我们在编写Android程序时,Glide图片加载框架已成为大多数App必不可少的部分。我这准备分为上、中、下三篇文章解读Glide源码。接下来我将从如下几点解读Glide源码的上部分。
- Glide 网络请求
- Glide 生命周期举例
- Glide 生命周期管理
- Glide 为什么能监听网络判断
Android开发Glide原理解析/面试题解析_哔哩哔哩_bilibili
1、Glide 网络请求
在讲Glide 网络请求之前,先看看最原始的网络图片请求加载方式。
public void loadImageUrl(View view) {
//最原始的网络图片加载
//1、请求网络,子线程请求网络,HttpURLConnection
//2、渲染UI,主线
//3、切换到主线程
//4、将流转成Bitmap
//5、bitmap设置到imageview
final String url = "https://img0.baidu.com/it/u=3736037748,233424948&fm=26&fmt=auto&gp=0.jpg";
//非主线程操作的网络请求
new Thread(new Runnable() {
@Override
public void run() {
final Bitmap bitmap = getImageBitmap(url);
runOnUiThread(new Runnable() {
@Override
public void run() {
iv_image1.setImageBitmap(bitmap);
}
});
}
}).start();
}
//http
private Bitmap getImageBitmap(String url){
Bitmap bitmap=null;
try {
URL imageUrl = new URL(url);
//要用到HttpURLConnection
HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
//Bitmap工厂类,流转化成Bitmap
bitmap = BitmapFactory.decodeStream(is);
is.close();
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
非常原始的方式,开启一个子线程,通过 HttpURLConnection 得到连接流,最后再通过BitmapFactory 转为 Bitmap。
那么我们来看看Glide是怎样进行网络请求的。
定位到 HttpUrlFetcher.class
public class HttpUrlFetcher implements DataFetcher {
...略
@Override
public void loadData(@NonNull Priority priority,
@NonNull DataCallback super InputStream> callback) {
long startTime = LogTime.getLogTime();
try {
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
callback.onDataReady(result);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to load data for url", e);
}
callback.onLoadFailed(e);
} finally {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime));
}
}
}
...略
}
源码解析
很明显这里这调用了 loadDataWithRedirects 方法得到对应的 InputStream 。
loadDataWithRedirects
private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl,
...略
urlConnection = connectionFactory.build(url);
for (Map.Entry headerEntry : headers.entrySet()) {
urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
}
urlConnection.setConnectTimeout(timeout);
urlConnection.setReadTimeout(timeout);
urlConnection.setUseCaches(false);
urlConnection.setDoInput(true);
urlConnection.setInstanceFollowRedirects(false);
urlConnection.connect();
stream = urlConnection.getInputStream();
if (isCancelled) {
return null;
}
final int statusCode = urlConnection.getResponseCode();
if (isHttpOk(statusCode)) {
return getStreamForSuccessfulRequest(urlConnection);
} else if (isHttpRedirect(statusCode)) {
String redirectUrlString = urlConnection.getHeaderField("Location");
if (TextUtils.isEmpty(redirectUrlString)) {
throw new HttpException("Received empty or null redirect url");
}
URL redirectUrl = new URL(url, redirectUrlString);
cleanup();
return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
} else if (statusCode == INVALID_STATUS_CODE) {
throw new HttpException(statusCode);
} else {
throw new HttpException(urlConnection.getResponseMessage(), statusCode);
}
}
源码解析
通过这段代码可得出,Glide 框架内部依然通过 HttpURLConnection 连接的网络。
2、Glide 生命周期举例
在正式讲解 Glide生命周期之前,先以大家熟悉的Activity与Fragment之间关系举例。
MainActivity
public class MainActivity extends Activity {
private static final String TAG = "1111--MainActivity";
ImageView iv_image1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG,"MainActivity--onCreate");
setContentView(R.layout.activity_main);
iv_image1 = findViewById(R.id.iv_image1);
FragmentManager fragmentManager = getFragmentManager();
//开启一个事物
FragmentTransaction beginTransaction = fragmentManager.beginTransaction();
beginTransaction.replace(android.R.id.content,new Fragment1());
beginTransaction.commit();
}
@Override
protected void onStart() {
super.onStart();
Log.d(TAG,"MainActivity--onStart");
}
@Override
protected void onRestart() {
super.onRestart();
Log.d(TAG,"MainActivity--onRestart");
}
@Override
protected void onResume() {
super.onResume();
Log.d(TAG,"MainActivity--onResume");
}
@Override
protected void onPause() {
super.onPause();
Log.d(TAG,"MainActivity--onPause");
}
@Override
protected void onStop() {
super.onStop();
Log.d(TAG,"MainActivity--onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG,"MainActivity--onDestroy");
}
}
Fragment
public class Fragment1 extends Fragment {
private static String TAG = "1111--Fragment1";
//他的功能只是给我们进行一个生命周期的监听
public void onAttach(Context context) {
super.onAttach(context);
Log.d(TAG,"Fragment1--onAttach");
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG,"Fragment1--onCreate");
}
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d(TAG,"Fragment1--onCreateView");
View root = inflater.inflate(R.layout.fragment, container, false);
return root;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.d(TAG,"Fragment1--onActivityCreated");
}
@Override
public void onStart() {
super.onStart();
Log.d(TAG,"Fragment1--onStart");
}
@Override
public void onResume() {
super.onResume();
Log.d(TAG,"Fragment1--onResume");
}
@Override
public void onPause() {
super.onPause();
Log.d(TAG,"Fragment1--onPause");
}
@Override
public void onStop() {
super.onStop();
Log.d(TAG,"Fragment1--onStop");
}
@Override
public void onDestroyView() {
super.onDestroyView();
Log.d(TAG,"Fragment1--onDestroyView");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG,"Fragment1--onDestroy");
}
@Override
public void onDetach() {
super.onDetach();
Log.d(TAG,"Fragment1--onDetach");
}
}
这没啥可说的,直接运行看效果。
MainActivity: MainActivity--onCreate
Fragment1: Fragment1--onAttach
Fragment1: Fragment1--onCreate
Fragment1: Fragment1--onCreateView
Fragment1: Fragment1--onActivityCreated
MainActivity: MainActivity--onStart
Fragment1: Fragment1--onStart
MainActivity: MainActivity--onResume
Fragment1: Fragment1--onResume
Fragment1: Fragment1--onPause
MainActivity: MainActivity--onPause
Fragment1: Fragment1--onStop
MainActivity: MainActivity--onStop
Fragment1: Fragment1--onDestroyView
Fragment1: Fragment1--onDestroy
Fragment1: Fragment1--onDetach
MainActivity: MainActivity--onDestroy
这一系列的生命周期,最后再来张图总结下。
3、Glide 生命周期管理
说到生命周期,我们第一时间想到的都是Activity与Fragment之间的关系,现在我们来看看Glide生命周期是什么样的。
Glide.with(this).load(url).into(iv_image1);
这简短的一句话,就完成了整个网络图片加载。我们先进with看看。
@NonNull
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
在进get。
@NonNull
public RequestManager get(@NonNull Activity activity) {
//当前图片加载页面是否在后台运行
if (Util.isOnBackgroundThread()) {
//如果加载的图片对应的页面在后台运行,那么进入该逻辑
return get(activity.getApplicationContext());
} else {
//判断当前显示的activity是否被销毁。
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
return fragmentGet(
activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
这里有个逻辑判断,表示当前加载的图片是否在后台页面展示。现在我们分别以在后台、不在后台两个方向解读源码。
3.1、当前图片加载页面在后台运行
那么直接会调用对应get方法,继续追进看看
@NonNull
public RequestManager get(@NonNull Context context) {
if (context == null) {
throw new IllegalArgumentException("You cannot start a load on a null Context");
} else if (Util.isOnMainThread() && !(context instanceof Application)) {
if (context instanceof FragmentActivity) {
return get((FragmentActivity) context);
} else if (context instanceof Activity) {
return get((Activity) context);
} else if (context instanceof ContextWrapper) {
return get(((ContextWrapper) context).getBaseContext());
}
}
return getApplicationManager(context);
}
源码解读
因为上面传参为:activity.getApplicationContext() ,那么就不可能进入if条件判断,将会直接进 getApplicationManager 方法。进去看看。
@NonNull
private RequestManager getApplicationManager(@NonNull Context context) {
// Either an application context or we're on a background thread.
if (applicationManager == null) {
synchronized (this) {
if (applicationManager == null) {
Glide glide = Glide.get(context.getApplicationContext());
applicationManager =
factory.build(
glide,
new ApplicationLifecycle(),
new EmptyRequestManagerTreeNode(),
context.getApplicationContext());
}
}
}
return applicationManager;
}
源码解析
仔细看源码中用到 ApplicationLifecycle ,也就是说,当我们加载的图片对应的界面在后台运行时,对应的生命周期就和应用生命周期相互绑定。
现在我们就该分析图片加载在前台运行的源码了。
3.2、当前图片加载页面在前台运行
@NonNull
public RequestManager get(@NonNull Activity activity) {
//当前图片加载页面是否在后台运行
if (Util.isOnBackgroundThread()) {
//如果加载的图片对应的页面在后台运行,那么进入该逻辑
return get(activity.getApplicationContext());
} else {
//判断当前显示的activity是否被销毁。
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
return fragmentGet(
activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
源码解析
继续回到这里,刚刚已经分析了if逻辑里面的源码,现在该分析else里面了。首先调用了assertNotDestroyed进行 activity是否销毁的处理。其次核心逻辑在 fragmentGet方法里,进去看看。
@NonNull
private RequestManager fragmentGet(@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
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);
current.setRequestManager(requestManager);
}
return requestManager;
}
源码解析
这里隐隐约约好像看到了 Fragment,通过 getRequestManagerFragment 方法获取的。继续看看 getRequestManagerFragment 方法。
@NonNull
private RequestManagerFragment getRequestManagerFragment(
@NonNull final android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
//如果第一层判断为空,就去缓存里面获取对应的 Fragment
current = pendingRequestManagerFragments.get(fm);
if (current == null) {
//如果缓存里面还为空,那么就创建一个新的 Fragment
current = new RequestManagerFragment();
current.setParentFragmentHint(parentHint);
if (isParentVisible) {
current.getGlideLifecycle().onStart();
}
//向缓存里面添加新创建的 Fragment
pendingRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
源码解析
到这里可以看出,这 getRequestManagerFragment 方法返回的就是 Fragment,并和当前显示的activity相互绑定 ,难道说Glide的生命周期和 Fragment 有关系?带着这样的疑问进入RequestManagerFragment看看。
RequestManagerFragment.class
public class RequestManagerFragment extends Fragment {
private static final String TAG = "RMFragment";
private final ActivityFragmentLifecycle lifecycle;
...略
@VisibleForTesting
@SuppressLint("ValidFragment")
RequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
this.lifecycle = lifecycle;
}
...略
@NonNull
ActivityFragmentLifecycle getGlideLifecycle() {
return lifecycle;
}
...略
@Override
public void onDetach() {
super.onDetach();
unregisterFragmentWithRoot();
}
@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();
}
@Override
public String toString() {
return super.toString() + "{parent=" + getParentFragmentUsingHint() + "}";
}
...略
}
源码解析
到这里,我们大致差不多能明白了,Glide加载的图片在当前显示activity时,将会创建或者获取已创建过对应空页面的Fragment,接着将对应Fragment生命周期里面的 onStart、onStop、onDestroy这三个方法通过 ActivityFragmentLifecycle 与Glide进行生命周期的绑定。也就是说,当Fragment进行这三个生命周期方法时,对应的Glide也会处理对应生命周期的逻辑。
现在我们举例 onDestroy 来验证一下,上面说的是否正确。
@Override
public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();
unregisterFragmentWithRoot();
}
当执行到 onDestroy 方法时,也会执行 lifecycle 的 onDestroy。现在进入 lifecycle 的 onDestroy看看。
所图所示
进入 ActivityFragmentLifecycle 实现类 RequestManager
public class RequestManager implements LifecycleListener,
ModelTypes> {
...略
@Override
public void onStart() {
resumeRequests();
targetTracker.onStart();
}
@Override
public void onStop() {
pauseRequests();
targetTracker.onStop();
}
@Override
public void onDestroy() {
targetTracker.onDestroy();
for (Target> target : targetTracker.getAll()) {
clear(target);
}
targetTracker.clear();
requestTracker.clearRequests();
lifecycle.removeListener(this);
lifecycle.removeListener(connectivityMonitor);
mainHandler.removeCallbacks(addSelfToLifecycle);
glide.unregisterRequestManager(this);
}
...略
}
源码解析
看到这里,能够完全确认了,当activity执行对应的生命周期时,Glide对应的Fragment也会执行相应的生命周期,同时Glide内部的lifecycle 也会执行相应的逻辑处理。
4、Glide 为什么能监听网络判断
在我们使用Glide的切换网络(WIFI/流量相互切换)的时候,Glide依然能够正常的加载网络图片。它在里面做了些什么处理呢?我们带着这样的疑问进去看看。
public class Glide implements ComponentCallbacks2 {
...略
@NonNull
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
...略
}
源码解析
这里with方法返回 RequestManager ,核心逻辑就在这里面,进去看看。
public class RequestManager implements LifecycleListener,
ModelTypes> {
...略
RequestManager(
Glide glide,
Lifecycle lifecycle,
RequestManagerTreeNode treeNode,
RequestTracker requestTracker,
ConnectivityMonitorFactory factory,
Context context) {
this.glide = glide;
this.lifecycle = lifecycle;
this.treeNode = treeNode;
this.requestTracker = requestTracker;
this.context = context;
connectivityMonitor =
factory.build(
context.getApplicationContext(),
new RequestManagerConnectivityListener(requestTracker));
if (Util.isOnBackgroundThread()) {
mainHandler.post(addSelfToLifecycle);
} else {
lifecycle.addListener(this);
}
lifecycle.addListener(connectivityMonitor);
setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());
glide.registerRequestManager(this);
}
...略
private static class RequestManagerConnectivityListener implements ConnectivityMonitor
.ConnectivityListener {
private final RequestTracker requestTracker;
RequestManagerConnectivityListener(@NonNull RequestTracker requestTracker) {
this.requestTracker = requestTracker;
}
@Override
public void onConnectivityChanged(boolean isConnected) {
if (isConnected) {
requestTracker.restartRequests();
}
}
}
}
源码解析
从这段代码可以看出,在构造方法里面注册了RequestManagerConnectivityListener 事件,而这个 RequestManagerConnectivityListener 类实现了 ConnectivityMonitor里面的ConnectivityMonitor 接口。进去看看。
如图所示
进入DefaultConnectivityMonitor 里面看看。
final class DefaultConnectivityMonitor implements ConnectivityMonitor {
...略
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 方法。继续跟进。
@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) {
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Failed to determine connectivity status when connectivity changed", e);
}
return true;
}
return networkInfo != null && networkInfo.isConnected();
}
源码解析
这里已 Context.CONNECTIVITY_SERVICE注册了 网络连接的广播,当有正常网络连接的时候,将会实时获取。我们再回到上一步。
final class DefaultConnectivityMonitor implements ConnectivityMonitor {
...略
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);
}
}
};
...略
}
源码解析
这里的 if (wasConnected != isConnected) 判断,也就是说,当网络发生改变时,就会调用下面onConnectivityChanged 方法。继续追进。
public class RequestManager implements LifecycleListener,
ModelTypes> {
...略
private static class RequestManagerConnectivityListener implements ConnectivityMonitor
.ConnectivityListener {
...略
@Override
public void onConnectivityChanged(boolean isConnected) {
if (isConnected) {
requestTracker.restartRequests();
}
}
}
...略
}
源码解析
这里如果说网络状态为可用,那么将会调用 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);
}
}
}
}
源码解析
这里就会遍历所有网络图片加载情况,先判断单个图片是否加载完成,那就删除对应图片加载,其次判断加载过程中是否暂停,如果暂停那就重新开始,最后就是如果还没开始加载,如果没加载那就添加至队列中。
5、总结
本篇文章,主要讲解了 Glide网络请求、生命周期、以及对应的网络监听处理。
在下一篇中,主要解读 Glide 的 with、load、into 三部曲。
相关推荐
【2021 最新版】Android studio全套教程+Android(安卓)开发入门到精通(项目实战篇)_哔哩哔哩_bilibili
【2021最新版】Kotlin语言教程——Kotlin入门到精通全系列_哔哩哔哩_bilibili
Android流行框架零基础入门到精通全套教程/热修复/Glide/插件化/Retrofit/OKHTTP/Gson/组件化/Jetpack/IOC/高德地图_哔哩哔哩_bilibili
Android开发进阶学习—设计思想解读开源框架 · 已更新至104集(持续更新中~)_哔哩哔哩_bilibili
【实战教学】Android开发—jetpack入门到精通_哔哩哔哩_bilibili
价值100W+Android实战项目大全/高级UI/灵动的锦鲤/QQ空间热修复/插件化框架/组件化框架设计/网络访问框架/RXJava/IOC/MVVM/NDK_哔哩哔哩_bilibili
Android音视频开发:音视频基础知识到直播推流实战系列教程_哔哩哔哩_bilibili
Android项目实战-从0开始手把手实现组件化路由SDK项目实战_哔哩哔哩_bilibili
【Android开发教程】一节课解剖Retrofit源码内核_哔哩哔哩_bilibili
本文转自 https://juejin.cn/post/7016611778767355935,如有侵权,请联系删除。