Android一些小知識(shí)整理,用于面試

如果你想看Android源碼,強(qiáng)無敵,so,c++,jni,java都有

1. Android生命周期大家都知道,但你知道什么時(shí)候走onStop和onPuase,onDestory么,區(qū)別呢?

來自網(wǎng)絡(luò)圖片

Activity的活動(dòng)狀態(tài)與Activity在棧中的位置有密切的關(guān)系,而且,Android在系統(tǒng)資源不足的時(shí)候,也是從Activity棧中選擇哪些Activity是可以終止的,一般來講,Activity系統(tǒng)會(huì)優(yōu)先選擇終止處于目前是停止?fàn)顟B(tài)并且比較靠近Activity棧底的Activity。
也就是說onDestory并不是那么快,那為什么我應(yīng)用總onStop直接onDestory呢,因?yàn)槟沩?xiàng)目越是龐大,需求的資源就越多,所以系統(tǒng)認(rèn)為需要GC。

結(jié)合實(shí)例:
Activity的生命周期是指Activity從啟動(dòng)到銷毀的過程。


來自網(wǎng)絡(luò)圖片

Activity有四種狀態(tài):活動(dòng)狀態(tài) 暫停狀態(tài) 停止?fàn)顟B(tài) 非活動(dòng)狀態(tài)


來自網(wǎng)絡(luò)圖片

先看下Actvity的七個(gè)生命周期函數(shù)以及說下這幾個(gè)函數(shù)都是在什么時(shí)候調(diào)用的:
來自網(wǎng)絡(luò)圖片
  • 那么說明onDestory并不是來得飛快
  • 那么說明onStop只有被全部遮擋,就調(diào)用
  • 那么說明onPause只要被遮擋,就調(diào)用(除了幾個(gè)特殊)
    • 1.鎖屏的時(shí)候,會(huì)依次調(diào)用onPause()和onStop()。
    • 2.Toast、Dialog、Menu,三者都不會(huì)使Activity調(diào)用onPause()
    • 3.一個(gè)非全屏的Activity在前面時(shí),后面的Activity只調(diào)用onPause()

再補(bǔ)充一點(diǎn):這篇文章很贊,兩個(gè)activity切換生命周期你真懂么?
再擴(kuò)展發(fā)下思維:不同生命時(shí)期,調(diào)用finish會(huì)發(fā)生啥

出自:深入理解Android(2)鄧平凡

出自:深入理解Android(2)鄧平凡

出自:深入理解Android(2)鄧平凡
出自:深入理解Android(2)鄧平凡
出自:深入理解Android(2)鄧平凡

結(jié)合前面知識(shí)你應(yīng)用很清楚認(rèn)識(shí)到這個(gè)啟動(dòng)的流程的生命周期了。
再總結(jié)下:


出自:深入理解Android(2)鄧平凡

2. Actvity啟動(dòng)你了解過底層么,流程大致呢,繼承Actvity,自己是否一定要實(shí)現(xiàn)oncreate的方法?

轉(zhuǎn)載:Android Application啟動(dòng)流程分析
凡是涉及父類源碼中要調(diào)用getApplication().dispatchActivityXXX(this)時(shí)要重寫super.XXX(),因?yàn)檫@是binder回調(diào)過程,需要通知和更新當(dāng)前生命周期。當(dāng)然binder還要回饋給遠(yuǎn)端System Server

3. Android官方優(yōu)化工具會(huì)用么,區(qū)別呢?

轉(zhuǎn)載:App優(yōu)化之性能分析工具

  • 本人只會(huì)用Traceview而且很好用,分析方法調(diào)用棧以及其執(zhí)行時(shí)間, 優(yōu)化方法執(zhí)行。絕大部分是優(yōu)化時(shí)間效率
  • 控件樹的優(yōu)化,其實(shí)你在開發(fā)需求的時(shí)候就定死,你不可能腦殘到循環(huán)嵌套那么多層,用Hierarchy Viewer查看把深度的控件樹,變成廣度控件樹能提升。Hierarchy Viewer在ddms中其他window中,能單步反應(yīng)出每個(gè)控件的效率在相對(duì)這棵樹的情況,保持綠色小圓點(diǎn)最優(yōu),保持16ms渲染速度,3個(gè)小圓點(diǎn),Measure, Layout, Draw,保持draw在10ms以下基本最優(yōu)。
    你要有個(gè)概念GPU和CPU,你布局邏輯計(jì)算是CPU完成的,GPU只是貼圖和柵格化,主線程拿不到CPU片斷你也會(huì)掉幀。
    什么是掉幀,源碼是SurfaceFlinger真正繪制,發(fā)送Vsync通過Choreographer不停的loop向主線程,16ms一次,其中就被阻塞,如果當(dāng)次在16ms沒有繪制完,系統(tǒng)發(fā)出的Vsync沒有得到回收,該幀被丟棄,等待下一個(gè)Vsync才開始繪制,導(dǎo)致了可能在16ms*2內(nèi)顯示同一個(gè)畫面,這就是卡頓的原因。
    推薦個(gè)很牛的博客,底層分析
    來自網(wǎng)絡(luò)圖片
  • 還有內(nèi)存和oom,這個(gè)本人使用LeackCanary和Memory Monitor去分析了,大量的GC,內(nèi)存波動(dòng),你就要想這個(gè)需求是否正確了,LeackCanary會(huì)報(bào)很多GC不能回收的錯(cuò)誤,debug時(shí)候開啟它,盡量在開發(fā)時(shí)候就解決,到后期優(yōu)化,你要跳樓的。LeackCanary生成內(nèi)存分析報(bào)文hrof文件,在as中直接查看,如果你想忽略其中報(bào)錯(cuò),加入LeackCanary白名單代碼map,或者
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
   @Override
   public void handleMessage(Message msg) {
       super.handleMessage(msg);
   }
};

