Android 架构之Glide源码解读(上)

前言

我们在编写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 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,如有侵权,请联系删除。

你可能感兴趣的:(Android 架构之Glide源码解读(上))