首页 > 其他分享 >Android Framework之Activity启动流程

Android Framework之Activity启动流程

时间:2024-07-10 09:30:11浏览次数:4  
标签:-- app Activity ActivityThread Framework activity Android 方法

原文地址 https://juejin.cn/post/7212432799848579133

启动Activty触发点为Activity中的startActivity。

Activity startActivity ->

Instrumentation --> execStartActivity

 
try {
    intent.migrateExtraStreamToClipData(who);
    intent.prepareToLeaveProcess(who);
    //
    int result = android.app.ActivityTaskManager.getService().startActivity(whoThread,
            who.getBasePackageName(), who.getAttributionTag(), intent,
            intent.resolveTypeIfNeeded(who.getContentResolver()), token,
            target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
    checkStartActivityResult(result, intent);
} catch (RemoteException e) {
    throw new RuntimeException("Failure from system", e);
}
 
/** @hide */
public static IActivityTaskManager getService() {
    //通过aidl接口获取ActivityTaskManagerService操作对象
    return IActivityTaskManagerSingleton.get();
}

通过aidl接口得到ActivityTaskManagerService的对象(简称ATMS),activity启动原来是ams管理的,在android10之后增加了ATMS,将原来AMS中的部分代码移动了此类中。

image.png

Instrumentation中调用了execStartActivity之后,最终调用了ATMS中的startActivityAsUser()方法。

 
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
        String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
        String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
        Bundle bOptions) {
    return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
            resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions,
            UserHandle.getCallingUserId());
}
 
private int startActivityAsUser(IApplicationThread caller, String callingPackage,
        @Nullable String callingFeatureId, Intent intent, String resolvedType,
        IBinder resultTo, String resultWho, int requestCode, int startFlags,
        ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
    assertPackageMatchesCallingUid(callingPackage);
    enforceNotIsolatedCaller("startActivityAsUser");

    userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
            Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");

    // TODO: Switch to user app stacks here.
    //通过ActivityStartController最终调用到了ActivityStarter中的execute方法。
    return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
            .setCaller(caller)
            .setCallingPackage(callingPackage)
            .setCallingFeatureId(callingFeatureId)
            .setResolvedType(resolvedType)
            .setResultTo(resultTo)
            .setResultWho(resultWho)
            .setRequestCode(requestCode)
            .setStartFlags(startFlags)
            .setProfilerInfo(profilerInfo)
            .setActivityOptions(bOptions)
            .setUserId(userId)
            .execute();
}

通过ActivityStartController最终调用到了ActivityStarter中的execute方法。

execute方法方法调用:startActivityInner---> deliverToCurrentTopIfNeeded

RootWindowContainer-->resumeFocusedStacksTopActivities

ActivityStack-->resumeTopActivityUncheckedLocked-->resumeTopActivityInnerLocked

在resumeTopActivityInnerLocked末尾处调用了ActivityStackSupervisor中的startSpecificActivity方法。

image.png

ActivityStackSupervisor--->startSpecificActivity 代码如下:

 
void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
    // Is this activity's application already running?
    final WindowProcessController wpc =
            mService.getProcessController(r.processName, r.info.applicationInfo.uid);

    boolean knownToBeDead = false;
    if (wpc != null && wpc.hasThread()) {
        try {
            realStartActivityLocked(r, wpc, andResume, checkConfig);
            return;
        } catch (RemoteException e) {
            Slog.w(TAG, "Exception when starting activity "
                    + r.intent.getComponent().flattenToShortString(), e);
        }

        // If a dead object exception was thrown -- fall through to
        // restart the application.
        knownToBeDead = true;
    }

    r.notifyUnknownVisibilityLaunchedForKeyguardTransition();

    final boolean isTop = andResume && r.isTopRunningActivity();
    mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
}

此处,如果有app进程,则直接调用realStartActivityLocked方法。

如果没有进程,则去启动进程,我们进入mService.startProcessAsync() 代码,进行跟踪。

ActivityTaskManagerService-->startProcessAsync

image.png

方法中调用了这个方法:ActivityManagerInternal::startProcess,这个接口直接回调到了AMS中的startProcess。

ActivityManagerService-->startProcess--> startProcessLocked

ProcessList-->startProcessLocked-->startProcessLocked

image.png

final String entryPoint = "android.app.ActivityThread"; 这个值很关键

startProcessLocked方法继续往下。

startProcessLocked-->startProcess-->startProcess()-->createAppZygoteForProcessIfNeeded