關(guān)于LeackCanary抓取回收dump文件過程,不詳細(xì)介紹,網(wǎng)上一大把。
大致:Application ====》install()====》LeackCanary:RefWatcher這貨去監(jiān)聽了Context的生命周期回調(diào)
AndroidWatchExextor線程處理收集信息 =====》Dump文件 ====》回調(diào)DumpService中Listener去刷新界面和通知欄
1.RefWactcher.watch()會(huì)監(jiān)控對(duì)象來創(chuàng)建一個(gè)keyedweadkRerence弱引用對(duì)象。
2.在AndroidWatchExextor后臺(tái)線程來檢查弱引用的對(duì)象被請(qǐng)出沒有,如果沒有,GC一次,然后再看
3.如果沒有干掉說明,內(nèi)存泄露,系統(tǒng)導(dǎo)出hprof文件
所有的強(qiáng)引用是鏈接在GC樹上的,只有瞬時(shí)的對(duì)象和臨時(shí)對(duì)象會(huì)自動(dòng)回收不在鏈接樹。
GC ROOT 你沒有懂?看這個(gè),我第一次就瞬間懂了

4. Android生命周期長(zhǎng)短比較?

getApplicationContext()(全局appliction的上下文) > getApplication()(全局appliction對(duì)象) > this(context)

關(guān)于上面錯(cuò)誤感謝評(píng)論區(qū):lockeez童鞋指針,錯(cuò)誤我先留這了,大家利用評(píng)論區(qū),學(xué)習(xí)總結(jié)下。
每個(gè)Application對(duì)應(yīng)于子進(jìn)程創(chuàng)建次數(shù),都會(huì)調(diào)用onCreate(),Application和Service一樣沒有onResume

5. JobServices?

在android7.0以后谷歌官方推薦用JobServices做調(diào)度作業(yè),起到優(yōu)化作用。
在以下場(chǎng)景很適用:
1.最小延時(shí) 2.是否空閑
3.是否有網(wǎng)絡(luò) 4.最晚執(zhí)行
5.是否充電。
滿足之一,需要調(diào)用權(quán)限。

6. AsyncTaskLoader和AsyncTask?

區(qū)別于AsyncTask一般做數(shù)據(jù)查詢,在Activity配置沒有改變,只更新數(shù)據(jù)源,loader用來開啟異步任務(wù)加載數(shù)據(jù)庫或者Uri數(shù)據(jù),只支持不耗時(shí)操作。

7. Android進(jìn)程優(yōu)先級(jí)你真了解完全了?

命令查看進(jìn)程
補(bǔ)充優(yōu)先級(jí)和拉活知識(shí)
據(jù)說手Q,保持活就是前臺(tái)一個(gè)像素activity
再補(bǔ)充一句,adb shell 默認(rèn)端口你了解過么,5037!
adb shell dumpsys activity top 獲取最上層的Activity

8. 非UI線程能更新UI?

非UI線程能更新UI,只要它有自己的ViewRoot。因?yàn)?,?bào)錯(cuò)是報(bào),你的view不在原來的線程。
轉(zhuǎn)載:Android子線程真的不能更新UI么

