Fragment 源码解析
- Activity 是如何与 Fragment 关联,如何操作 fragment 的?
- Fragment 的本质是一个 View 吗?
前言
Activity 和 Fragment 密不可分, 分析 Fragment 必须去从 Activity 的生命周期着手去分析其中和 Fragment 的关联。
我们在 Activity 操作 Fragment 通过如下代码:
getSupportFragmentManager().beginTransaction().add(R.id.container, new MyFragment()).commit();
复制代码
查看源码可以发现 getSupportFragmentManager()
内部通过 FragmentController
操作。
这个 FragmentController
类是负责控制 Fragment 的。
它的内部持有一个 FragmentHostCallback
,所有的核心操作都间接交给了这个类,这个 FragmentHostCallback
类才是重点。而且它的命名是 mHost
,它才是最主要的操作者。FragmentController
只是个中间对象。
// Fragment 可以寄生在任何对象上,让 fragment 寄存在自己身上需要实现 FragmentHostCallback 类,实现里面的一些方法 。
public abstract class FragmentHostCallback<E> extends FragmentContainer
复制代码
Activity 通过 FragmentController
类管理 Fragment。FragmentController
的实例在成员变量中实例化,所以当 Activity
被实例化的时候,FragmentController
就被实例化了。
public class FragmentActivity {final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
// ...
}
复制代码
那么 Activity
在哪里被实例化的?
Activit 的实例化
实例 Activity 的过程发生在 ActivityThread
中的 performLaunchActivity()
中的这段代码。
// 通过 Instrumentation 的 newActivity 方法使用类加载器创建 Activity 对象
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
activity.attach();
/**-------------------------------------------------------*/
// newActivity() 方法内部调用了 Activity 的无参实例:Activity activity = (Activity)clazz.newInstance();复制代码
在 Activity 实例化之后会立刻调用 Activity#attach(),这个方法内部会调用mFragments.attachHost(null /*parent*/);
public void attachHost(Fragment parent) {mHost.mFragmentManager.attachController(mHost, mHost /*container*/, parent);
}
复制代码
// 第一个参数是宿主;
// 第二参数是容器,FragmentHostCallback 继承于 FragmentContainer 也代表容器;
// 第三个参数是父类 Fragment
public void attachController(FragmentHostCallback host,FragmentContainer container, Fragment parent) {// 宿主只能有一个if (mHost != null) throw new IllegalStateException("Already attached");mHost = host;mContainer = container;mParent = parent;
}
复制代码
这个方法最终将宿主对象和控制器中的 FragmentManager 关联,内部就是进行赋值。
为什么里面传的是 null?注释写了 parent。应该是传入的父类 fragment,而由 Activity 创建的 fragment 没有父类,所以是 null。
FragmentController 的初始化
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
复制代码
public static final FragmentController createController(FragmentHostCallback<?> callbacks) {return new FragmentController(callbacks);
}
复制代码
createController()
方法中传入了一个 HostCallbacks
实例。
HostCallbacks
是 FragmentActivity
的内部类,是 FragmentHostCallback
的实现类。
HostCallbacks 的初始化
在构造函数中调用父类的构造函数,将当前的 Activity
实例传进去:
public HostCallbacks() {super(FragmentActivity.this /*fragmentActivity*/);
}
复制代码
父类 FragmentHostCallback
有 3 个构造方法:
public FragmentHostCallback(Context context, Handler handler, int windowAnimations) {this(context instanceof Activity ? (Activity) context : null, context, handler, windowAnimations);
}FragmentHostCallback(FragmentActivity activity) {this(activity, activity /*context*/, activity.mHandler, 0 /*windowAnimations*/);
}FragmentHostCallback(Activity activity, Context context, Handler handler,int windowAnimations) {mActivity = activity;mContext = context;mHandler = handler;mWindowAnimations = windowAnimations;
}
复制代码
HostCallbacks
调用的是第二个构造,将 mActivity
、mContext
赋值为 Activity
的实例,mHandler
赋值为 Activity
中的 mHandler
,mWindowAnimations
直接赋值 0。
这里的 mHandler
也是在 Activty
被实例化的时候实例化,看代码是处理 Fragment
的 stop
和 resume
状态的。具体怎么处理的后面再看,这里先了解传入的 mHandler 在哪里初始化的。
final Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MSG_REALLY_STOPPED:if (mStopped) {doReallyStop(false);}break;case MSG_RESUME_PENDING:onResumeFragments();mFragments.execPendingActions();break;default:super.handleMessage(msg);}}
};
复制代码
FragmentHostCallback 的成员变量
// Actvity
private final Activity mActivity;// 上下文
final Context mContext;// 在 Activity 中实例化的 handler,负责处理 fragment 的生命周期,内部执行具体的事务
private final Handler mHandler;// window 的动画
final int mWindowAnimations;// 在成员变量中直接实例化了 FragmentManagerImpl
final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();// loaderManager 的集合, loadMangaer 通过 Fragment#getLoaderManager() 获取,最终是由 FragmentHostCallback#getLoaderManager() 获取。
/** The loader managers for individual fragments [i.e. Fragment#getLoaderManager()] */
private SimpleArrayMap<String, LoaderManager> mAllLoaderManagers;// 标记 fragmentLoader 是否应该保存 fragment 的状态
/** Whether or not fragment loaders should retain their state */
private boolean mRetainLoaders;// fragment 宿主的 loaderManager,通过 Activity#getLoaderManager() 获取, 最终是由 FragmentHostCallback#getLoaderManagerImpl() 获取。
/** The loader manger for the fragment host [i.e. Activity#getLoaderManager()] */
private LoaderManagerImpl mLoaderManager;// 检查 loaderManager 是否为空
private boolean mCheckedForLoaderManager;// 宿主的 loaderManager 是否开始加载
/** Whether or not the fragment host loader manager was started */
private boolean mLoadersStarted;复制代码
根据注释和局部代码初步了解一下这些变量的含义,有个大概的印象。可以看到内部有一个 loader manager 的存在。宿主有一个单独的加载器,以 "(root)"
为键存入了 SimpleArrayMap<String, LoaderManager>
集合中。 每个 fragment
也对应有一个自己的 loader manager。 这个 load manager 是干啥的,现在还不知道,后面再看。
FragmentManagerImpl 的初始化
FragmentManager、FragmentManagerState、FragmentManagerImpl 三个类共存于 FragmentManager.java 文件下,它们是同级的关系,而不是内部类的关系。
我们平常操作 fragment
所调用的 getSupportFragmentManager()
返回的就是 FragmentManager
对象。顾名思义,它是 fragment 的管理者,负责添加、删除、替换 fragment 等一些操作。
FragmentManager 是一个抽象类,定义了操作 fragment 的一系列方法,如开启事务、进栈、弹栈等。除此之外,有一个 BackStackEntry
接口和一个 FragmentLifecycleCallbacks
生命周期回调。
public abstract class FragmentManager {public abstract FragmentTransaction beginTransaction();public abstract boolean executePendingTransactions();public abstract Fragment findFragmentById(@IdRes int id);public abstract Fragment findFragmentByTag(String tag);public abstract void popBackStack();public abstract boolean popBackStackImmediate();// .....// 当调用 FragmentTransaction#addToBackStack(String) 时,将放入回退栈的 frament 的信息存起来。用于以后检索。public interface BackStackEntry {public int getId();public String getName();@StringRes public int getBreadCrumbTitleRes();@StringRes public int getBreadCrumbShortTitleRes();public CharSequence getBreadCrumbTitle();public CharSequence getBreadCrumbShortTitle();}// 回退栈内容改变时的监听接口public interface OnBackStackChangedListener {public void onBackStackChanged();}// frgment 的生命周期回调public abstract static class FragmentLifecycleCallbacks {public void onFragmentPreAttached(FragmentManager fm, Fragment f, Context context) {}public void onFragmentAttached(FragmentManager fm, Fragment f, Context context) {}public void onFragmentCreated(FragmentManager fm, Fragment f, Bundle savedInstanceState) {}public void onFragmentActivityCreated(FragmentManager fm, Fragment f,Bundle savedInstanceState) {}public void onFragmentViewCreated(FragmentManager fm, Fragment f, View v,Bundle savedInstanceState) {}// ...}}
复制代码
FragmentManager
的具体实现是 FragmentManagerImpl
具体内部的实现,现在先不深入看了。现在先把主要的流程走通,后面再看具体的细节。
final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
复制代码
FragmentMangerImpl 在 FragmentHostCallback() 的成员变量中被实例化。所以 Activity 被实例化的时候,FragmentController
、HostCallbacks
、FragmentManagerImpl
都会被实例化。然后再通过我们前面说到的 attach()
将他们关联,让 FragmentManagerImpl
实例持有 HostCallbacks
实例。
Activity 的 onCreate()
Activity 的生命周期从 onCreate 开始, 在 Activity 实例化后,FragmentManager 就可以被使用来操作 fragment,即我们常用的 getFragmentManager().beginTransaction().add()
等操作。 这些操作都是在 Activity 的 onCreate
完成的。
Activity 的 onCreate()
发生在哪里?
onCreate()
也发生在 ActivityThread 中的 performLaunchActivity()
中:
mInstrumentation.callActivityOnCreate(activity, r.state);
复制代码
// Instrumentation
public void callActivityOnCreate(Activity activity, Bundle icicle) {prePerformCreate(activity);activity.performCreate(icicle);postPerformCreate(activity);
}
复制代码
// Activityfinal void performCreate(Bundle icicle) {restoreHasCurrentPermissionRequest(icicle);onCreate(icicle);mActivityTransitionState.readState(icicle);performCreateCommon();}
复制代码
protected void onCreate(@Nullable Bundle savedInstanceState) {// ...mFragments.dispatchCreate();
}复制代码
final void performCreateCommon() {// ...mFragments.dispatchActivityCreated();// ...
}
复制代码
最终在 Activity 的 onCreate
调用了 FragmentController#dispatchCreate()
,接着在 performCreateCommon()
中调用了 FragmentController#dispatchActivityCreated()
:
public void dispatchCreate() {mHost.mFragmentManager.dispatchCreate();
}
public void dispatchActivityCreated() {mHost.mFragmentManager.dispatchActivityCreated();
}
复制代码
这两个方法都是调用的 HostCallback
实例中的 FragmentManagerImpl
实例的方法。
public void dispatchCreate() {mStateSaved = false;mExecutingActions = true;moveToState(Fragment.CREATED, false);mExecutingActions = false;
}public void dispatchActivityCreated() {mStateSaved = false;mExecutingActions = true;moveToState(Fragment.ACTIVITY_CREATED, false);mExecutingActions = false;
}
复制代码
看到这里结合源码注释我们知道这俩方法通过 moveToState()
去更新 Fragment 的 状态。并且用 mExecutingActions
标记事务是否在进行。 用 mStateSaved
标记状态是否保存了。
void moveToState(int newState, boolean always) {// 状态没变且没有设置必须更新就结束if (!always && newState == mCurState) {return;}// 更新当前状态mCurState = newState;// ...}
复制代码
这个方法有 2 个参数,第一个参数是即将更新的状态,第二个参数表示是否更新所有 fragment 的状态。
static final int INITIALIZING = 0; // Not yet created.
static final int CREATED = 1; // Created.
static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.
static final int STOPPED = 3; // Fully created, not started.
static final int STARTED = 4; // Created and started, not resumed.
static final int RESUMED = 5; // Created started and resumed.int mState = INITIALIZING;
复制代码
Fragment 的状态有上面几种。默认是 INITIALIZING。
这里我有个地方有点疑惑:Activity onCreate() 的时候给 FragmentManager 通知更新 CREATED
状态,此时应该还没有创建任何 fragment,为啥是个 CREATED
。看到后面又有个 STOPPED
,表示创建完成,还没开始的状态。那么 CREATED
应该表示的是开始创建,还没创建好。
事务操作
接着我们会在 Activity
中的 onCreate()
创建执行 fragment 的事务。 getFragmentManager()
前面已经看过,现在来看 beginTransaction()
。
// FragmentManagerImpl
public FragmentTransaction beginTransaction() {return new BackStackRecord(this);
}
复制代码
// BackStackState
final class BackStackRecord extends FragmentTransaction implementsFragmentManager.BackStackEntry, FragmentManagerImpl.OpGenerator {static final String TAG = FragmentManagerImpl.TAG;static final boolean SUPPORTS_TRANSITIONS = Build.VERSION.SDK_INT >= 21;final FragmentManagerImpl mManager;// 表示一系列操作static final int OP_NULL = 0;static final int OP_ADD = 1;static final int OP_REPLACE = 2;static final int OP_REMOVE = 3;static final int OP_HIDE = 4;static final int OP_SHOW = 5;static final int OP_DETACH = 6;static final int OP_ATTACH = 7;static final int OP_SET_PRIMARY_NAV = 8;static final int OP_UNSET_PRIMARY_NAV = 9;// 双链表的节点static final class Op {// 执行的操作(添加/删除。。。)int cmd;Fragment fragment;// 进栈动画int enterAnim;int exitAnim;// 出栈动画int popEnterAnim;int popExitAnim;Op() {}Op(int cmd, Fragment fragment) {this.cmd = cmd;this.fragment = fragment;}}// ...
}
复制代码
BackStackRecord 继承 FragmentTransation 抽象类,同时实现 BackStackEntry 和 OpGenerator 接口。我们在程序里要进行 add,remove,replace 等等操作时,用的是 FragmentTransation 类型,其实这个实例是 BackStackRecord 对象。
BackStackRecord 是用于保存用户一次提交的操作行为,一次提交并不是一种变化,而是一系列的变化,是一组 add、replace、remove 变化的集合。每一次的变化,即是一次操作,用 Op 类来表示。在 BackStackRecord 里保存了一个双向链表 (mHead, mTail),用于保存一组操作。Op 类中的 cmd 表示操作类型(如 add,replace,remove 等等)
例如:
getSupportFragmentManager().beginTransaction().add(R.id.container, new MyFragment()).hide(R.id.container,fragment2).replace(R.id.container,fragment3).commit();
复制代码
最终通过 commit()
方法提交一些列操作。
BackStackRecord
BackStackRecord 实现了操作 fragment 的所有事务,每个方法内部都是由 doAddOp
实现的。
@Overridepublic FragmentTransaction add(int containerViewId, Fragment fragment) {doAddOp(containerViewId, fragment, null, OP_ADD);return this;}public FragmentTransaction replace(int containerViewId, Fragment fragment, String tag) {if (containerViewId == 0) {throw new IllegalArgumentException("Must use non-zero containerViewId");}doAddOp(containerViewId, fragment, tag, OP_REPLACE);return this;}@Overridepublic FragmentTransaction remove(Fragment fragment) {addOp(new Op(OP_REMOVE, fragment));return this;}@Overridepublic FragmentTransaction hide(Fragment fragment) {addOp(new Op(OP_HIDE, fragment));return this;}@Overridepublic FragmentTransaction show(Fragment fragment) {addOp(new Op(OP_SHOW, fragment));return this;}@Overridepublic FragmentTransaction detach(Fragment fragment) {addOp(new Op(OP_DETACH, fragment));return this;}@Overridepublic FragmentTransaction attach(Fragment fragment) {addOp(new Op(OP_ATTACH, fragment));return this;}复制代码
private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {// ...// 将 manager 赋值给 fragmentfragment.mFragmentManager = mManager;// 设置 containerViewIdif (containerViewId != 0) {fragment.mContainerId = fragment.mFragmentId = containerViewId;}// ...// 将这个事务对象加到 ArrayList 中addOp(new Op(opcmd, fragment));}复制代码
提交事务
常用的提交事务, 一种是将所有事物放入事务队列,轮询执行。另一种是立刻执行,从方法命名也可以看出来。看看它们内部是如何提交的。而立刻提交是不允许加入回退栈的。
@Overridepublic int commit() {return commitInternal(false);}int commitInternal(boolean allowStateLoss) {mCommitted = true;// 判断是否加入回退栈if (mAddToBackStack) {mIndex = mManager.allocBackStackIndex(this);} else {mIndex = -1;}// 将事务添加到轮询队列等待执行mManager.enqueueAction(this, allowStateLoss);return mIndex;}public void enqueueAction(OpGenerator action, boolean allowStateLoss) {// 检查状态if (!allowStateLoss) {checkStateLoss();}synchronized (this) {if (mDestroyed || mHost == null) {throw new IllegalStateException("Activity has been destroyed");}if (mPendingActions == null) {mPendingActions = new ArrayList<>();}mPendingActions.add(action);scheduleCommit();}}// 将事务交通过 handler post 执行private void scheduleCommit() {synchronized (this) {boolean postponeReady =mPostponedTransactions != null && !mPostponedTransactions.isEmpty();boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1;if (postponeReady || pendingReady) {mHost.getHandler().removeCallbacks(mExecCommit);mHost.getHandler().post(mExecCommit);}}}// mExecCommit 这个 Runnable 做的事:
public boolean execPendingActions() {ensureExecReady(true);boolean didSomething = false;while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {mExecutingActions = true;try {// 优化执行我们的实务操作,具体的执行就在这个方法里optimizeAndExecuteOps(mTmpRecords, mTmpIsPop);} finally {cleanupExec();}didSomething = true;}doPendingDeferredStart();return didSomething;}
复制代码
// 这里进行了优化和执行事务的操作,执行事务是由 executeOpsTogether 完成private void optimizeAndExecuteOps(ArrayList<BackStackRecord> records,ArrayList<Boolean> isRecordPop) {// ... final int numRecords = records.size();int startIndex = 0;// 遍历所有的事务for (int recordNum = 0; recordNum < numRecords; recordNum++) {// 标记优化final boolean canOptimize = records.get(recordNum).mAllowOptimization;if (!canOptimize) {// ..if (startIndex != recordNum) {executeOpsTogether(records, isRecordPop, startIndex, recordNum);}executeOpsTogether(records, isRecordPop, recordNum, optimizeEnd);// ...}}if (startIndex != numRecords) {executeOpsTogether(records, isRecordPop, startIndex, numRecords);}}// 这里发现执行事务由 executeOps 方法来执行的private void executeOpsTogether(ArrayList<BackStackRecord> records,ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {final boolean allowOptimization = records.get(startIndex).mAllowOptimization;// ... // ...executeOps(records, isRecordPop, startIndex, endIndex);// ...if (postponeIndex != startIndex && allowOptimization) {// need to run something nowFragmentTransition.startTransitions(this, records, isRecordPop, startIndex,postponeIndex, true);moveToState(mCurState, true);}// ..if (addToBackStack) {reportBackStackChanged();}}复制代码
// 最终判断执行 executeOps 还是 executePopOpsprivate static void executeOps(ArrayList<BackStackRecord> records,ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {for (int i = startIndex; i < endIndex; i++) {final BackStackRecord record = records.get(i);final boolean isPop = isRecordPop.get(i);if (isPop) {record.bumpBackStackNesting(-1);// Only execute the add operations at the end of// all transactions.boolean moveToState = i == (endIndex - 1);record.executePopOps(moveToState);} else {record.bumpBackStackNesting(1);record.executeOps();}}}
复制代码
这里通过 fragmentManager 来操作
void executeOps() {final int numOps = mOps.size();for (int opNum = 0; opNum < numOps; opNum++) {final Op op = mOps.get(opNum);final Fragment f = op.fragment;if (f != null) {f.setNextTransition(mTransition, mTransitionStyle);}switch (op.cmd) {case OP_ADD:f.setNextAnim(op.enterAnim);mManager.addFragment(f, false);break;case OP_REMOVE:f.setNextAnim(op.exitAnim);mManager.removeFragment(f);break;case OP_HIDE:f.setNextAnim(op.exitAnim);mManager.hideFragment(f);break;// ...}}// ...}
复制代码
最后调用 movetToState()
public void addFragment(Fragment fragment, boolean moveToStateNow) {if (mAdded == null) {mAdded = new ArrayList<Fragment>();}makeActive(fragment);if (!fragment.mDetached) {// ...mAdded.add(fragment);fragment.mAdded = true;fragment.mRemoving = false;if (fragment.mView == null) {fragment.mHiddenChanged = false;}if (fragment.mHasMenu && fragment.mMenuVisible) {mNeedMenuInvalidate = true;}if (moveToStateNow) {moveToState(fragment);}}}
复制代码
这一段的代码特别长,根据状态调用对应的生命周期, 在添加的时候把 View 添加进父布局。通过 View.GONE/VISIBLE
显示隐藏 Fragment。
void moveToState(Fragment f, int newState, int transit, int transitionStyle,boolean keepActive) {if (f.mState <= newState) {// ...switch (f.mState) {case Fragment.INITIALIZING:// OnFragmentPreAttacheddispatchOnFragmentPreAttached(f, mHost.getContext(), false);// 调用 fragment 的 onAttachf.onAttach(mHost.getContext());// 回调宿主的 onAttachFragmentmHost.onAttachFragment(f);dispatchOnFragmentAttached(f, mHost.getContext(), false);// 执行 fragment 的 onCreatef.performCreate(f.mSavedFragmentState);dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);// ...case Fragment.CREATED:f.mContainer = container;// fragmenr 执行 onCreateView 创建 Viewf.mView = f.performCreateView(f.getLayoutInflater(f.mSavedFragmentState), container, f.mSavedFragmentState);if (container != null) {// 加入父布局container.addView(f.mView);}// 设置 View 的 GONE VISIBLE 来控制 hide,showif (f.mHidden) {f.mView.setVisibility(View.GONE);}// onViewCreatedf.onViewCreated(f.mView, f.mSavedFragmentState);// 回调dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState,false);// onActivityCreated f.performActivityCreated(f.mSavedFragmentState);// ...case Fragment.ACTIVITY_CREATED://...case Fragment.STOPPED:// ..// onStartf.performStart();dispatchOnFragmentStarted(f, false);case Fragment.STARTED:// ...// onResumef.performResume();dispatchOnFragmentResumed(f, false);}} else if (f.mState > newState) {switch (f.mState) {case Fragment.RESUMED:// onPausef.performPause();dispatchOnFragmentPaused(f, false);// ..case Fragment.STARTED:// onStopf.performStop();dispatchOnFragmentStopped(f, false);// ...case Fragment.STOPPED:f.performReallyStop();// ... case Fragment.ACTIVITY_CREATED:// ..// onDestroyViewf.performDestroyView();dispatchOnFragmentViewDestroyed(f, false);case Fragment.CREATED:// onDestoryf.performDestroy();// onDetachf.performDetach();// ...}}}复制代码
总结
回到最初疑惑的 2 个问题。
- Activity 是如何与 Fragment 关联,如何操作 fragment 的?
Activiy 通过 FragmentManager 得到事务的实现类 BackStackRecord,它将 Fragment 封装成一个 Ops,提交给 FragmentManager 处理。如果是异步提交,就通过 Handler 发送 Runnable 任务,FragmentManager 拿到任务后,先处理 Ops 状态,然后调用 moveToState() 方法根据状态调用 Fragment 对应的生命周期方法,从而达到 Fragment 的添加、布局的替换隐藏等。
- Fragment 的本质是一个 View 吗?
本质上是一个对 View 的封装,它持有 view, containerView, fragmentManager, childFragmentManager 等信息。
参考
通过源码解析 Fragment 启动过程
Fragment FragmentManager FragmentTransaction 深入理解
Fragment 源码解析相关推荐
- Android之EasyPermissions源码解析
转载请标明出处:[顾林海的博客] 个人开发的微信小程序,目前功能是书籍推荐,后续会完善一些新功能,希望大家多多支持! 前言 我们知道在Android中想要申请权限就需要在AndroidManifest ...
- 路由框架ARouter最全源码解析
ARouter是2017年阿里巴巴开源的一款Android路由框架,官方定义: ARouter是Android平台中对页面,服务提供路由功能的中间件,提倡简单且够用 有下面几个优势: 1.直接解析UR ...
- Android Lifecycle源码解析(一)
Android Lifecycle源码解析(一) 首先我们看HomeActivity中我们添加到一行代码 public class HomeActivity extends AppCompatActi ...
- Android Glide图片加载框架(二)源码解析之with()
文章目录 一.前言 二.如何阅读源码 三.源码解析 1.with() Android Glide图片加载框架系列文章 Android Glide图片加载框架(一)基本用法 Android Glide图 ...
- RxPermissions 源码解析之举一反三
[toc] RxPermissions 源码解析 简介 RxPermissions 是基于 RxJava 开发的用于帮助 在Android 6.0 中处理运行时权限检测的框架.在 Android 6. ...
- Andromeda 源码解析 (同步获取服务)
Andromeda Andromeda是爱奇艺开源的适用于多进程架构的组件通信框架. github地址: https://github.com/iqiyi/Andromeda 其特点如下: 无需开发者 ...
- Glide 源码解析之监听生命周期
code小生 一个专注大前端领域的技术平台公众号回复Android加入安卓技术群 作者:断了谁的弦 链接:https://www.jianshu.com/p/1169a91342a9 声明:本文已获断 ...
- LiveData 源码解析(2.4.1 版本)
文章目录 1.LiveData 简介 2.LiveData 配置与基本用法 2.1 依赖引入与配置 2.2 基本用法 2.2.1 LiveData 简单使用 2.2.2 LiveData 扩展 2.2 ...
- ARouter 源码解析(零) 基本使用
ARouter 源码解析(零) 基本使用 零.要解决的问题 在app的开发中,页面之间的相互跳转是最基本常用的功能.在Android中的跳转一般通过显式intent和隐式intent两种方式实现的,而 ...
最新文章
- RGB与16进制颜色转换的原理
- irsend 树莓派 php,用树莓派给家用电器加上智能(红外篇)
- qt opencv cmake配置 单纯小白
- Python快速学习03:运算 缩进和选择
- 前端学习(619):变量的小案例二
- Git 的安装、使用、分支、命令 一篇博客全都学会
- python字符串匹配的准确率_说说在 Python 中,如何找出所有字符串匹配
- OpenResty中使用反向代理
- linux数据库实例开机启动,Oracle数据库之Linux下实现Oracle数据库单实例开机自启动设置...
- iPhone开发之第三方回调函数的使用方法
- 红外传感器的基础知识
- 移远BC95 NB-IoT模块串口发送数据到服务器
- Python-继人物词频统计三国演义之后-三国词云(Wordcloud)
- windows 2008 r2 kb4512486 安装失败解决方法
- 刺客信条奥德赛ce修改技能点_刺客信条奥德赛特长加点
- java多态工作机制_Java多态
- 常用crc查表法_请教查表法计算CRC的原理
- 用vs2022实现c++简单游戏2-别碰方块
- YY语音无有效验证导致下载执行任意程序
- 物联网卡的分类有哪些