Android Application的雜事

一、Application簡(jiǎn)單介紹

每個(gè)Android App都在一個(gè)獨(dú)立空間里, 意味著其運(yùn)行在一個(gè)單獨(dú)的進(jìn)程中, 擁有自己的VM, 被系統(tǒng)分配一個(gè)唯一的user ID。Android App由很多不同組件組成,這些組件還可以啟動(dòng)其他App的組件。 因此, Android App并沒有一個(gè)類似程序入口的main()方法。

Android Application組件包括:
  • Activities: 前臺(tái)界面, 直接面向User, 提供UI和操作。
  • Services: 后臺(tái)任務(wù)。
  • Broadcast Receivers: 廣播接收者。
  • Contexnt Providers: 數(shù)據(jù)提供者。
一個(gè)進(jìn)程里面只有一個(gè)線程---主線程。 這個(gè)主線程中有一個(gè)Looper實(shí)例,通過調(diào)用Looper.loop()從Message隊(duì)列里面取出Message來做相應(yīng)的處理。

如果你的apk沒有運(yùn)行, 系統(tǒng)會(huì)為其創(chuàng)建一個(gè)新的進(jìn)程并啟動(dòng) 。通常, 這個(gè)進(jìn)程會(huì)持續(xù)運(yùn)行直到被系統(tǒng)殺死. 關(guān)鍵是: 進(jìn)程是在被需要的時(shí)候才創(chuàng)建的。

二、Application啟動(dòng)流程

用戶點(diǎn)擊app的時(shí)候發(fā)生了什么事情呢?

1 會(huì)調(diào)用startActivity(Intent), 會(huì)通過Binder IPC機(jī)制, 最終調(diào)用到ActivityManagerService。 該Service會(huì)執(zhí)行如下操作:
  • 第一步通過PackageManager的resolveIntent()收集這個(gè)intent對(duì)象的指向信息.
    指向信息被存儲(chǔ)在一個(gè)intent對(duì)象中。
  • 接著通過grantUriPermissionLocked()方法來驗(yàn)證用戶是否有足夠的權(quán)限去調(diào)用該intent對(duì)象指向的Activity。
  • 如果有權(quán)限, ActivityManagerService會(huì)檢查并在新的task中啟動(dòng)目標(biāo)activity.
    現(xiàn)在, 是時(shí)候檢查這個(gè)進(jìn)程的ProcessRecord是否存在了。
  • 如果ProcessRecord是null, ActivityManagerService會(huì)創(chuàng)建新的進(jìn)程來實(shí)例化目標(biāo)activity。
2 創(chuàng)建進(jìn)程

ActivityManagerService調(diào)用startProcessLocked()方法來創(chuàng)建新的進(jìn)程, 該方法會(huì)通過前面講到的socket通道傳遞參數(shù)給Zygote進(jìn)程. Zygote孵化自身, 并調(diào)用ZygoteInit.main()方法來實(shí)例化ActivityThread對(duì)象并最終返回新進(jìn)程的pid。

ActivityThread隨后依次調(diào)用Looper.prepareLoop()和Looper.loop()來開啟消息循環(huán)。

3 綁定Application

接下來要做的就是將進(jìn)程和指定的Application綁定起來. 這個(gè)是通過上節(jié)的ActivityThread對(duì)象中調(diào)用bindApplication()方法完成的. 該方法發(fā)送一個(gè)BIND_APPLICATION的消息到消息隊(duì)列中, 最終通過handleBindApplication()方法處理該消息. 然后調(diào)用makeApplication()方法來加載App的classes到內(nèi)存中。

Paste_Image.png
4 啟動(dòng)Activity

經(jīng)過前兩個(gè)步驟之后, 系統(tǒng)已經(jīng)擁有了該application的進(jìn)程. 后面的調(diào)用順序就是普通的從一個(gè)已經(jīng)存在的進(jìn)程中啟動(dòng)一個(gè)新進(jìn)程的activity了.

實(shí)際調(diào)用方法是realStartActivity(), 它會(huì)調(diào)用application線程對(duì)象中的sheduleLaunchActivity()發(fā)送一個(gè)LAUNCH_ACTIVITY消息到消息隊(duì)列中, 通過 handleLaunchActivity()來處理該消息

四、通過Application來監(jiān)聽App處于前臺(tái)和后臺(tái)?
/**
 * @創(chuàng)建 HaiJia
 * @時(shí)間 2017/3/16 15:26
 * @描述 利用Application監(jiān)聽App處于前臺(tái)和后臺(tái)
 * @需求 App從前臺(tái)切換到后臺(tái),不需要做什么操作;從后臺(tái)切換到前臺(tái),需要先驗(yàn)證屏鎖密碼
 */

public class ForegroundCallBacks implements Application.ActivityLifecycleCallbacks{