9. Activity啟動(dòng)模式小知識(shí)

  • 1.不同TaskAffiny和不同進(jìn)程都能StartActivityForResult回調(diào),這個(gè)過程谷歌官方說是安全的,就調(diào)用相機(jī),一定會(huì)有回掉,但數(shù)據(jù)有沒有不能保證。但!,很重要一點(diǎn),除了singleTop或者singleInstance特殊,activityA 通過startActivityForResult()方法來啟動(dòng)另一個(gè)ActivtyB,那么系統(tǒng)將直接返回Activity.Result_Canceled而不會(huì)繼續(xù)等待。這是由于FrameWork曾對(duì)2者做的限制,不同Task之間,默認(rèn)是不能傳遞數(shù)據(jù)的,如果你需要,那就Intent。
  • 2.getApplicationContext()能不能startActivity()?可以的。
    在ContextImpl.startActivity方法中,那我們?nèi)タ聪缕湓创a,如下:
    @Override
    public void startActivity(Intent intent, Bundle options) {
        warnIfCallingFromSystemProcess();
        // 就是下面這個(gè)檢測(cè)干的好事?。。?        if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
            throw new AndroidRuntimeException(
                    "Calling startActivity() from outside of an Activity "
                    + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
                    + " Is this really what you want?");
        }
        mMainThread.getInstrumentation().execStartActivity(
                getOuterContext(), mMainThread.getApplicationThread(), null,
                (Activity) null, intent, -1, options);
    }

通過上面的源碼我們發(fā)現(xiàn)了問題的根本原因,要fix這個(gè)問題也很簡(jiǎn)單,添加如下代碼intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);即可。

  • 3.onActivityResult特性:
/**
     * Called when an activity you launched exits, giving you the requestCode
     * you started it with, the resultCode it returned, and any additional
     * data from it.  The <var>resultCode</var> will be
     * {@link #RESULT_CANCELED} if the activity explicitly returned that,
     * didn't return any result, or crashed during its operation.
     *
     * <p>You will receive this call immediately before onResume() when your
     * activity is re-starting.
     *
     * <p>This method is never invoked if your activity sets
     * {@link android.R.styleable#AndroidManifestActivity_noHistory noHistory} to
     * <code>true</code>.
     *
     * @param requestCode The integer request code originally supplied to
     *                    startActivityForResult(), allowing you to identify who this
     *                    result came from.
     * @param resultCode The integer result code returned by the child activity
     *                   through its setResult().
     * @param data An Intent, which can return result data to the caller
     *               (various data can be attached to Intent "extras").
     *
     * @see #startActivityForResult
     * @see #createPendingResult
     * @see #setResult(int)
     */
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    }

也就是說,如果你給requestCode并且大于0,那么就會(huì)有數(shù)據(jù)返回,這和底層binder通信有關(guān),非oneway的形式。如果返回沒有結(jié)果,或者崩潰了在傳遞過程中,resultCode將等于RESULT_CANCELED。這個(gè)過程是onResume之前的。如果你的activity在AndroidManifest設(shè)置了noHistory為true,將不會(huì)有回調(diào)。

10. Bitmap用完一定要bitmap.recycle()么?

不需要,你調(diào)用也沒有錯(cuò),自動(dòng)Android 3.0之后,由于Bitmap放到j(luò)ava heap上,其內(nèi)存有GC管理,之前版本是在系統(tǒng)Native上的。

11.Android中為什么主線程不會(huì)因?yàn)長(zhǎng)ooper.loop()里的死循環(huán)卡死?

  • 也就是說,Android本身主線程是帶阻塞的,然而又為什么不會(huì)卡界面其他響應(yīng)呢,因?yàn)槭茿ndroid系統(tǒng)操作會(huì)繪制是事件驅(qū)動(dòng)行的,每次做個(gè)操作或者完成繪制,改變狀態(tài)是一個(gè)事件Post到主線程的,然后繼續(xù)運(yùn)行,休眠。
  • 再補(bǔ)充一點(diǎn)為什么ActivityThread本身是一個(gè)普通類,不是Runnable和Thread怎么實(shí)現(xiàn)線程機(jī)制和界面刷新的。在ActivityThread::main()===>attach()中完成了looper創(chuàng)建和ViewRootImpl創(chuàng)建(這就上面第8點(diǎn)的疑惑)
  • 其中會(huì)引入一個(gè)IdleHandler問題,什么叫空閑線程Handler,它就是在你這線程cpu空虛的時(shí)候干點(diǎn)臟活,如釋放資源,打印log
    內(nèi)容太多,簡(jiǎn)單描述就是,干完以后就休眠M(jìn)essageQueue
  • 這篇介紹了額外的內(nèi)容,關(guān)于C++底層監(jiān)控

補(bǔ)充內(nèi)容:為什么Android的Handler采用管道而不使用Binder?,Binder底層和Handler底層實(shí)現(xiàn)是一樣的,管道操作文件描述符的句柄,使用epoll往其中內(nèi)存地址空間寫數(shù)據(jù)。只是Binder比管道更加繁重,有Binder驅(qū)動(dòng)完成跨進(jìn)程,找到對(duì)應(yīng)端口。而管道只支持線程通信,因?yàn)樗僮鞯牡刂肥枪潭ǖ?,一端寫入一端寫出,跨進(jìn)程是需要拷貝數(shù)據(jù)到目標(biāo)進(jìn)程的。反過來可以,看鏈接描述。