image.png

image.png

创建AppZygote对象,保存到zygote集合中,并返回此对象。

创建appzygote对象之后,直接调用start方法。

image.png

此时来到了ZygoteProcess类中的start方法。

ZygoteProcess-->start()-->startViaZygote()

image.png

start方法调用后会根据传入的processClass参数进行创建新的进程然后调用该进程的main方法,在start函数reture之后创建出来的进程不受影响,继续运行。

进入到startViaZygote方法之内。

image.png

调用zygoteSendArgsAndGetResult,注意入参,会检查是否需要建立socket链接进行通信。

进入openZygoteSocketIfNeeded方法,最终调用connect方法。

image.png

 
/**
 * @hide for internal use only
 */
public static final int SOCKET_BUFFER_SIZE = 256;

先是创建一个LocalSocket,然后connect链接,并设置了传输buffer字节限制,SOCKET_BUFFER_SIZE=256.

socket链接之后,我们回到zygoteSendArgsAndGetResult,进入该方法中。

image.png

进入到 attemptUsapSendArgsAndGetResult 方法中,写入消息:

image.png

前面传入的 final String entryPoint = "android.app.ActivityThread" 值就是processClass,被socket发送了出去。

Zygote查看接收方法,如果调用进程的main方法的。

zygote初始化的时候会开启一个无限循环,一直读取发送过来的值。

ZygoteInit -->main()

ZygoteServer --> runSelectLoop()

image.png

进入到processOneCommand方法中,继续调用 handleChildProc 方法,最后调用Zygote中的 childZygoteInit 方法。

ZygoteServer --> runSelectLoop()

ZygoteConnection --> processOneCommand()--> handleChildProc()

processOneCommand的方法如下:

image.png

readArgumentList就是读取localSocket发送过来的值。(android.app.ActivityThread 这个processClass字符参数就被发送到了这里)

ZygoteInit --> childZygoteInit()

 
/**
 * The main function called when starting a child zygote process. This is used as an alternative
 * to zygoteInit(), which skips calling into initialization routines that start the Binder
 * threadpool.
 */
static final Runnable childZygoteInit(
        int targetSdkVersion, String[] argv, ClassLoader classLoader) {
    RuntimeInit.Arguments args = new RuntimeInit.Arguments(argv);
    return RuntimeInit.findStaticMain(args.startClass, args.startArgs, classLoader);
}

RuntimeInit-->findStaticMain() 通过反射调用class的main方法。

image.png

传递进来的className是ActivityThread,所以此处反射的就是ActivityThread的main方法,我们直接进入其中看下代码。

ActivityThread.main()

代码如下:

 
public static void main(String[] args) {
    
    ……………………
    
    Looper.prepareMainLooper();

    // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
    // It will be in the format "seq=114"
    long startSeq = 0;
    if (args != null) {
        for (int i = args.length - 1; i >= 0; --i) {
            if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                startSeq = Long.parseLong(
                        args[i].substring(PROC_START_SEQ_IDENT.length()));
            }
        }
    }
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);

    …………………

    // End of event ActivityThreadMain.
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");
}

ActivityThread --> main()-->attach(false)

image.png

注意此处的attach传入的参数是false,不是true,我们不要看到下面的 createAppContext中创建context逻辑里面去了。

IActivityManager --> attachApplication(); 此类是aidl接口,让ActivityThread和AMS直接通信。

ActivityManageService--> attachApplication() 这个方法很长,大约四百多行,我们直接搜索参数thread使用的地方,找到了thread.bindApplication();

ActivityThread-->bindApplication() -->sendMessage(H.BIND_APPLICATION, data)-->handleBindApplication()

image.png

图片中红色箭头处是创建applicatio的流程:

LoadedApk-->makeApplication()

Instumentation--> newApplication()

Application --> attach()-->attachBaseContext()

ContextWrapper -->attachBaseContext()

