内容简介:图片的一般是异步的,异步经常面临的问题是内存泄露和异步加载回来view已经销毁导致的空指针问题。而Glide在使用的时候只要求传入当前加载的view或者context,且没有用setLifeCyclelistener什么的方法就实现了生命周期的管理,它是如何做到的呢?我们知道Fragment和View最大区别其实就是多了生命周期,Glide采用的是用创建一个空白Fragment来实现生命周期的管理和监听的。这是如何实现的我们一步步看代码:Glide.java
Motivation/动机
图片的一般是异步的,异步经常面临的问题是内存泄露和异步加载回来view已经销毁导致的空指针问题。而Glide在使用的时候只要求传入当前加载的view或者context,且没有用setLifeCyclelistener什么的方法就实现了生命周期的管理,它是如何做到的呢?
Fragment Trick
我们知道Fragment和View最大区别其实就是多了生命周期,Glide采用的是用创建一个空白Fragment来实现生命周期的管理和监听的。这是如何实现的我们一步步看代码:
Step 1:根据传入的Context得到FragmentManager
Glide.java
@NonNull public static RequestManager with(@NonNull Context context) { return getRetriever(context).get(context); }
获取到正确的Context
com/bumptech/glide/manager/RequestManagerRetriever.java
@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); }
根据Context获取到FragmentManager
@NonNull public RequestManager get(@NonNull FragmentActivity activity) { if (Util.isOnBackgroundThread()) { return get(activity.getApplicationContext()); } else { assertNotDestroyed(activity); FragmentManager fm = activity.getSupportFragmentManager(); return supportFragmentGet(activity, fm, null /*parentHint*/); } }
Step 2:RequestManagerFragment里注册Callback
获取SupportRequestManagerFragment,这个就是监听生命周期的主角Fragment了。下面去看看SupportRequestManagerFragment里有什么吧
@NonNull private RequestManager supportFragmentGet(@NonNull Context context, @NonNull FragmentManager fm, @Nullable Fragment parentHint) { SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint); RequestManager requestManager = current.getRequestManager(); // 省略..部分 return requestManager; }
其实里面就是一个持有ActivityFragmentLifecycle和RequestManager的空白Fragment。
public class SupportRequestManagerFragment extends Fragment { private static final String TAG = "SupportRMFragment"; private final ActivityFragmentLifecycle lifecycle; @Nullable private RequestManager requestManager; // ..省略.. @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里又实现了ActivityFragmentLifecycle从而可以根据什么周期对请求做一些处理
如:在RequestManager里的onDestroy回调里取消所有图片加载请求,销毁监听器
com.bumptech.glide.RequestManager
@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); }
Bouns拓展
空白Fragment还有什么其他妙用呢?
* 动态申请权限。对于不是必要的权限不同意就退出App是非常糟糕的用户体验,最佳实践应该是当要用到该权限的时候再向用户申请。这样写面临的问题就会是授权代码会散落在各个地方,这样显然是很糟糕的。所以用一个空白的Fragment,把权限检查和申请逻辑全部丢到里面,在需要用到地方只要持有这个Fragment做一下检查就好。
如:
public class CameraMicPermissionHelper extends Fragment { private static final int REQUEST_CAMERA_MIC_PERMISSIONS = 10; public static final String TAG = "CamMicPerm"; private CameraMicPermissionCallback mCallback; private static boolean sCameraMicPermissionDenied; public static CameraMicPermissionHelper newInstance() { return new CameraMicPermissionHelper(); } public CameraMicPermissionHelper() { // Required empty public constructor } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); } @Override public void onAttach(Activity activity) { super.onAttach(activity); if (activity instanceof CameraMicPermissionCallback) { mCallback = (CameraMicPermissionCallback) activity; } else { throw new IllegalArgumentException("activity must extend BaseActivity and implement LocationHelper.LocationCallback"); } } @Override public void onDetach() { super.onDetach(); mCallback = null; } public void checkCameraMicPermissions() { if (PermissionUtil.hasSelfPermission(getActivity(), new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO})) { mCallback.onCameraMicPermissionGranted(); } else { // UNCOMMENT TO SUPPORT ANDROID M RUNTIME PERMISSIONS if (!sCameraMicPermissionDenied) { requestPermissions(new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO}, REQUEST_CAMERA_MIC_PERMISSIONS); } } } public void setCameraMicPermissionDenied(boolean cameraMicPermissionDenied) { this.sCameraMicPermissionDenied = cameraMicPermissionDenied; } public static boolean isCameraMicPermissionDenied() { return sCameraMicPermissionDenied; } /** * Callback received when a permissions request has been completed. */ @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == REQUEST_CAMERA_MIC_PERMISSIONS) { if (PermissionUtil.verifyPermissions(grantResults)) { mCallback.onCameraMicPermissionGranted(); } else { Log.i("BaseActivity", "LOCATION permission was NOT granted."); mCallback.onCameraMicPermissionDenied(); } } else { super.onRequestPermissionsResult(requestCode, permissions, grantResults); } } public interface CameraMicPermissionCallback { void onCameraMicPermissionGranted(); void onCameraMicPermissionDenied(); } }
-
不建议的hack手段:
在ViewModel出现之前,有一种很hack的方式用Fragment保存数据。在设备的configurationChange的时候保存大块数据。
关键方法, 把Fragment设置为true后可以在configurationChange的时候不被销毁,利用这一点保存数据。现在用ViewModel显然是更好的方法
/* Control whether a fragment instance is retained across Activity re-creation (such as from a configuration change).*/ setRetainInstance(boolean retain)
- 声明周期的监听,现在用Android Jetpack里的 Lifecycle-Aware Components来做是一个更简单的做法。
参考
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- WWDC19 看点
- Glide看点(三) 内存管理
- 腾讯看点视频推荐索引构建方案
- WWDC2017看点分析:那些内容值得期待?
- Glide源码看点-图片pre scale
- 2017年IaaS云计算市场10大看点
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Cascading Style Sheets 2.0 Programmer's Reference
Eric A. Meyer / McGraw-Hill Osborne Media / 2001-03-20 / USD 19.99
The most authoritative quick reference available for CSS programmers. This handy resource gives you programming essentials at your fingertips, including all the new tags and features in CSS 2.0. You'l......一起来看看 《Cascading Style Sheets 2.0 Programmer's Reference》 这本书的介绍吧!