這張圖能很好說明,跨進(jìn)程機(jī)制

12.Activity4種啟動(dòng)模式都知道了?那么有2個(gè)同是singleInstance并且taskAffinity相同會(huì)這樣呢?

沒有任何關(guān)系,啟動(dòng)后打印TaskId還是不同的idx。

        <activity
            android:name="com.example.aaa.a1"
            android:label="@string/app_name"
            android:taskAffinity="c.aaaa"
            android:launchMode="singleInstance">
        </activity>

        <activity
            android:name="com.example.aaa.a2"
            android:label="@string/app_name"
            android:taskAffinity="c.aaaa"
            android:launchMode="singleInstance">
        </activity>

13.bind啟動(dòng)的service,當(dāng)調(diào)用者finish掉后,會(huì)真的調(diào)用onUnbind么?

會(huì),親測(cè)demo

    @Override
    Activity :: protected void onCreate(Bundle savedInstanceState) {
        Intent intent = new Intent(this, a.class);
        bindService(intent, conn, Context.BIND_AUTO_CREATE);
        new Handler().post(new Runnable() {
            @Override
            public void run() {
                AppActivity.this.finish();
            }
        });

    @Override
    Service :: public boolean onUnbind(Intent intent) {
        Toast.makeText(this, "exit", Toast.LENGTH_SHORT).show();
        return super.onUnbind(intent);
    }

你可能不知道IntentService和Service真正區(qū)別。讓一次性簡(jiǎn)單記住,IntentService是只能塞進(jìn)去去完成任務(wù),做完就unbind了,所以你就認(rèn)為一次性的。Service復(fù)雜點(diǎn),能查詢也能做,IntentService只能做,不能記住狀態(tài)去查詢。

14你知道ViewRootImpl何時(shí)調(diào)用第一次performTraversals()?

出自 我簡(jiǎn)短了大部分,用來回答我問題,其他懂的,可以不看。
handleResumeActivity在收到AMS代理遠(yuǎn)程對(duì)象的Scaule后開始。
performLaunchActivity函數(shù)完成了兩件事:

  • 1 Activity窗口對(duì)象的創(chuàng)建,通過attach函數(shù)來完成;
  • 2 Activity視圖對(duì)象的創(chuàng)建,通過setContentView函數(shù)來完成;

這些準(zhǔn)備工作完成后,就可以顯示該Activity了,應(yīng)用程序進(jìn)程通過調(diào)用handleResumeActivity函數(shù)來啟動(dòng)Activity的顯示過程。

看addView()

frameworks\base\core\java\android\app\ ActivityThread.java

final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {  
    unscheduleGcIdler();  
    ActivityClientRecord r;  
    try {  
        ①r = performResumeActivity(token, clearHide);  
    } catch (Exception e) {  
        ...  
    }  
    if (r != null) {  
        final Activity a = r.activity;  
        ...  
        if (r.window == null && !a.mFinished && willBeVisible) {  
            //獲得為當(dāng)前Activity創(chuàng)建的窗口PhoneWindow對(duì)象  
            r.window = r.activity.getWindow();  
            //獲取為窗口創(chuàng)建的視圖DecorView對(duì)象  
            View decor = r.window.getDecorView();  
            decor.setVisibility(View.INVISIBLE);  
            //在attach函數(shù)中就為當(dāng)前Activity創(chuàng)建了WindowManager對(duì)象  
            ViewManager wm = a.getWindowManager();  
            //得到該視圖對(duì)象的布局參數(shù)  
            ②WindowManager.LayoutParams l = r.window.getAttributes();  
            //將視圖對(duì)象保存到Activity的成員變量mDecor中  
            a.mDecor = decor;  
            l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;  
            if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {  
                l.idleScreenAvailable = true;  
            } else {  
                l.idleScreenAvailable = false;  
            }  
            l.softInputMode |= forwardBit;  
            if (a.mVisibleFromClient) {  
                a.mWindowAdded = true;  
                //將創(chuàng)建的視圖對(duì)象DecorView添加到Activity的窗口管理器中  
                ③wm.addView(decor, l);  
            }  
        } else if (!willBeVisible) {  
            ...  
        }  
        ...  
        if (!r.onlyLocalRequest) {  
            r.nextIdle = mNewActivities;  
            mNewActivities = r;  
            Looper.myQueue().addIdleHandler(new Idler());  
        }  
        ...  
    } else {  
        ...  
    }  
}  

在前面的performLaunchActivity函數(shù)中完成Activity的創(chuàng)建后,會(huì)將當(dāng)前當(dāng)前創(chuàng)建的Activity在應(yīng)用程序進(jìn)程端的描述符ActivityClientRecord以鍵值對(duì)的形式保存到ActivityThread的成員變量mActivities中:mActivities.put(r.token, r),r.token就是Activity的身份證,即是IApplicationToken.Proxy代理對(duì)象,也用于與AMS通信。上面的函數(shù)首先通過performResumeActivity從mActivities變量中取出Activity的應(yīng)用程序端描述符ActivityClientRecord,然后取出前面為Activity創(chuàng)建的視圖對(duì)象DecorView和窗口管理器WindowManager,最后將視圖對(duì)象添加到窗口管理器中。

來自網(wǎng)絡(luò)圖片

我們知道Activity引用的其實(shí)是輕量級(jí)的窗口管理器LocalWindowManager

frameworks\base\core\java\android\view\ Window.java

public final void addView(View view, ViewGroup.LayoutParams params) {  
    WindowManager.LayoutParams wp = (WindowManager.LayoutParams)params;  
    CharSequence curTitle = wp.getTitle();  
    //應(yīng)用程序窗口  
    if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&  
        wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {  
        if (wp.token == null) {  
            View decor = peekDecorView();  
            if (decor != null) {  
                // LayoutParams 的token設(shè)置為W本地Binder對(duì)象  
                wp.token = decor.getWindowToken();  
            }  
        }  
        if (curTitle == null || curTitle.length() == 0) {  
            //根據(jù)窗口類型設(shè)置不同的標(biāo)題  
            …  
            if (mAppName != null) {  
                title += ":" + mAppName;  
            }  
            wp.setTitle(title);  
        }  
    } else {//系統(tǒng)窗口  
        if (wp.token == null) {  
            wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;  
        }  
        if ((curTitle == null || curTitle.length() == 0)  
                && mAppName != null) {  
            wp.setTitle(mAppName);  
        }  
    }  
    if (wp.packageName == null) {  
        wp.packageName = mContext.getPackageName();  
    }  
    if (mHardwareAccelerated) {  
        wp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;  
    }  
    super.addView(view, params);  
}  

看setView()

frameworks\base\core\java\android\view\WindowManagerImpl.java

private void addView(View view, ViewGroup.LayoutParams params,  
        CompatibilityInfoHolder cih, boolean nest) {  
    ...  
    final WindowManager.LayoutParams wparams= (WindowManager.LayoutParams)params;  
    ViewRootImpl root;  
    View panelParentView = null;  
    synchronized (this) {  
        ...  
        //從mViews中查找當(dāng)前添加的View  
        int index = findViewLocked(view, false);  
        //如果已經(jīng)存在,直接返回  
        if (index >= 0) {  
            ...  
            return;  
        }  
        //尚未添加當(dāng)前View  
        if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&  
                wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {  
            final int count = mViews != null ? mViews.length : 0;  
            for (int i=0; i<count; i++) {  
                if (mRoots[i].mWindow.asBinder() == wparams.token) {  
                    panelParentView = mViews[i];  
                }  
            }  
        }  
        //為Activity創(chuàng)建一個(gè)ViewRootImpl對(duì)象  
        ①root = new ViewRootImpl(view.getContext());  
        ...  
        //設(shè)置視圖組件的布局參數(shù)  
        view.setLayoutParams(wparams);  
        if (mViews == null) {  
            index = 1;  
            mViews = new View[1];  
            mRoots = new ViewRootImpl[1];  
            mParams = new WindowManager.LayoutParams[1];  
        } else {  
            //動(dòng)態(tài)增加mViews數(shù)組長(zhǎng)度  
            index = mViews.length + 1;  
            Object[] old = mViews;  
            mViews = new View[index];  
            System.arraycopy(old, 0, mViews, 0, index-1);  
            //動(dòng)態(tài)增加mRoots數(shù)組長(zhǎng)度  
            old = mRoots;  
            mRoots = new ViewRootImpl[index];  
            System.arraycopy(old, 0, mRoots, 0, index-1);  
            //動(dòng)態(tài)增加mParams數(shù)組長(zhǎng)度  
            old = mParams;  
            mParams = new WindowManager.LayoutParams[index];  
            System.arraycopy(old, 0, mParams, 0, index-1);  
        }  
        index--;  
        ②mViews[index] = view;  
        mRoots[index] = root;  
        mParams[index] = wparams;  
    }  
    try {  
        ③root.setView(view, wparams, panelParentView);   
    } catch (RuntimeException e) {  
        ...  
    }  
}  

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {  
    synchronized (this) {  
        if (mView == null) {  
            //將DecorView保存到ViewRootImpl的成員變量mView中  
            mView = view;  
            mFallbackEventHandler.setView(view);  
            mWindowAttributes.copyFrom(attrs);  
            attrs = mWindowAttributes;  
            mClientWindowLayoutFlags = attrs.flags;  
            setAccessibilityFocus(null, null);  
            //DecorView實(shí)現(xiàn)了RootViewSurfaceTaker接口  
            if (view instanceof RootViewSurfaceTaker) {  
                mSurfaceHolderCallback =  
                        ((RootViewSurfaceTaker)view).willYouTakeTheSurface();  
                if (mSurfaceHolderCallback != null) {  
                    mSurfaceHolder = new TakenSurfaceHolder();  
                    mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);  
                }  
            }  
            ...  
            //同時(shí)將DecorView保存到mAttachInfo中  
            mAttachInfo.mRootView = view;  
            mAttachInfo.mScalingRequired = mTranslator != null;  
            mAttachInfo.mApplicationScale = mTranslator == null ? 1.0f : mTranslator.applicationScale;  
            if (panelParentView != null) {  
                mAttachInfo.mPanelParentWindowToken  
                        = panelParentView.getApplicationWindowToken();  
            }  
            ...  
            //在添加窗口前進(jìn)行UI布局  
            ①requestLayout();  
            if ((mWindowAttributes.inputFeatures& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {  
                mInputChannel = new InputChannel();  
            }  
            try {  
                mOrigWindowType = mWindowAttributes.type;  
                mAttachInfo.mRecomputeGlobalAttributes = true;  
                collectViewAttributes();  
                //將窗口添加到WMS服務(wù)中,mWindow為W本地Binder對(duì)象,通過Binder傳輸?shù)絎MS服務(wù)端后,變?yōu)镮Window代理對(duì)象  
                ②res = sWindowSession.add(mWindow, mSeq, mWindowAttributes,  
                        getHostVisibility(), mAttachInfo.mContentInsets,  
                        mInputChannel);  
            } catch (RemoteException e) {  
                ...  
            }  
            ...  
            //建立窗口消息通道  
            if (view instanceof RootViewSurfaceTaker) {  
                mInputQueueCallback =  
                    ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();  
            }  
            if (mInputChannel != null) {  
                if (mInputQueueCallback != null) {  
                    mInputQueue = new InputQueue(mInputChannel);  
                    mInputQueueCallback.onInputQueueCreated(mInputQueue);  
                } else {  
                    mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,Looper.myLooper());  
                }  
            }  
            ...  
        }  
    }  
}  

public void requestLayout() {  
    //檢查當(dāng)前線程是否是UI線程  
    checkThread();  
    //標(biāo)識(shí)當(dāng)前正在請(qǐng)求UI布局  
    mLayoutRequested = true;  
    scheduleTraversals();  
} 

void scheduleTraversals() {  
    if (!mTraversalScheduled) {  
        mTraversalScheduled = true;  
        //暫停UI線程消息隊(duì)列對(duì)同步消息的處理  
        mTraversalBarrier = mHandler.getLooper().postSyncBarrier();  
        //向Choreographer注冊(cè)一個(gè)類型為CALLBACK_TRAVERSAL的回調(diào),用于處理UI繪制  
        mChoreographer.postCallback(  
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);  
        //向Choreographer注冊(cè)一個(gè)類型為CALLBACK_INPUT的回調(diào),用于處理輸入事件  
        scheduleConsumeBatchedInput();  
    }  
}  

final TraversalRunnable mTraversalRunnable = new TraversalRunnable();  
final class TraversalRunnable implements Runnable {  
        @Override  
        public void run() {  
            doTraversal();  
        }  
}  

void doTraversal() {  
    if (mTraversalScheduled) {  
        mTraversalScheduled = false;  
        mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);  
        if (mProfile) {  
            Debug.startMethodTracing("ViewAncestor");  
        }  
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals");  
        try {  
            performTraversals();  
        } finally {  
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);  
        }  
        if (mProfile) {  
            Debug.stopMethodTracing();  
            mProfile = false;  
        }  
    }  
} 