此刻的Application创建好之后,并没有发现执行application的onCreate方法,所以我们需要回到ActtivityThread中的当前代码节点继续往下看。

 
try {
    //创建application
    app = data.info.makeApplication(data.restrictedBackupMode, null);

    if (!data.restrictedBackupMode) {
        if (!ArrayUtils.isEmpty(data.providers)) {
             //初始化contentProvider
            installContentProviders(app, data.providers);
        }
    }

    try {
        mInstrumentation.onCreate(data.instrumentationArgs);
    }
    catch (Exception e) {
        throw new RuntimeException(
            "Exception thrown in onCreate() of "
            + data.instrumentationName + ": " + e.toString(), e);
    }
    try {
        //回调application的onCreate方法
        mInstrumentation.callApplicationOnCreate(app);
    } catch (Exception e) {
        if (!mInstrumentation.onException(app, e)) {
            throw new RuntimeException(
              "Unable to create application " + app.getClass().getName()
              + ": " + e.toString(), e);
        }
    }
} finally {
    // If the app targets < O-MR1, or doesn't change the thread policy
    // during startup, clobber the policy to maintain behavior of b/36951662
    if (data.appInfo.targetSdkVersion < Build.VERSION_CODES.O_MR1
            || StrictMode.getThreadPolicy().equals(writesAllowedPolicy)) {
        StrictMode.setThreadPolicy(savedPolicy);
    }
}

我们进入到callApplicationOnCreate方法中,代码如下:

 
/**
 * Perform calling of the application's {@link Application#onCreate}
 * method.  The default implementation simply calls through to that method.
 *
 * <p>Note: This method will be called immediately after {@link #onCreate(Bundle)}.
 * Often instrumentation tests start their test thread in onCreate(); you
 * need to be careful of races between these.  (Well between it and
 * everything else, but let's start here.)
 *
 * @param app The application being created.
 */
public void callApplicationOnCreate(Application app) {
    app.onCreate();
}

该方法直接执行了Application的onCreate方法,此时我们的程序已经算启动了。

前面流程先回顾一下

activity通过startActivity时,最终会调用到ActivityStackSupervisor--->startSpecificActivity() ,进程如果不存在,则去启动,如果进程存在,则会执行realStartActivityLocked()方法。

image.png

而在该方法中,我们刚刚是看的进程未启动的流程,所以这个地方它是如何又回调的这个地方来的呢?我们回到ActivityManagerService中的thread.bindApplication()代码节点继续往下走。

image.png

图片中红框一 调用了ATMS中的attachApplication() 方法。

红框二处是绑定服务的流程,先略过。

进入到ATMS中的attachApplication方法。

ATMS-->attachApplication();

RootWindowContainer --> attachApplication() -- startActivityForAttachedApplicationIfNeeded();

image.png

进入到startActivityForAttachedApplicationIfNeede方法中。

 
private boolean startActivityForAttachedApplicationIfNeeded(ActivityRecord r,
        WindowProcessController app, ActivityRecord top) {
    if (r.finishing || !r.okToShowLocked() || !r.visibleIgnoringKeyguard || r.app != null
            || app.mUid != r.info.applicationInfo.uid || !app.mName.equals(r.processName)) {
        return false;
    }

    try {
        //此处回调了ActivityStackSupervisor中的realStartActivityLocked方法。
        if (mStackSupervisor.realStartActivityLocked(r, app,
                top == r && r.isFocusable() /*andResume*/, true /*checkConfig*/)) {
            mTmpBoolean = true;
        }
    } catch (RemoteException e) {
        Slog.w(TAG, "Exception in new application when starting activity "
                + top.intent.getComponent().flattenToShortString(), e);
        mTmpRemoteException = e;
        return true;
    }
    return false;
}

此处回调了ActivityStackSupervisor中的realStartActivityLocked方法。

ActivityStackSupervisor --> realStartActivityLocked();

这个地方就和前面形成了闭环,即启动activity时,先检查进程是否存在,如果存在,直接启动activity;如果不存在,去创建进程,进程创建成功后,再次启动activity。

我们进入到realStartActivityLocked 看看activity是怎么启动的,它的生命周期又是如何回调的。

 
// Create activity launch transaction.
final ClientTransaction clientTransaction = ClientTransaction.obtain(
        proc.getThread(), r.appToken);

final DisplayContent dc = r.getDisplay().mDisplayContent;
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),


// Schedule transaction.
mService.getLifecycleManager().scheduleTransaction(clientTransaction);

该方法中调用了ATMS中的getLifecycleManager方法,并最终调用了ClientLifecycleManager.scheduleTransaction()方法,并将ClientTransaction对象当做参数传递了进去。

注意:此处创建了ClientTransaction对象,并addCallBack(). LaunchActivityItem,这个LaunchActivityItem是ClientTransactionItem的子类,后面执行execut方法时会被回调到。

 
public void schedule() throws RemoteException {
    mClient.scheduleTransaction(this);
}

ClientLifecycleManager --> scheduleTransaction()