    public static final long CHECK_DELAY = 500;//Handler延遲執(zhí)行時(shí)間
    public static final String TAG = ForegroundCallBacks.class.getName();

    public interface Listener {
        public void onBecameForeground();
        public void onBecameBackground();
    }


    private static ForegroundCallBacks instance;
    private boolean foreground = false, paused = true;
    private Handler handler = new Handler();
    private List<Listener> listeners = new CopyOnWriteArrayList<>();
    private Runnable check;


    /**
     *
     * @描述 初始化
     */
    public static ForegroundCallBacks init(Application application){
        if (instance == null) {
            instance = new ForegroundCallBacks();
            application.registerActivityLifecycleCallbacks(instance);
        }
        return instance;
    }

    /**
     *
     * @描述 get ForegroundCallBacks實(shí)例
     * @param Application
     */
    public static ForegroundCallBacks get(Application application){
        if (instance == null) {
            init(application);
        }
        return instance;
    }

    /**
     *
     * @描述 get ForegroundCallBacks實(shí)例
     * @param Context
     */
    public static ForegroundCallBacks get(Context ctx){
        if (instance == null) {
            Context appCtx = ctx.getApplicationContext();
            if (appCtx instanceof Application) {
                init((Application)appCtx);
            }else {
                throw new IllegalStateException(
                        "Foreground is not initialised and " +
                                "cannot obtain the Application object");
            }
        }
        return instance;
    }

    /**
     * @描述 get ForegroundCallBacks實(shí)例
     */
    public static ForegroundCallBacks get(){
        if (instance == null) {
            throw new IllegalStateException(
                    "Foreground is not initialised - invoke " +
                            "at least once with parameterised init/get");
        }
        return instance;
    }

    /**
     *
     * @描述 App處于是否在前臺(tái)
     */
    public boolean isForeground(){
        return foreground;
    }

    /**
     *
     * @描述 App處于是否在后臺(tái)
     */
    public boolean isBackground(){
        return !foreground;
    }

    /**
     *
     * @描述 添加監(jiān)聽
     */
    public void addListener(Listener listener){
        listeners.add(listener);
    }

    /**
     *
     * @描述 移除監(jiān)聽
     */
    public void removeListener(Listener listener){
        listeners.remove(listener);
    }



    /**
     * @描述 onActivityResumed
     */
    @Override
    public void onActivityResumed(Activity activity) {
        paused = false;
        boolean wasBackground = !foreground;
        foreground = true;
        if (check != null)
            handler.removeCallbacks(check);
        if (wasBackground){
            LogUtils.log("went foreground");
            for (Listener l : listeners) {
                try {
                    l.onBecameForeground();
                } catch (Exception exc) {
                    LogUtils.log("Listener threw exception!", exc);
                }
            }
        } else {
            LogUtils.log("still foreground");
        }
    }

    @Override
    public void onActivityPaused(Activity activity) {
        paused = true;
        if (check != null)
            handler.removeCallbacks(check);
        handler.postDelayed(check = new Runnable(){
            @Override
            public void run() {
                if (foreground && paused) {
                    foreground = false;
                    LogUtils.log("went background");
                    for (Listener l : listeners) {
                        try {
                            l.onBecameBackground();
                        } catch (Exception exc) {
                            LogUtils.log("Listener threw exception!", exc);
                        }
                    }
                } else {
                    LogUtils.log("still foreground");
                }
            }
        }, CHECK_DELAY);
    }

    @Override
    public void onActivityCreated(Activity activity, Bundle bundle) {

    }

    @Override
    public void onActivityStarted(Activity activity) {

    }

    @Override
    public void onActivityStopped(Activity activity) {

    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {

    }

    @Override
    public void onActivityDestroyed(Activity activity) {

    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,765評(píng)論 25 709
  • Android Studio JNI流程首先在java代碼聲明本地方法 用到native關(guān)鍵字 本地方法不用去實(shí)現(xiàn)...
    MigrationUK閱讀 12,077評(píng)論 7 123
  • 本文出自 Eddy Wiki ,轉(zhuǎn)載請(qǐng)注明出處:http://eddy.wiki/interview-androi...
    eddy_wiki閱讀 3,375評(píng)論 0 20
  • 1.什么是Activity?問的不太多,說點(diǎn)有深度的 四大組件之一,一般的,一個(gè)用戶交互界面對(duì)應(yīng)一個(gè)activit...
    JoonyLee閱讀 5,855評(píng)論 2 51
  • 0403晨讀 :暗示 自律 記錄 1、暗示:刷牙時(shí)牙膏的一點(diǎn)清涼感,可以讓人下意識(shí)的覺得牙齒的清潔,大概人們會(huì)把清...
    宵汀閱讀 210評(píng)論 0 1

友情鏈接更多精彩內(nèi)容