ViewRootImpl的setView函數(shù)向WMS服務(wù)添加一個(gè)窗口對(duì)象過程:

  • 1 requestLayout()在應(yīng)用程序進(jìn)程中進(jìn)行窗口UI布局;
  • 2 WindowSession.add()向WMS服務(wù)注冊(cè)一個(gè)窗口對(duì)象;
  • 3 注冊(cè)應(yīng)用程序進(jìn)程端的消息接收通道;
    這就是為什么你在OnReume一開始調(diào)用View的高寬拿不到,postRunnale以后能拿到,因?yàn)閐oTraversal()在Post棧頂,等它跑完就能拿到數(shù)值了。
    補(bǔ)充硬件加速原理

對(duì)View補(bǔ)充一些知識(shí)






出自Android開發(fā)藝術(shù)探索-4.3.1章

15 Android在應(yīng)用層有3種信號(hào)你知道么?

public static final int SIGNAL_QUIT = 3; // 追蹤日志
public static final int SIGNAL_KILL = 9; // Process::killProcess()應(yīng)用比較多
public static final int SIGNAL_USR1 = 10; // 用于強(qiáng)制執(zhí)行GC

理解殺進(jìn)程的實(shí)現(xiàn)原理

16 Intent和PendingIntent?

Android中pendingIntent的深入理解

  • Intent是立即使用的,而PendingIntent可以等到事件發(fā)生后觸發(fā),PendingIntent可以cancel
  • Intent在程序結(jié)束后即終止,而PendingIntent在程序結(jié)束后依然有效
  • PendingIntent自帶Context,而Intent需要在某個(gè)Context內(nèi)運(yùn)行
  • Intent在原task中運(yùn)行,PendingIntent在新的task中運(yùn)行