IApplicationThread --> scheduleTransaction()

ApplicationThread(ActivityThrad的内部类) --> scheduleTransaction()

ClientTransactionHandler(ActivitThread的父类) --> scheduleTransaction()

 

/** Prepare and schedule transaction for execution. */
void scheduleTransaction(ClientTransaction transaction) {
    transaction.preExecute(this);
    sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}

ActivityThread的handler中查看该消息。

image.png

TransactionExecutor -- > execute() --> executeCallbacks()

ClientTransactionItem --> execute() 调用其父类的execute方法。

LaunchActivityItem --> execute() .

ClientTransactionHandler --> handleLaunchActivity() 它只有一个子类,就是ActivityThread。

ActivityThread --> handleLaunchActivity() --> performLaunchActivity();

performLaunchActivity代码精简如下:

 
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    
    //反射创建activity类。
    ContextImpl appContext = createBaseContextForActivity(r);
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = appContext.getClassLoader();
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
        StrictMode.incrementExpectedActivityCount(activity.getClass());
        r.intent.setExtrasClassLoader(cl);
        r.intent.prepareToEnterProcess();
        if (r.state != null) {
            r.state.setClassLoader(cl);
        }
    } catch (Exception e) {
        if (!mInstrumentation.onException(activity, e)) {
            throw new RuntimeException(
                "Unable to instantiate activity " + component
                + ": " + e.toString(), e);
        }
    }
    

    activity.attach(appContext, this, getInstrumentation(), r.token,
            r.ident, app, r.intent, r.activityInfo, title, r.parent,
            r.embeddedID, r.lastNonConfigurationInstances, config,
            r.referrer, r.voiceInteractor, window, r.configCallback,
            r.assistToken);


    if (activity != null) {      
        activity.mCalled = false;
        //执行Activity的onCreate方法。
        if (r.isPersistable()) {
            mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
        } else {
            mInstrumentation.callActivityOnCreate(activity, r.state);
        }

    }

    return activity;
}

其中先是反射创建了activity类,然后attach,最后通过Instumentation回调了Activity的onCreate方法。

Intrumentation --> callActivityOnCreate(); Activity --> onCreate();

 
mWindow = new PhoneWindow(this, window, activityConfigCallback);

attach方法就是赋值变量、然后给Activity创建一个视图窗口。

Activity.onCreate()被触发

在触发了Activity的onCreate的方法之后,整个Activity就算启动了,而Activity的启动流程也算是完毕。

Activity的其他生命周期,如start、resume、restart等方法回调是在TransactionExecutor --execute()--> executeLifecycleState().这个和前面的executeCallbacks()触发流程基本差不多,这里就不继续分析了。

avtivity启动后都是在onResume界面才能看到画面,所以我们单独看下onResume的触发流程。

TransactionExecutor-->executeLifecycleState()

ActivityLifecycleItem(父类的方法) --> execute

ResumeActivityItem --> handleResumeActivity()

ActivityThread --> handleResumeActivity();

 
if (r.activity.mVisibleFromClient) {
    r.activity.makeVisible();
}

Activity中的makeVisible方法如下:

 
void makeVisible() {
    if (!mWindowAdded) {
        ViewManager wm = getWindowManager();
        wm.addView(mDecor, getWindow().getAttributes());
        mWindowAdded = true;
    }
    mDecor.setVisibility(View.VISIBLE);
}

mDecor.setVisibility(View.VISIBLE);

mDecor.setVisibility(View.VISIBLE) 显示界面。

Activity启动全流程汇总

Activity --> startActivity()

Instrumentation ---> execStartActivity

ActivityTaskManagerService --> startActivityAsUser()

ActivityStarter--execute()--> startActivityInner--》deliverToCurrentTopIfNeeded()

RootWindowContainer--》resumeFocusedStacksTopActivities

ActivityStack-->resumeTopActivityUncheckedLocked-->resumeTopActivityInnerLocked

ActivityStackSupervisor--》startSpecificActivity()

startSpecificActivity方法内有两种情况:

 
1、存在进程,直接做创建activity并启动等流程:ActivityStackSupervisor--》 realStartActivityLocked

2、不存在进程,创建进程,然后再次回调  realStartActivityLocked()。

先看进程没有的流程。

先从zygote发送进程创建的流程开始。

ActivityTaskManagerService-->startProcessAsync

ActivityManagerService-->startProcess--> startProcessLocked()

