分析源码前我自己想了几个问题,带着目的去看。

  1. Activity 是如何与 Fragment 关联,如何操作 fragment 的?
  2. 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 实例。

HostCallbacksFragmentActivity 的内部类,是 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 调用的是第二个构造,将 mActivitymContext 赋值为 Activity 的实例,mHandler 赋值为 Activity 中的 mHandlermWindowAnimations 直接赋值 0。

这里的 mHandler 也是在 Activty 被实例化的时候实例化,看代码是处理 Fragmentstopresume 状态的。具体怎么处理的后面再看,这里先了解传入的 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 被实例化的时候,FragmentControllerHostCallbacksFragmentManagerImpl 都会被实例化。然后再通过我们前面说到的 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 个问题。

  1. Activity 是如何与 Fragment 关联,如何操作 fragment 的?

Activiy 通过 FragmentManager 得到事务的实现类 BackStackRecord,它将 Fragment 封装成一个 Ops,提交给 FragmentManager 处理。如果是异步提交,就通过 Handler 发送 Runnable 任务,FragmentManager 拿到任务后,先处理 Ops 状态,然后调用 moveToState() 方法根据状态调用 Fragment 对应的生命周期方法,从而达到 Fragment 的添加、布局的替换隐藏等。

  1. Fragment 的本质是一个 View 吗?

本质上是一个对 View 的封装,它持有 view, containerView, fragmentManager, childFragmentManager 等信息。

参考

通过源码解析 Fragment 启动过程

Fragment FragmentManager FragmentTransaction 深入理解

Fragment 源码解析相关推荐

  1. Android之EasyPermissions源码解析

    转载请标明出处:[顾林海的博客] 个人开发的微信小程序,目前功能是书籍推荐,后续会完善一些新功能,希望大家多多支持! 前言 我们知道在Android中想要申请权限就需要在AndroidManifest ...

  2. 路由框架ARouter最全源码解析

    ARouter是2017年阿里巴巴开源的一款Android路由框架,官方定义: ARouter是Android平台中对页面,服务提供路由功能的中间件,提倡简单且够用 有下面几个优势: 1.直接解析UR ...

  3. Android Lifecycle源码解析(一)

    Android Lifecycle源码解析(一) 首先我们看HomeActivity中我们添加到一行代码 public class HomeActivity extends AppCompatActi ...

  4. Android Glide图片加载框架(二)源码解析之with()

    文章目录 一.前言 二.如何阅读源码 三.源码解析 1.with() Android Glide图片加载框架系列文章 Android Glide图片加载框架(一)基本用法 Android Glide图 ...

  5. RxPermissions 源码解析之举一反三

    [toc] RxPermissions 源码解析 简介 RxPermissions 是基于 RxJava 开发的用于帮助 在Android 6.0 中处理运行时权限检测的框架.在 Android 6. ...

  6. Andromeda 源码解析 (同步获取服务)

    Andromeda Andromeda是爱奇艺开源的适用于多进程架构的组件通信框架. github地址: https://github.com/iqiyi/Andromeda 其特点如下: 无需开发者 ...

  7. Glide 源码解析之监听生命周期

    code小生 一个专注大前端领域的技术平台公众号回复Android加入安卓技术群 作者:断了谁的弦 链接:https://www.jianshu.com/p/1169a91342a9 声明:本文已获断 ...

  8. LiveData 源码解析(2.4.1 版本)

    文章目录 1.LiveData 简介 2.LiveData 配置与基本用法 2.1 依赖引入与配置 2.2 基本用法 2.2.1 LiveData 简单使用 2.2.2 LiveData 扩展 2.2 ...

  9. ARouter 源码解析(零) 基本使用

    ARouter 源码解析(零) 基本使用 零.要解决的问题 在app的开发中,页面之间的相互跳转是最基本常用的功能.在Android中的跳转一般通过显式intent和隐式intent两种方式实现的,而 ...

最新文章

  1. RGB与16进制颜色转换的原理
  2. irsend 树莓派 php,用树莓派给家用电器加上智能(红外篇)
  3. qt opencv cmake配置 单纯小白
  4. Python快速学习03:运算 缩进和选择
  5. 前端学习(619):变量的小案例二
  6. Git 的安装、使用、分支、命令 一篇博客全都学会
  7. python字符串匹配的准确率_说说在 Python 中,如何找出所有字符串匹配
  8. OpenResty中使用反向代理
  9. linux数据库实例开机启动,Oracle数据库之Linux下实现Oracle数据库单实例开机自启动设置...
  10. iPhone开发之第三方回调函数的使用方法
  11. 红外传感器的基础知识
  12. 移远BC95 NB-IoT模块串口发送数据到服务器
  13. Python-继人物词频统计三国演义之后-三国词云(Wordcloud)
  14. windows 2008 r2 kb4512486 安装失败解决方法
  15. 刺客信条奥德赛ce修改技能点_刺客信条奥德赛特长加点
  16. java多态工作机制_Java多态
  17. 常用crc查表法_请教查表法计算CRC的原理
  18. 用vs2022实现c++简单游戏2-别碰方块
  19. YY语音无有效验证导致下载执行任意程序
  20. 物联网卡的分类有哪些

热门文章

  1. select 语句的执行顺序
  2. Spark的RDD序列化
  3. Local模式下Spark程序只输出关键信息
  4. Codeforces Round #276 (Div. 2)
  5. 校园资源建设平台源代码
  6. 关于Block Formatting Context--BFC和IE的hasLayout
  7. 标准浏览器的选择器封装
  8. TreeView控件结合js树形选择 .
  9. 数据结构2:中序线索化二叉树为什么要通过pre设置后继结点
  10. OpenCv 金字塔之上采样与下采样