PendingIntent還要注意其中flag,因?yàn)樗怯袃?nèi)核收集器,像Map一樣

public final class PendingIntent implements Parcelable {
       /** @hide */
       @IntDef(flag = true, //======================flag值=============================
            value = {
                    FLAG_ONE_SHOT,
                    FLAG_NO_CREATE,
                    FLAG_CANCEL_CURRENT,
                    FLAG_UPDATE_CURRENT,

                    Intent.FILL_IN_ACTION,
                    Intent.FILL_IN_DATA,
                    Intent.FILL_IN_CATEGORIES,
                    Intent.FILL_IN_COMPONENT,
                    Intent.FILL_IN_PACKAGE,
                    Intent.FILL_IN_SOURCE_BOUNDS,
                    Intent.FILL_IN_SELECTOR,
                    Intent.FILL_IN_CLIP_DATA
            })

    public static PendingIntent getActivity(Context context, int requestCode,
            Intent intent, @Flags int flags) {
        return getActivity(context, requestCode, intent, flags, null);
    }

    public static PendingIntent getActivity(Context context, int requestCode,
            @NonNull Intent intent, @Flags int flags, @Nullable Bundle options) {
        String packageName = context.getPackageName();
        String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
                context.getContentResolver()) : null;
        try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess(context);
            IIntentSender target =
                ActivityManagerNative.getDefault().getIntentSender(
                    ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
                    null, null, requestCode, new Intent[] { intent },
                    resolvedType != null ? new String[] { resolvedType } : null,
                    flags, options, UserHandle.myUserId());
            return target != null ? new PendingIntent(target) : null;
        } catch (RemoteException e) {
        }
        return null;
    }
}