ProcessList-->startProcessLocked-->startProcessLocked()-->startProcess-->startProcess()-->createAppZygoteForProcessIfNeeded()去创建zygote对象

 
//在startProcesslocked会判断是否启动了app进程,如果启动了,直接返回,没有则去通过Zygote发送消息的方式启动ActivitThread进程,

ZygoteProcess-->start()-->startViaZygote()--》zygoteSendArgsAndGetResult()

 
先建立localSocket链接,然后发送消息,去创建ActivitThread,并调用main方法。

另外此处发送的消息是什么要搞清楚?是processClass字段,值是 android.app.ActivityThread 

发送消息成功后,我们再看Zygote的接收流程:

从zygote初始化走起。

ZygoteInit -->main()

ZygoteServer --> runSelectLoop() :

 
runSelectLoop开启无限循环,一直读取localSocket的值。

ZygoteConnection --> processOneCommand()--> handleChildProc()

 
    try {
        //一直读取消息,在前面发送“com.app.AcitityThread”消息之后,这里会受到此消息。
        args = Zygote.readArgumentList(mSocketReader);
    } catch (IOException ex) {
        throw new IllegalStateException("IOException on command socket", ex);
    }

ZygoteInit --> childZygoteInit()

RuntimeInit-->findStaticMain() 通过反射调用class的main方法。

这里就是Zygote的发送消息、接收消息并创建ActivityThread且执行其main()方法的流程。


查看ActivityThread被创建之后的流程。

ActivityThread.main()

ActivityThread --> main()-->attach(false)

 
    attach传入的是false。

IActivityManager --> attachApplication();

 
    IActivityManager此类是aidl接口,让ActivityThread和AMS直接通信

ActivityManageService--> attachApplication()

ActivityThread-->bindApplication() -->sendMessage(H.BIND_APPLICATION, data)-->handleBindApplication()

 
    //handleBindApplication执行流程如下:

LoadedApk-->makeApplication()

Instumentation--> newApplication()

Application --> attach()-->attachBaseContext()

ContextWrapper -->attachBaseContext()

application和context都创建完毕之后,继续执行ActivityThread 之后的代码。

ActivityThread-->callApplicationOnCreate()

 
public void callApplicationOnCreate(Application app) {
	app.onCreate();
}		

此处执行了Application的onCreate方法,我们的程序已经启动

进程启动并执行onCreate方法之后,我们回到ATMS继续执行之后的方法。

ATMS-->attachApplication();

RootWindowContainer --> attachApplication() -- startActivityForAttachedApplicationIfNeeded();

ActivityStackSupervisor --> realStartActivityLocked();

 
   调用realStartActivityLocke()d和刚开始点击activity时的流程形成了闭环,即启动进程之后,再去执行启动Activity的流程。

我们现在可以查看realStartActivityLocked()方法之后的流程。

ClientLifecycleManager --> scheduleTransaction()

IApplicationThread --> scheduleTransaction()

ApplicationThread(ActivityThrad的内部类) --> scheduleTransaction()

ClientTransactionHandler(ActivitThread的父类) --> scheduleTransaction()

TransactionExecutor -- > execute() --> executeCallbacks()

ClientTransactionItem --> execute()

LaunchActivityItem --> execute()

ClientTransactionHandler --> handleLaunchActivity()

 
    ClientTransactionHandler它只有一个子类,就是ActivityThread。

ActivityThread --> handleLaunchActivity() --> performLaunchActivity();

 
    performLaunchActivity此处反射创建了activity类,然后attach,最后通过Instumentation回调了Activity的onCreate方法。

Activity.onCreate()被触发

至此Actiivty的启动流程已经完毕。

最后我们再看一下activity显示的流程。

avtivity启动后都是在onResume界面才能看到画面,所以我们单独看下onResume的触发流程。

TransactionExecutor-->executeLifecycleState()

ActivityLifecycleItem(父类的方法) --> execute

ResumeActivityItem --> handleResumeActivity()

ActivityThread --> handleResumeActivity();

 
if (r.activity.mVisibleFromClient) {
	r.activity.makeVisible();
}

void makeVisible() {
	if (!mWindowAdded) {
		ViewManager wm = getWindowManager();
		wm.addView(mDecor, getWindow().getAttributes());
		mWindowAdded = true;
	}
	mDecor.setVisibility(View.VISIBLE);
}

	
mDecor.setVisibility(View.VISIBLE);

mDecor.setVisibility(View.VISIBLE);这个就是显出view的方法,VISIBLE之后,我们的界面也能看到了。

