Glide源码学习-生命周期

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启动时:
Glide源码学习-生命周期
onAttcah:和activity关联之后调用

当activity关闭时时:先走fragment生命周期,再走activity的生命周期
Glide源码学习-生命周期
具体关联流程:
Glide源码学习-生命周期

经过测试,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);这段代码不能在子线程执行,因为通过源码发现,如果运行不在主线程,直接抛异常,如下:
Glide源码学习-生命周期

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源码学习-生命周期
在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;
}

总结

上一篇:轻松学安卓web开发!轻松获得一线大厂面试offer,大牛最佳总结


下一篇:inux设备驱动归纳总结(五):2.操作硬件——IO内存【转】