遠(yuǎn)程對(duì)象,在system server進(jìn)程中 AMS.getIntentSender。

public IIntentSender getIntentSender(int type,
        String packageName, IBinder token, String resultWho,
        int requestCode, Intent[] intents, String[] resolvedTypes,
        int flags, Bundle options, int userId) {
    //重新拷貝一次intent對(duì)象內(nèi)容
    if (intents != null) {
        for (int i=0; i<intents.length; i++) {
            Intent intent = intents[i];
            if (intent != null) {
                intents[i] = new Intent(intent);
            }
        }
    }

    ...
       synchronized(this) {
        int callingUid = Binder.getCallingUid();
        int origUserId = userId;
        userId = handleIncomingUser(Binder.getCallingPid(), callingUid, userId,
                type == ActivityManager.INTENT_SENDER_BROADCAST,
                ALLOW_NON_FULL, "getIntentSender", null);
        if (origUserId == UserHandle.USER_CURRENT) {
            userId = UserHandle.USER_CURRENT;
        }
        return getIntentSenderLocked(type, packageName, callingUid, userId,
              token, resultWho, requestCode, intents, resolvedTypes, flags, options);
    }
}

IIntentSender getIntentSenderLocked(int type, String packageName,
        int callingUid, int userId, IBinder token, String resultWho,
        int requestCode, Intent[] intents, String[] resolvedTypes, int flags,
        Bundle options) {
    ActivityRecord activity = null;
    ...
    //創(chuàng)建Key對(duì)象
    PendingIntentRecord.Key key = new PendingIntentRecord.Key(
            type, packageName, activity, resultWho,
            requestCode, intents, resolvedTypes, flags, options, userId);
    WeakReference<PendingIntentRecord> ref;
    ref = mIntentSenderRecords.get(key);//=======================關(guān)于flag使用========================
    PendingIntentRecord rec = ref != null ? ref.get() : null;
    if (rec != null) {
        if (!cancelCurrent) {
            if (updateCurrent) {
                if (rec.key.requestIntent != null) {
                    rec.key.requestIntent.replaceExtras(intents != null ?
                            intents[intents.length - 1] : null);
                }
                if (intents != null) {
                    intents[intents.length-1] = rec.key.requestIntent;
                    rec.key.allIntents = intents;
                    rec.key.allResolvedTypes = resolvedTypes;
                } else {
                    rec.key.allIntents = null;
                    rec.key.allResolvedTypes = null;
                }
            }
            return rec;
        }
        rec.canceled = true;
        mIntentSenderRecords.remove(key);
    }
    if (noCreate) {
        return rec;
    }
    //創(chuàng)建PendingIntentRecord對(duì)象
    rec = new PendingIntentRecord(this, key, callingUid);
    mIntentSenderRecords.put(key, rec.ref);
    ...
    return rec;
}