启动时序总图

image.png

总结

Activity启动流程通过startActivity触发,会去检查进程是否启动,如果没有启动进程,会通过Zygote进程通过localSocket发送消息,消息的最关键信息是进程名字:android.app.ActivityThread。

因为zygote开启了无限循环检测,所以能够立马收到消息,并反射创建我们的ActivityThread类,并执行main方法。

ActivityThrad创建之后,会通过AMS中的attachApplication方法,创建Application,最后回到ActivityThread将application绑定context,最后执行Application的onCreate方法,app进程启动。

application启动之后再去启动activity。

启动activity最终会调用ActivityThread中的handleLaunchActivity方法,此方法调用之后会触发activity的onCreate方法,activity启动。

标签:--,app,Activity,ActivityThread,Framework,activity,Android,方法
From: https://www.cnblogs.com/zhanyaowang/p/18293205

相关文章

  • 【vueUse库Reactivity模块各函数简介及使用方法--上篇】
    vueUse库是一个专门为Vue打造的工具库,提供了丰富的功能,包括监听页面元素的各种行为以及调用浏览器提供的各种能力等。其中的Browser模块包含了一些实用的函数,以下是这些函数的简介和使用方法:vueUse库Sensors模块各函数简介及使用方法vueUseReactivity函数1.com......
  • 【vueUse库Reactivity模块各函数简介及使用方法--中篇】
    vueUse库是一个专门为Vue打造的工具库,提供了丰富的功能,包括监听页面元素的各种行为以及调用浏览器提供的各种能力等。其中的Browser模块包含了一些实用的函数,以下是这些函数的简介和使用方法:vueUse库Sensors模块各函数简介及使用方法vueUseReactivity函数1.rea......
  • HomeActivity启动流程(launcher)
     简介:0.写在前面的话上一篇讲了各种Service是在何时启动的,最后提到了关于HomeActivity的启动。HomeActivity作为Android系统启动后第一个加载的Activity,今天就来分析下其启动流程。0.写在前面的话上一篇讲了各种Service是在何时启动的,最后提到了关于HomeActivity的启动......
  • android RecyclerView 长按之后滑动手指多选
    关键函数与类LinearLayoutManager.canScrollHorizontally()LinearLayoutManager.canScrollVertically()RecyclerView.OnItemTouchListener核心代码mCanRecyclerViewScroll=true;recyclerView.setLayoutManager(newLinearLayoutManager(getContext(),LinearLayoutMana......
  • Android 11 recovery恢复出厂设置保留某些文件
    /bootable/recovery/recovery.cpprecovery的注释,流程解释!/**Therecoverytoolcommunicateswiththemainsystemthrough/cachefiles.*/cache/recovery/command-INPUT-commandlinefortool,oneargperline*/cache/recovery/log-OUTPUT-combin......
  • 将android studio安装到D盘
    双击exe安装,勾选指定到D盘复选框为[不创建快捷方式],点击[Install]安装完成启动不导入设置不发送信息取消下一步自定义设置设置主题指定sdk下载位置下一步下一步同意开始下载下载完成点击查看详情Preparing"......
  • Android面试题之Activity的启动模式和flag
    本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点Activity中的几种启动模式activity的几种启动模式是android中常考的知识点,一般会考察有哪几种启动模式,以及每种启动模式在什么场景下使用:standard:这个是android......
  • Android |(六)基础控件10 RecycleView 滑动【进阶】
      RecyclerView是官方在5.0之后新添加的控件,推出用来替代传统的ListView和GridView列表控件。一、RecycleView(一)总:添加RecycleView控件(1)activity_main中(2)初始化 (3)setLayoutManager()listRv.setLayoutManager(newLinearLayoutManager(this));RecyclerView提供......
  • IIS部署后运行报错:“C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporar
    IIS报错当前标识(IISAPPPOOL.NETv4.5)没有对“C:\Windows\Microsoft.NET\Framework64\v4.0.30319\TemporaryASP.NETFiles”的写访问权限。解决方法:1、以管理员权限运行PowerShell2、输入以下指令:C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Aspnet_regiis.exe-ga'......
  • Android全局替换字体
    一、概述由于业务需要,各端之间统一字体(Android、IOS、PC、网页)。所以android也需要替换成特定的字体。以后有可能还会增加其他的字体。方案:使用LayoutInflaterCompat.setFactory2来全局替换字体。这样做的好处是可以一次性的替换大部分的字体。剩余的个性......