17 BroadcastReceiver?

BroadcastReceiver分為兩類:

  • 靜態(tài)廣播接收者:通過AndroidManifest.xml的標(biāo)簽來申明的BroadcastReceiver。
  • 動(dòng)態(tài)廣播接收者:通過AMS.registerReceiver()方式注冊(cè)的BroadcastReceiver,動(dòng)態(tài)注冊(cè)更為靈活,可在不需要時(shí)通過unregisterReceiver()取消注冊(cè)。

前面你都知道,下面這3個(gè)你知道么。
從廣播發(fā)送方式可分為三類:

  • 普通廣播:通過Context.sendBroadcast()發(fā)送,可并行處理
  • 有序廣播:通過Context.sendOrderedBroadcast()發(fā)送,串行處理
  • Sticky廣播:通過Context.sendStickyBroadcast()發(fā)送

區(qū)別。很多誤區(qū)在有序廣播,并不是發(fā)送一條條有序,而是接受一條條有順序,排序更android:priority有關(guān)。

18 java對(duì)象和java序列化原理?

序列化的原理
對(duì)象模型
其實(shí)就是一堆字節(jié)碼,linux也是有文件節(jié)點(diǎn)掛載起來的,說白了也是一堆字節(jié)碼。通信就全靠序列號(hào)來標(biāo)識(shí)。

19 說說Android應(yīng)用的persistent屬性?

Android應(yīng)用的persistent屬性觀看這個(gè)博客需要先看Android系統(tǒng)啟動(dòng)流程,才能大部分有概念。一般普通應(yīng)用不要使用,沒有權(quán)限限制這貨。
知道這貨能干嘛呢?如果我要你啟動(dòng)系統(tǒng)相機(jī)你怎么玩,不要彈出Intent匹配對(duì)話框?

    public static void launchSystemCamera(Activity activity, File file, int requestCode) {
        try{
            //獲取相機(jī)包名
            Intent infoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            List<ResolveInfo> infos = activity.getPackageManager().queryIntentActivities(infoIntent, 0);
            if(infos != null && infos.size() > 0) {
                for(ResolveInfo info:infos) {
                    int flags = info.activityInfo.applicationInfo.flags;
                    if ((flags & ApplicationInfo.FLAG_SYSTEM) != 0) { //系統(tǒng)相機(jī)
                        String packageName = info.activityInfo.packageName;
                        String className = info.activityInfo.name;
                        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
                        ComponentName cn = new ComponentName(packageName, className);
                        intent.setComponent(cn);
                        intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
                        intent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(file));
                        activity.startActivityForResult(intent,requestCode);
                        return;
                    }
                }
            }
        } catch(Exception e) {
            e.printStackTrace();
        }

    }

20 為啥從應(yīng)用層面來說,沒有殺不死的進(jìn)程?

Android進(jìn)程絕殺技--forceStop看完這篇依賴相殺,大家估計(jì)都有個(gè)概念了。需要了解AMS下的AMS死亡監(jiān)聽
關(guān)于自創(chuàng)Native進(jìn)程,不知怎么殺...

21 是時(shí)候熟悉一個(gè)JNI調(diào)用系統(tǒng)服務(wù)代碼了,Camera?

Android Camera 系統(tǒng)架構(gòu)源碼分析
總結(jié)下:底層大致數(shù)據(jù)處理時(shí)會(huì)阻塞,然后自己不處理,姿勢(shì)把數(shù)據(jù)流放給上層,在上層開始Camera的時(shí)候你會(huì)設(shè)置一堆監(jiān)聽,然后底層會(huì)通過binder遠(yuǎn)程調(diào)用監(jiān)聽。
DisplayClient用來負(fù)責(zé)顯示,CamClient則是一個(gè)大統(tǒng)一,把Camera的操作都?xì)w集于此。CamClient又把自己的功能分成幾個(gè) Client去負(fù)責(zé),其中PreviewClient負(fù)責(zé)預(yù)覽錄制,RecordClient負(fù)責(zé)錄制。
CameraClient和DisplayClient是兩個(gè)功能的操作者,而CamAdapter則是整個(gè)Camera的管理者,負(fù)責(zé)與底層溝通,讀取Buf,并負(fù)責(zé)分配Buf給各個(gè)功能操作者,并包括管理著Camer各種屬性和算法,如3A,是否自動(dòng)對(duì)焦等

22 共享內(nèi)存MMP 總結(jié):



出自深入理解ANDROID 卷1.pdf

23 容易被多進(jìn)程命名誤導(dǎo)":"在xml的含義



出自Android開發(fā)藝術(shù)探索,2.2.1章
最后編輯于
?著作權(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)容

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