01.Android之基礎(chǔ)組件問題

目錄介紹

  • 1.0.0.1 說下Activity的生命周期?屏幕旋轉(zhuǎn)時生命周期?異常條件會調(diào)用什么方法?
  • 1.0.0.2 后臺的Activity被系統(tǒng)回收怎么辦?說一下onSaveInstanceState()和onRestoreInstanceState()方法特點?
  • 1.0.0.3 如何避免配置改變時Activity重建?優(yōu)先級低的Activity在內(nèi)存不足被回收后怎樣做可以恢復(fù)到銷毀前狀態(tài)?
  • 1.0.0.4 app切換到后臺,當前activity會走onDestory方法嗎?一般在onstop方法里做什么?什么情況會導(dǎo)致app會被殺死?
  • 1.0.0.5 Activity的啟動過程是有幾種方式?從桌面launcher上點擊應(yīng)用圖標會干啥,調(diào)用startActivty()又會做什么?
  • 1.0.0.6 說下Activity的四種啟動模式?singleTop和singleTask的區(qū)別以及應(yīng)用場景?任務(wù)棧的作用是什么?
  • 1.0.0.7 兩個Activity之間怎么傳遞數(shù)據(jù)?intent和bundle有什么區(qū)別?為什么有了intent還要設(shè)計bundle?
  • 1.0.0.8 知道哪些Activity啟動模式的標記位?flag是干什么用的,什么時候用到?
  • 1.0.1.0 同一程序不同的Activity是否可以放在不同的Task任務(wù)棧中?
  • 1.0.1.1 介紹一下Service,啟動Service有幾種方式,生命周期是怎樣的?說一下onStartCommand()的作用?service如何殺不死?
  • 1.0.1.2 一個Activty先start一個Service后,再bind時會回調(diào)什么方法?此時如何做才能回調(diào)Service的destory()方法?
  • 1.0.1.3 bindService是一個異步的過程嗎?綁定service大概需要經(jīng)歷那些過程?
  • 1.0.1.4 是否能在Service進行耗時操作?如果非要可以怎么做,如何避免service線程卡頓?service里面可以彈土司嗎?
  • 1.0.1.5 Activity如何與Service通信?Service的生命周期與啟動方法有什么區(qū)別?
  • 1.0.2.0 是否了解ActivityManagerService,它發(fā)揮什么作用,說一下AMS啟動流程?
  • 1.0.2.1 Android中哪些事件需要用到廣播?廣播的生命周期是怎樣的?
  • 1.0.2.3 廣播有幾種形式?他們分別有什么特點,如何使用廣播?廣播是怎么實現(xiàn)不同進程之間通信的?
  • 1.0.2.8 Fragment與Activity之間是如何傳值的?Fragment與Fragment之間是如何傳值的?
  • 1.0.2.9 Activity創(chuàng)建Fragment的方式是什么?FragmentPageAdapter和FragmentPageStateAdapter的區(qū)別?
  • 1.0.3.0 fragment 特點?說一下Fragment的生命周期?如何解決getActivity為null的異常問題?
  • 1.0.3.1 在fragment中為什么有時getActivity()會為null?Fragment試圖為什么有的時候會重疊,怎么產(chǎn)生的,又如何解決?
  • 1.0.3.2 為什么fragment傳遞數(shù)據(jù)不用構(gòu)造方法傳遞?FragmentManager , add 和 replace 有什么區(qū)別?
  • 1.0.3.9 Activitiy啟動流程中performLaunchActivity的作用?
  • 1.0.4.0 Intent是什么?Intent可以傳遞哪些數(shù)據(jù)?傳遞對象的時候為什么要實例化?
  • 1.0.4.1 mipmap系列中xxxhdpi、xxhdpi、xhdpi、hdpi、mdpi和ldpi存在怎樣的關(guān)系?
  • 1.0.4.2 res目錄和assets目錄的區(qū)別?R文件是如何生成的,主要有什么作用?
  • 1.0.4.3 Context是什么?Context有哪些類型,分別作用是什么?Context下有哪些子類?哪些場景只能用activity上下文?
  • 1.0.4.4 ActivityThread的main()的流程大概是怎么樣的?
  • 1.0.5.0 序列化的方式有哪些?效率對比有何優(yōu)勢?如何做性能上分析的?
  • 1.0.5.9 界面的刷新為什么需16.6ms?畫面的顯示需要哪些步驟?界面保持不變時還會16.6ms刷新一次屏幕嗎?
  • 1.0.6.0 Android中日志級別有哪幾種?開發(fā)中需要注意什么問題,打印日志源碼分析原理是什么?

好消息

  • 博客筆記大匯總【15年10月到至今】,包括Java基礎(chǔ)及深入知識點,Android技術(shù)博客,Python學習筆記等等,還包括平時開發(fā)中遇到的bug匯總,當然也在工作之余收集了大量的面試題,長期更新維護并且修正,持續(xù)完善……開源的文件是markdown格式的!同時也開源了生活博客,從12年起,積累共計500篇[近100萬字],將會陸續(xù)發(fā)表到網(wǎng)上,轉(zhuǎn)載請注明出處,謝謝!
  • 鏈接地址:https://github.com/yangchong211/YCBlogs
  • 如果覺得好,可以star一下,謝謝!當然也歡迎提出建議,萬事起于忽微,量變引起質(zhì)變!所有的筆記將會更新到GitHub上,同時保持更新,歡迎同行提出或者push不同的看法或者筆記!

1.0.0.1 說下Activity的生命周期?屏幕旋轉(zhuǎn)時生命周期?異常條件會調(diào)用什么方法?

  • 在Activity的生命周期涉及到七大方法,分別是:
    • onCreate()表示Activity 正在創(chuàng)建,常做初始化工作,如setContentView界面資源、初始化數(shù)據(jù)
    • onStart()表示Activity 正在啟動,這時Activity 可見但不在前臺,無法和用戶交互
    • onResume()表示Activity 獲得焦點,此時Activity 可見且在前臺并開始活動
    • onPause()表示Activity 正在停止,可做 數(shù)據(jù)存儲、停止動畫等操作
    • onStop()表示activity 即將停止,可做稍微重量級回收工作,如取消網(wǎng)絡(luò)連接、注銷廣播接收器等
    • onDestroy()表示Activity 即將銷毀,常做回收工作、資源釋放
    • onRestart()表示當Activity由后臺切換到前臺,由不可見到可見時會調(diào)用,表示Activity 重新啟動
  • 屏幕旋轉(zhuǎn)時生命周期
    • 屏幕旋轉(zhuǎn)時候,如果不做任何處理,activity會經(jīng)過銷毀到重建的過程。一般這種效果都不是想要的。比如視頻播放器就經(jīng)常會涉及屏幕旋轉(zhuǎn)場景。技術(shù)博客大總結(jié)
    • 第一種情況:當前的Activity不銷毀【設(shè)置Activity的android:configChanges="orientation|keyboardHidden|screenSize"時,切屏不會重新調(diào)用各個生命周期,只會執(zhí)行onConfigurationChanged方法】
      <activity
          android:name=".activity.VideoDetailActivity"
          android:configChanges="orientation|keyboardHidden|screenSize"
          android:screenOrientation="portrait"/>
      
      • 執(zhí)行該方法
      //重寫旋轉(zhuǎn)時方法,不銷毀activity
      @Override
      public void onConfigurationChanged(Configuration newConfig) {
          super.onConfigurationChanged(newConfig);
      }
      
    • 第二種情況:銷毀當前的Activity后重建,這種也盡量避免?!静辉O(shè)置Activity的android:configChanges時,切屏會重新調(diào)用各個生命周期,默認首先銷毀當前activity,然后重新加載】
  • 異常條件會調(diào)用什么方法
    • 當非人為終止Activity時,比如系統(tǒng)配置發(fā)生改變時導(dǎo)致Activity被殺死并重新創(chuàng)建、資源內(nèi)存不足導(dǎo)致低優(yōu)先級的Activity被殺死,會調(diào)用 onSavaInstanceState() 來保存狀態(tài)。該方法調(diào)用在onStop之前,但和onPause沒有時序關(guān)系。
    • 有人會問,onSaveInstanceState()與onPause()的區(qū)別,onSaveInstanceState()適用于對臨時性狀態(tài)的保存,而onPause()適用于對數(shù)據(jù)的持久化保存。
    • 當異常崩潰后App又重啟了,這個時候會走onRestoreInstanceState()方法,可以在該方法中取出onSaveInstanceState()保存的狀態(tài)數(shù)據(jù)。
  • 什么時候會引起異常生命周期
    • 資源相關(guān)的系統(tǒng)配置發(fā)生改變或者資源不足:例如屏幕旋轉(zhuǎn),當前Activity會銷毀,并且在onStop之前回調(diào)onSaveInstanceState保存數(shù)據(jù),在重新創(chuàng)建Activity的時候在onStart之后回調(diào)onRestoreInstanceState。其中Bundle數(shù)據(jù)會傳到onCreate(不一定有數(shù)據(jù))和onRestoreInstanceState(一定有數(shù)據(jù))。技術(shù)博客大總結(jié)
    • 防止屏幕旋轉(zhuǎn)的時候重建,在清單文件中添加配置:android:configChanges="orientation"

1.0.0.2 后臺的Activity被系統(tǒng)回收怎么辦?說一下onSaveInstanceState()和onRestoreInstanceState()方法特點?

  • 后臺的Activity被系統(tǒng)回收怎么辦?
    • Activity中提供了一個 onSaveInstanceState()回調(diào)方法,這個方法會保證一定在活動被回收之前調(diào)用,可以通過這個方法來解決活動被回收時臨時數(shù)據(jù)得不到保存的問題。onSaveInstanceState()方法會攜帶一個Bundle類型的參數(shù),Bundle提供了一系列的方法用于保存數(shù)據(jù),比如可以使用putString()方法保存字符串,使用putInt()方法保存整型數(shù)據(jù)。每個保存方法需要傳入兩個參數(shù),第一個參數(shù)是鍵,用于后面從 Bundle中取值,第二個參數(shù)是真正要保存的內(nèi)容。技術(shù)博客大總結(jié)
  • 說一下onSaveInstanceState()和onRestoreInstanceState()方法特點?
    • Activity的 onSaveInstanceState()和onRestoreInstanceState()并不是生命周期方法,它們不同于onCreate()、onPause()等生命周期方法,它們并不一定會被觸發(fā)。
      //保存數(shù)據(jù)
      @Override
      protected void onSaveInstanceState(Bundle outBundle) {
          super.onSaveInstanceState(outBundle);
          outBundle.putBoolean("Change", mChange);
      }
      
      //取出數(shù)據(jù)
      @Override 
      protected void onRestoreInstanceState(Bundle savedInstanceState) {
          super.onRestoreInstanceState(savedInstanceState);
          mChange = savedInstanceState.getBoolean("Change");
      }
      
      //或者在onCreate方法取數(shù)據(jù)也可以
      //onCreate()方法其實也有一個Bundle類型的參數(shù)。這個參數(shù)在一般情況下都是null,
      //但是當活動被系統(tǒng)回收之前有通過 onSaveInstanceState()方法來保存數(shù)據(jù)的話,這個參就會帶有之前所保存的全部數(shù)據(jù)
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          if (savedInstanceState != null) {
              String data = savedInstanceState.getString("data");
          }
      }
      
  • 什么時候會觸發(fā)走這兩個方法?
    • 當應(yīng)用遇到意外情況(如:內(nèi)存不足、用戶直接按Home鍵)由系統(tǒng)銷毀一個Activity,onSaveInstanceState() 會被調(diào)用。但是當用戶主動去銷毀一個Activity時,例如在應(yīng)用中按返回鍵,onSaveInstanceState()就不會被調(diào)用。除非該activity是被用戶主動銷毀的,通常onSaveInstanceState()只適合用于保存一些臨時性的狀態(tài),而onPause()適合用于數(shù)據(jù)的持久化保存。
  • onSaveInstanceState()被執(zhí)行的場景有哪些?
    • 系統(tǒng)不知道你按下HOME后要運行多少其他的程序,自然也不知道activityA是否會被銷毀,因此系統(tǒng)都會調(diào)用onSaveInstanceState(),讓用戶有機會保存某些非永久性的數(shù)據(jù)。以下幾種情況的分析都遵循該原則當用戶按下HOME鍵時
      • 長按HOME鍵,選擇運行其他的程序時
      • 鎖屏時
      • 從activity A中啟動一個新的activity時
      • 屏幕方向切換時

1.0.0.3 如何避免配置改變時Activity重建?優(yōu)先級低的Activity在內(nèi)存不足被回收后怎樣做可以恢復(fù)到銷毀前狀態(tài)?

  • 如何避免配置改變時Activity重建
    • 為了避免由于配置改變導(dǎo)致Activity重建,可在AndroidManifest.xml中對應(yīng)的Activity中設(shè)置android:configChanges="orientation|screenSize"。此時再次旋轉(zhuǎn)屏幕時,該Activity不會被系統(tǒng)殺死和重建,只會調(diào)用onConfigurationChanged。因此,當配置程序需要響應(yīng)配置改變,指定configChanges屬性,重寫onConfigurationChanged方法即可。
    • 使用場景,比如視頻播放器橫豎屏切換播放視頻,就需要設(shè)置這種屬性。具體可以看我封裝的視頻播放器庫,地址:https://github.com/yangchong211/YCVideoPlayer
  • 優(yōu)先級低的Activity在內(nèi)存不足被回收后怎樣做可以恢復(fù)到銷毀前狀態(tài)
    • 優(yōu)先級低的Activity在內(nèi)存不足被回收后重新打開會引發(fā)Activity重建。Activity被重新創(chuàng)建時會調(diào)用onRestoreInstanceState(該方法在onStart之后),并將onSavaInstanceState保存的Bundle對象作為參數(shù)傳到onRestoreInstanceState與onCreate方法。因此可通過onRestoreInstanceState(Bundle savedInstanceState)和onCreate((Bundle savedInstanceState)來判斷Activity是否被重建,并取出數(shù)據(jù)進行恢復(fù)。但需要注意的是,在onCreate取出數(shù)據(jù)時一定要先判斷savedInstanceState是否為空。
  • 如何判斷activity的優(yōu)先級?技術(shù)博客大總結(jié)
    • 除了在棧頂?shù)腶ctivity,其他的activity都有可能在內(nèi)存不足的時候被系統(tǒng)回收,一個activity越處于棧底,被回收的可能性越大.如果有多個后臺進程,在選擇殺死的目標時,采用最近最少使用算法(LRU)。

1.0.0.4 app切換到后臺,當前activity會走onDestory方法嗎?一般在onstop方法里做什么?什么情況會導(dǎo)致app會被殺死,這時候會走onDestory嗎?

  • app切換到后臺,當前activity會走onDestory方法嗎?
    • 不會走onDestory方法,會先后走onPause和onStop方法。
  • 一般在onstop方法里做什么?
    • 比如。寫輪播圖的時候,會在onstop方法里寫上暫停輪播圖無限輪播,在onStart方法中會開啟自動無限輪播。
    • 再比如,寫視頻播放器的時候,當app切換到后臺,則需要停止視頻播放,也是可以在onstop中處理的。關(guān)于視頻播放器,可以看我這個開源項目:視頻播放器
  • 什么情況會導(dǎo)致app會被殺死,這時候會走onDestory嗎?
    • 系統(tǒng)資源不足,會導(dǎo)致app意外被殺死。應(yīng)用只有在進程存活的情況下才會按照正常的生命周期進行執(zhí)行,如果進程突然被kill掉,相當于System.exit(0); 進程被殺死,根本不會走(activity,fragment)生命周期。只有在進程不被kill掉,正常情況下才會執(zhí)行ondestory()方法。
  • activity被回收如何恢復(fù)
    • 當系統(tǒng)內(nèi)存不足時, activity會被回收,我們其實可以覆寫onSaveInstanceState()方法。onSaveInstanceState()方法接受一個Bundle類型的參數(shù), 開發(fā)者可以將狀態(tài)數(shù)據(jù)存儲到這個Bundle對象中,這樣即使activity被系統(tǒng)摧毀,當用戶重新啟動這個activity而調(diào)用它的onCreate()方法時,上述的Bundle對象會作為實參傳遞給onCreate()方法,開發(fā)者可以從Bundle對象中取出保存的數(shù)據(jù), 然后利用這些數(shù)據(jù)將activity恢復(fù)到被摧毀之前的狀態(tài)。

1.0.0.5 Activity的啟動過程是有幾種方式?從桌面launcher上點擊應(yīng)用圖標會干啥,調(diào)用startActivty()又會做什么?

  • Activity的啟動過程是怎樣的,有幾種方式?
    • 注意是啟動過程,不是生命周期。技術(shù)博客大總結(jié)
    • app啟動的過程有兩種情況,第一種是從桌面launcher上點擊相應(yīng)的應(yīng)用圖標,第二種是在activity中通過調(diào)用startActivity來啟動一個新的activity。
  • 從桌面launcher上點擊應(yīng)用圖標會干啥,調(diào)用startActivty()又會做什么?
    • 創(chuàng)建一個新的項目,默認的根activity都是MainActivity,而所有的activity都是保存在堆棧中的,啟動一個新的activity就會放在上一個activity上面,而我們從桌面點擊應(yīng)用圖標的時候,由于launcher本身也是一個應(yīng)用,當我們點擊圖標的時候,系統(tǒng)就會調(diào)用startActivitySately(),一般情況下,我們所啟動的activity的相關(guān)信息都會保存在intent中,比如action,category等等。
    • 我們在安裝這個應(yīng)用的時候,系統(tǒng)也會啟動一個PackaManagerService的管理服務(wù),這個管理服務(wù)會對AndroidManifest.xml文件進行解析,從而得到應(yīng)用程序中的相關(guān)信息,比如service,activity,Broadcast等等,然后獲得相關(guān)組件的信息。
    • 當我們點擊應(yīng)用圖標的時候,就會調(diào)用startActivitySately()方法,而這個方法內(nèi)部則是調(diào)用startActivty(),而startActivity()方法最終還是會調(diào)用startActivityForResult()這個方法。而在startActivityForResult()這個方法。因為startActivityForResult()方法是有返回結(jié)果的,所以系統(tǒng)就直接給一個-1,就表示不需要結(jié)果返回了。
    • 而startActivityForResult()這個方法實際是通過Instrumentation類中的execStartActivity()方法來啟動activity,Instrumentation這個類主要作用就是監(jiān)控程序和系統(tǒng)之間的交互。而在這個execStartActivity()方法中會獲取ActivityManagerService的代理對象,通過這個代理對象進行啟動activity。啟動會就會調(diào)用一個checkStartActivityResult()方法,如果說沒有在配置清單中配置有這個組件,就會在這個方法中拋出異常了。
    • 當然最后是調(diào)用的是Application.scheduleLaunchActivity()進行啟動activity,而這個方法中通過獲取得到一個ActivityClientRecord對象,而這個ActivityClientRecord通過handler來進行消息的發(fā)送,系統(tǒng)內(nèi)部會將每一個activity組件使用ActivityClientRecord對象來進行描述,而ActivityClientRecord對象中保存有一個LoaderApk對象,通過這個對象調(diào)用handleLaunchActivity來啟動activity組件,而頁面的生命周期方法也就是在這個方法中進行調(diào)用。

1.0.0.6 說下Activity的四種啟動模式?singleTop和singleTask的區(qū)別以及應(yīng)用場景?任務(wù)棧的作用是什么?

  • Activity的四種啟動模式
    • standard標準模式:每次啟動一個Activity就會創(chuàng)建一個新的實例
    • singleTop棧頂復(fù)用模式:如果新Activity已經(jīng)位于任務(wù)棧的棧頂,就不會重新創(chuàng)建,并回調(diào) onNewIntent(intent) 方法
    • singleTask棧內(nèi)復(fù)用模式:只要該Activity在一個任務(wù)棧中存在,都不會重新創(chuàng)建,并回調(diào) onNewIntent(intent) 方法。如果不存在,系統(tǒng)會先尋找是否存在需要的棧,如果不存在該棧,就創(chuàng)建一個任務(wù)棧,并把該Activity放進去;如果存在,就會創(chuàng)建到已經(jīng)存在的棧中
    • singleInstance單實例模式:具有此模式的Activity只能單獨位于一個任務(wù)棧中,且此任務(wù)棧中只有唯一一個實例
  • singleTop和singleTask的區(qū)別以及應(yīng)用場景
    • singleTop:同個Activity實例在棧中可以有多個,即可能重復(fù)創(chuàng)建;該模式的Activity會默認進入啟動它所屬的任務(wù)棧,即不會引起任務(wù)棧的變更;為防止快速點擊時多次startActivity,可以將目標Activity設(shè)置為singleTop
    • singleTask:同個Activity實例在棧中只有一個,即不存在重復(fù)創(chuàng)建;可通過android:taskAffinity設(shè)定該Activity需要的任務(wù)棧,即可能會引起任務(wù)棧的變更;常用于主頁和登陸頁
  • singleTop或singleTask的Activity在以下情況會回調(diào)onNewIntent()
    • singleTop:如果新Activity已經(jīng)位于任務(wù)棧的棧頂,就不會重新創(chuàng)建,并回調(diào) onNewIntent(intent) 方法
    • singleTask:只要該Activity在一個任務(wù)棧中存在,都不會重新創(chuàng)建,并回調(diào) onNewIntent(intent) 方法
  • 任務(wù)棧的作用是什么?技術(shù)博客大總結(jié)
    • 它是存放 Activity 的引用的,Activity不同的啟動模式,對應(yīng)不同的任務(wù)棧的存放;可通過 getTaskId()來獲取任務(wù)棧的 ID,如果前面的任務(wù)棧已經(jīng)清空,新開的任務(wù)棧ID+1,是自動增長的;首先來看下Task的定義,Google是這樣定義Task的:Task實際上是一個Activity棧,通常用戶感受的一個Application就是一個Task。從這個定義來看,Task跟Service或者其他Components是沒有任何聯(lián)系的,它只是針對Activity而言的。

1.0.0.7 兩個Activity之間怎么傳遞數(shù)據(jù)?intent和bundle有什么區(qū)別?為什么有了intent還要設(shè)計bundle?

  • 兩個Activity之間怎么傳遞數(shù)據(jù)?
    • 基本數(shù)據(jù)類型可以通過Intent傳遞數(shù)據(jù)
    • 把數(shù)據(jù)封裝至intent對象中
      Intent intent = new Intent(content, MeActivity.class);
      intent.putExtra("goods_id", goods_id);
      content.startActivity(intent);
      
    • 把數(shù)據(jù)封裝至bundle對象中技術(shù)博客大總結(jié)
    • 把bundle對象封裝至intent對象中
      Bundle bundle = new Bundle();
      bundle.putString("malename", "李志");
      intent.putExtras(bundle);
      startActivity(intent); 
      
  • intent和bundle有什么區(qū)別?
    • Intent傳遞數(shù)據(jù)和Bundle傳遞數(shù)據(jù)是一回事,Intent傳遞時內(nèi)部還是調(diào)用了Bundle。
      public @NonNull Intent putExtra(String name, String value) {
          if (mExtras == null) {
              mExtras = new Bundle();
          }
          mExtras.putString(name, value);
          return this;
      }
      
  • 為什么有了intent還要設(shè)計bundle?
    • 兩者比較
      • Bundle只是一個信息的載體,內(nèi)部其實就是維護了一個Map<String,Object>。
      • Intent負責Activity之間的交互,內(nèi)部是持有一個Bundle的。
    • bundle使用場景
      • Fragment之間傳遞數(shù)據(jù);比如,某個Fragment中點擊按鈕彈出一個DialogFragment。最便捷的方式就是通過Fragment.setArguments(args)傳遞參數(shù)。
      public static void showFragmentDialog(String title, String content, boolean is_open, AppCompatActivity activity) {
          ServiceDialogFragment mainDialogFragment = new ServiceDialogFragment();
          Bundle bundle = new Bundle();
          bundle.putString("title", title);
          bundle.putString("content", content);
          bundle.putBoolean("is_open",is_open);
          mainDialogFragment.setArguments(bundle);
          mainDialogFragment.show(activity.getSupportFragmentManager());
      }
      
      @Override
      public void onCreate(Bundle savedInstanceState) {
          setLocal(Local.CENTER);
          super.onCreate(savedInstanceState);
          Bundle bundle = getArguments();
          if (bundle != null) {
              title = bundle.getString("title");
              content = bundle.getString("content");
              is_open = bundle.getBoolean("is_open");
          }
      }
      

1.0.0.8 知道哪些Activity啟動模式的標記位?flag是干什么用的,什么時候用到?

  • 常見的標記為:
    • FLAG_ACTIVITY_SINGLE_TOP:對應(yīng)singleTop啟動模式
    • FLAG_ACTIVITY_NEW_TASK :對應(yīng)singleTask模式

1.0.1.0 同一程序不同的Activity是否可以放在不同的Task任務(wù)棧中?

  • 同一程序不同的Activity是否可以放在不同的Task任務(wù)棧中?
    • 可以的。比如:啟動模式里有個Singleinstance,可以運行在另外的單獨的任務(wù)棧里面。用這個模式啟動的activity,在內(nèi)存中只有一份,這樣就不會重復(fù)的開啟。
    • 也可以在激活一個新的activity時候,給intent設(shè)置flag,Intent的flag添加FLAG_ACTIVITY_NEW_TASK,這個被激活的activity就會在新的task棧里面

1.0.1.1 介紹一下Service,啟動Service有幾種方式,生命周期是怎樣的?說一下onStartCommand()的作用?service如何殺不死?

  • Service分為兩種
    • 本地服務(wù),屬于同一個應(yīng)用程序,通過startService來啟動或者通過bindService來綁定并且獲取代理對象。如果只是想開個服務(wù)在后臺運行的話,直接startService即可,如果需要相互之間進行傳值或者操作的話,就應(yīng)該通過bindService。
    • 遠程服務(wù)(不同應(yīng)用程序之間),通過bindService來綁定并且獲取代理對象。
  • 對應(yīng)的生命周期如下:
    • context.startService() ->onCreate()- >onStartCommand()->Service running--調(diào)用context.stopService() ->onDestroy()
    • context.bindService()->onCreate()->onBind()->Service running--調(diào)用>onUnbind() -> onDestroy()
  • 注意
    • Service默認是運行在main線程的,因此Service中如果需要執(zhí)行耗時操作(大文件的操作,數(shù)據(jù)庫的拷貝,網(wǎng)絡(luò)請求,文件下載等)的話應(yīng)該在子線程中完成。
  • Service生命周期解釋技術(shù)博客大總結(jié)
    • onCreate():服務(wù)第一次被創(chuàng)建時調(diào)用
    • onStartComand():服務(wù)啟動時調(diào)用
    • onBind():服務(wù)被綁定時調(diào)用
    • onUnBind():服務(wù)被解綁時調(diào)用
    • onDestroy():服務(wù)停止時調(diào)用
  • 說一下onStartCommand()的作用?
  • service如何殺不死?
    • 1.onStartCommand方法,返回START_STICKY(粘性)當service因內(nèi)存不足被kill,當內(nèi)存又有的時候,service又被重新創(chuàng)建
    • 2.設(shè)置優(yōu)先級,在服務(wù)里的ondestory里發(fā)送廣播 在廣播里再次開啟這個服務(wù),雙進程守護

1.0.1.2 一個Activty先start一個Service后,再bind時會回調(diào)什么方法?此時如何做才能回調(diào)Service的destory()方法?

  • 關(guān)于service中onDestroy()什么時候會被執(zhí)行?
    • 當調(diào)用了startService()方法后,又去調(diào)用stopService()方法,這時服務(wù)中的onDestroy()方法就會執(zhí)行,表示服務(wù)已經(jīng)銷毀了。
    • 類似地,當調(diào)用了 bindService()方法后,又去調(diào)用unbindService()方法,onDestroy()方法也會執(zhí)行,這兩種情況都很好理解。
  • 一個Activty先start一個Service后,再bind時會回調(diào)什么方法?

  • 先start后bind操作service,此時如何做才能回調(diào)Service的destory()方法?
    • 完全有可能對一個服務(wù)既調(diào)用了startService()方法,又調(diào)用了bindService()方法的,這種情況下該如何才能讓服務(wù)銷毀掉呢?根據(jù)Android系統(tǒng)的機制,一個服務(wù)只要被啟動或者被綁定了之后,就會一直處于運行狀態(tài),必須要讓以上兩種條件同時不滿足,服務(wù)才能被銷毀。
    • 這種情況下要同時調(diào)用stopService()和unbindService()方法,onDestroy()方法才會執(zhí)行這樣就把服務(wù)的生命周期完整地走了一遍。技術(shù)博客大總結(jié)

1.0.1.3 bindService是一個異步的過程嗎?綁定service大概需要經(jīng)歷那些過程?

1.0.1.4 是否能在Service進行耗時操作?如果非要可以怎么做,如何避免service線程卡頓?service里面可以彈土司嗎?

  • 是否能在Service進行耗時操作?
    • 默認情況,如果沒有顯示的指定service所運行的進程,Service和Activity是運行在當前app所在進程的mainThread(UI主線程)里面。
    • service里面不能執(zhí)行耗時的操作(網(wǎng)絡(luò)請求,拷貝數(shù)據(jù)庫,大文件),在Service里執(zhí)行耗時操作,有可能出現(xiàn)主線程被阻塞(ANR)的情況。
  • 如果非要可以怎么做,如何避免service線程卡頓?
    • 需要在子線程中執(zhí)行 new Thread(){}.start();
  • service里面可以彈土司嗎?
    • 可以,但是有條件。一般很少這樣做……技術(shù)博客大總結(jié)
    • 條件是,service里面彈toast需要添加到主線程里執(zhí)行。
      @Override  
      public void onCreate(){  
          handler = new Handler(Looper.getMainLooper());                          
          System.out.println("service started");  
          handler.post(new Runnable() {    
              @Override    
              public void run() {    
                  Toast.makeText(getApplicationContext(), "Test",Toast.LENGTH_SHORT).show();
              }
          });
      }
      

1.0.1.5 Activity如何與Service通信?Service的生命周期與啟動方法有什么區(qū)別?

  • Activity如何與Service通信?
    • 方法一:
      • 添加一個繼承Binder的內(nèi)部類,并添加相應(yīng)的邏輯方法。重寫Service的onBind方法,返回我們剛剛定義的那個內(nèi)部類實例。Activity中創(chuàng)建一個ServiceConnection的匿名內(nèi)部類,并且重寫里面的onServiceConnected方法和onServiceDisconnected方法,這兩個方法分別會在活動與服務(wù)成功綁定以及解除綁定的時候調(diào)用,在onServiceConnected方法中,我們可以得到一個剛才那個service的binder對象,通過對這個binder對象進行向下轉(zhuǎn)型,得到我們那個自定義的Binder實例,有了這個實例,做可以調(diào)用這個實例里面的具體方法進行需要的操作了
    • 方法二
      • 通過BroadCast(廣播)的形式,當我們的進度發(fā)生變化的時候我們發(fā)送一條廣播,然后在Activity的注冊廣播接收器,接收到廣播之后更新視圖

1.0.2.0 是否了解ActivityManagerService,它發(fā)揮什么作用,說一下AMS啟動流程?

  • ActivityManagerService是Android中最核心的服務(wù),主要負責系統(tǒng)中四大組件的啟動、切換、調(diào)度及應(yīng)用進程的管理和調(diào)度等工作,其職責與操作系統(tǒng)中的進程管理和調(diào)度模塊類似。
  • https://blog.csdn.net/dutedehuai/article/details/53495185

1.0.2.1 Android中哪些事件需要用到廣播?廣播的生命周期是怎樣的?

  • Android中哪些事件需要用到廣播?
    • Android中:系統(tǒng)在運行過程中,會產(chǎn)生會多事件,那么某些事件產(chǎn)生時,比如:電量改變、收發(fā)短信、撥打電話、屏幕解鎖、開機,系統(tǒng)會發(fā)送廣播,只要應(yīng)用程序接收到這條廣播,就知道系統(tǒng)發(fā)生了相應(yīng)的事件,從而執(zhí)行相應(yīng)的代碼。使用廣播接收者,就可以收聽廣播
  • 廣播的生命周期是怎樣的?
    • a.廣播接收者的生命周期非常短暫的,在接收到廣播的時候創(chuàng)建,onReceive()方法結(jié)束之后銷毀;
    • b.廣播接收者中不要做一些耗時的工作,否則會彈出 Application No Response錯誤對話框;
    • c.最好也不要在廣播接收者中創(chuàng)建子線程做耗時的工作,因為廣播接收者被銷毀后進程就成為了空進程,很容易被系統(tǒng)殺掉;
    • d.耗時的較長的工作最好放在服務(wù)中完成;

1.0.2.3 廣播有幾種形式?他們分別有什么特點,如何使用廣播?廣播是怎么實現(xiàn)不同進程之間通信的?

  • 廣播有幾種形式
    • 普通廣播:一種完全異步執(zhí)行的廣播,在廣播發(fā)出之后,所有的廣播接收器幾乎都會在同一時刻接收到這條廣播消息,因此它們接收的先后是隨機的。
    • 有序廣播:一種同步執(zhí)行的廣播,在廣播發(fā)出之后,同一時刻只會有一個廣播接收器能夠收到這條廣播消息,當這個廣播接收器中的邏輯執(zhí)行完畢后,廣播才會繼續(xù)傳遞,所以此時的廣播接收器是有先后順序的,且優(yōu)先級(priority)高的廣播接收器會先收到廣播消息。有序廣播可以被接收器截斷使得后面的接收器無法收到它。
    • 本地廣播:發(fā)出的廣播只能夠在應(yīng)用程序的內(nèi)部進行傳遞,并且廣播接收器也只能接收本應(yīng)用程序發(fā)出的廣播。
    • 粘性廣播:這種廣播會一直滯留,當有匹配該廣播的接收器被注冊后,該接收器就會收到此條廣播。
  • 廣播的兩種注冊形式技術(shù)博客大總結(jié)
    • 廣播的注冊有兩種方法:一種在活動里通過代碼動態(tài)注冊,另一種在配置文件里靜態(tài)注冊。兩種方式的相同點是都完成了對接收器以及它能接收的廣播值這兩個值的定義;不同點是動態(tài)注冊的接收器必須要在程序啟動之后才能接收到廣播,而靜態(tài)注冊的接收器即便程序未啟動也能接收到廣播,比如想接收到手機開機完成后系統(tǒng)發(fā)出的廣播就只能用靜態(tài)注冊了。
  • 動態(tài)注冊
    • 需要使用廣播接收者時,執(zhí)行注冊的代碼,不需要時,執(zhí)行解除注冊的代碼。安卓中有一些廣播接收者,必須使用代碼注冊,清單文件注冊是無效的。
      public class MainActivity extends Activity {
          private IntentFilter intentFilter;
          private NetworkChangeReceiver networkChangeReceiver;
          @Override
          protected void onCreate(Bundle savedInstanceState) {
                 super.onCreate(savedInstanceState);
                 setContentView(R.layout.activity_main);
                 intentFilter = new IntentFilter();
                 intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
                 networkChangeReceiver = new NetworkChangeReceiver();
                 registerReceiver(networkChangeReceiver, intentFilter);
          }
          @Override
          protected void onDestroy() {
                 super.onDestroy();
                 unregisterReceiver(networkChangeReceiver);
          }
          class NetworkChangeReceiver extends BroadcastReceiver {
                  @Override
                  public void onReceive(Context context, Intent intent) {
                       Toast.makeText(context, "network changes",Toast.LENGTH_SHORT).show();
                  }
          }
      }
      
  • 靜態(tài)注冊
    • 可以使用清單文件注冊。廣播一旦發(fā)出,系統(tǒng)就會去所有清單文件中尋找,哪個廣播接收者的action和廣播的action是匹配的,如果找到了,就把該廣播接收者的進程啟動起來。

1.0.2.8 Fragment與Activity之間是如何傳值的?Fragment與Fragment之間是如何傳值的?

  • Fragment與Activity之間是如何傳值的?
    • 1.Activity向Fragment傳值:
      • 步驟:
      • 要傳的值,放到bundle對象里;
      • 在Activity中創(chuàng)建該Fragment的對象fragment,通過調(diào)用
      • fragment.setArguments()傳遞到fragment中;
      • 在該Fragment中通過調(diào)用getArguments()得到bundle對象,就能得到里面的值。
    • 2.Fragment向Activity傳值:
      • 第一種:
        • 在Activity中調(diào)用getFragmentManager()得到fragmentManager,,調(diào)用findFragmentByTag(tag)或者通過findFragmentById(id)
        • FragmentManager fragmentManager = getFragmentManager();
        • Fragment fragment = fragmentManager.findFragmentByTag(tag);
      • 第二種:
        • 通過回調(diào)的方式,定義一個接口(可以在Fragment類中定義),接口中有一個空的方法,在fragment中需要的時候調(diào)用接口的方法,值可以作為參數(shù)放在這個方法中,然后讓Activity實現(xiàn)這個接口,必然會重寫這個方法,這樣值就傳到了Activity中
  • Fragment與Fragment之間是如何傳值的?
    • 第一種:
      • 通過findFragmentByTag得到另一個的Fragment的對象,這樣就可以調(diào)用另一個的方法了。
    • 第二種:
    • 第三種:
      • 通過setArguments,getArguments的方式。

1.0.2.9 Activity創(chuàng)建Fragment的方式是什么?FragmentPageAdapter和FragmentPageStateAdapter的區(qū)別?

  • Activity創(chuàng)建Fragment的方式是什么?
    • 靜態(tài)創(chuàng)建具體步驟
      • 首先我們同樣需要注冊一個xml文件,然后創(chuàng)建與之對應(yīng)的java文件,通過onCreatView()的返回方法進行關(guān)聯(lián),最后我們需要在Activity中進行配置相關(guān)參數(shù)即在Activity的xml文件中放上fragment的位置。
    • 動態(tài)創(chuàng)建具體步驟
      • (1)創(chuàng)建待添加的碎片實例
      • (2)獲取FragmentManager,在活動中可以直接通過調(diào)用 getSupportFragmentManager()方法得到。
      • (3)開啟一個事務(wù),通過調(diào)用beginTransaction()方法開啟。
      • (4)向容器內(nèi)添加或替換碎片,一般使用repalce()方法實現(xiàn),需要傳入容器的id和待添加的碎片實例。
      • (5)提交事務(wù),調(diào)用commit()方法來完成。
  • FragmentPageAdapter和FragmentPageStateAdapter的區(qū)別?
    • FragmnetPageAdapter在每次切換頁面時,只是將Fragment進行分離,適合頁面較少的Fragment使用以保存一些內(nèi)存,對系統(tǒng)內(nèi)存不會多大影響
    • FragmentPageStateAdapter在每次切換頁面的時候,是將Fragment進行回收,適合頁面較多的Fragment使用,這樣就不會消耗更多的內(nèi)存

1.0.3.0 fragment 特點?說一下Fragment的生命周期?如何解決getActivity為null的異常問題?

  • fragment 特點
    • Fragment可以作為Activity界面的一部分組成出現(xiàn);
    • 可以在一個Activity中同時出現(xiàn)多個Fragment,并且一個Fragment也可以在多個Activity中使用;
    • 在Activity運行過程中,可以添加、移除或者替換Fragment;
    • Fragment可以響應(yīng)自己的輸入事件,并且有自己的生命周期,它們的生命周期會受宿主Activity的生命周期影響。
  • Fragment從創(chuàng)建到銷毀整個生命周期中涉及到的方法依次為:
    • onAttach()->onCreate()->onCreateView()->onActivityCreated()->onStart()->onResume()->onPause()->onStop()->onDestroyView()->onDestroy()->onDetach(),其中和Activity有不少名稱相同作用相似的方法,而不同的方法有:
      • onAttach():當Fragment和Activity建立關(guān)聯(lián)時調(diào)用
      • onCreateView():當Fragment創(chuàng)建視圖時調(diào)用
      • onActivityCreated():當與Fragment相關(guān)聯(lián)的Activity完成onCreate()之后調(diào)用
      • onDestroyView():在Fragment中的布局被移除時調(diào)用
      • onDetach():當Fragment和Activity解除關(guān)聯(lián)時調(diào)用
  • 如何解決getActivity為null的異常問題技術(shù)博客大總結(jié)
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        activity = (PhoneNumActivity) context;
    }
    
    @Override
    public void onDetach() {
        super.onDetach();
        activity = null;
    }
    

1.0.3.1 在fragment中為什么有時getActivity()會為null?Fragment試圖為什么有的時候會重疊,怎么產(chǎn)生的,又如何解決?

  • getActivity()空指針:
    • 這種情況一般發(fā)生在在異步任務(wù)里調(diào)用getActivity(),而Fragment已經(jīng)onDetach(),此時就會有空指針,解決方案是在Fragment里使用一個全局變量mActivity,在onAttach()方法里賦值,這樣可能會引起內(nèi)存泄漏,但是異步任務(wù)沒有停止的情況下本身就已經(jīng)可能內(nèi)存泄漏,相比直接crash,這種方式顯得更妥當一些。
  • Fragment視圖重疊:
    • 在類onCreate()的方法加載Fragment,并且沒有判斷saveInstanceState==null或if(findFragmentByTag(mFragmentTag) == null),導(dǎo)致重復(fù)加載了同一個Fragment導(dǎo)致重疊。(PS:replace情況下,如果沒有加入回退棧,則不判斷也不會造成重疊,但建議還是統(tǒng)一判斷下)
    @Override 
    protected void onCreate(@Nullable Bundle savedInstanceState) {
    // 在頁面重啟時,F(xiàn)ragment會被保存恢復(fù),而此時再加載Fragment會重復(fù)加載,導(dǎo)致重疊 ;
        if(saveInstanceState == null){
        // 或者 if(findFragmentByTag(mFragmentTag) == null)
           // 正常情況下去 加載根Fragment 
        } 
    }
    

1.0.3.2 為什么fragment傳遞數(shù)據(jù)不用構(gòu)造方法傳遞?FragmentManager , add 和 replace 有什么區(qū)別?

  • 為什么fragment傳遞數(shù)據(jù)不用構(gòu)造方法傳遞?
    • activity給fragment傳遞數(shù)據(jù)一般不通過fragment的構(gòu)造方法來傳遞,會通過setArguments來傳遞,因為當橫豎屏會調(diào)用fragment的空參構(gòu)造函數(shù),數(shù)據(jù)丟失。
  • FragmentManager , add 和 replace 有什么區(qū)別?
    • 使用FragmentTransaction的時候,它提供了這樣兩個方法,一個add,一個replace,add和replace影響的只是界面,而控制回退的,是事務(wù)。
    • add 是把一個fragment添加到一個容器container里。replace是先remove掉相同id的所有fragment,然后在add當前的這個fragment。技術(shù)博客大總結(jié)
    • 在大部分情況下,這兩個的表現(xiàn)基本相同。因為,一般,咱們會使用一個FrameLayout來當容器,而每個Fragment被add 或者 replace 到這個FrameLayout的時候,都是顯示在最上層的。所以你看到的界面都是一樣的。但是,使用add的情況下,這個FrameLayout其實有2層,多層肯定要比一層的來得浪費,所以還是推薦使用replace。當然有時候還是需要使用add的。比如要實現(xiàn)輪播圖的效果,每個輪播圖都是一個獨立的Fragment,而他的容器FrameLayout需要add多個Fragment,這樣他就可以根據(jù)提供的邏輯進行輪播了。而至于返回鍵的時候,這個跟事務(wù)有關(guān),跟使用add還是replace沒有任何關(guān)系。
    • replace()方法會將被替換掉的那個Fragment徹底地移除掉,因此最好的解決方案就是使用hide()和show()方法來隱藏和顯示Fragment,這就不會讓Fragment的生命周期重走一遍了。

1.0.3.9 Activitiy啟動流程中performLaunchActivity的作用?Activity啟動流程中handleResumeActivity的作用?

  • Activitiy啟動流程中performLaunchActivity的作用?
    • 從ActivityClientRecord中獲取到待啟動的Activity的組件信息
    • 使用類加載器創(chuàng)建Activity對象
    • 通過LoadedApk的方法創(chuàng)建Applicayiton對象,該對象唯一,不會重復(fù)創(chuàng)建。
    • 會創(chuàng)建ContextImpl并且建立Context和Activity的聯(lián)系,以及創(chuàng)建PhoneWindow,建立Window和Activity的聯(lián)系。
    • 調(diào)用Activity的onCreate()
  • Activity啟動流程中handleResumeActivity的作用?
    • 執(zhí)行onStart()、onResume()—利用Instrucmentation
    • 獲取Window
    • 創(chuàng)建DecorView、設(shè)置為不可見INVISIBLE、建立DecorView和Activity的聯(lián)系。
    • 獲取Activity的WindowManager
    • 調(diào)用WindowManager.addView(decorView, ...)將DecorView添加到WM中,完成顯示的工作。
    • image
  • 何時將DecorView設(shè)置為VISIBLE?并且顯示出來?技術(shù)博客大總結(jié)
    • 也是在handleResumeActivity中
    • 現(xiàn)將DecorView設(shè)置為不可見
    • wm.addView(): 將DecorView添加到Window總
    • 然后執(zhí)行makeVisible讓DecorView可見
    • image

1.0.4.0 Intent是什么?Intent可以傳遞哪些數(shù)據(jù)?傳遞對象的時候為什么要實例化?

  • Intent是一種運行時綁定(run-time binding)機制,它能在程序運行過程中連接兩個不同的組件。
    • 舉例:比如,有一個Activity希望打開網(wǎng)頁瀏覽器查看某一網(wǎng)頁的內(nèi)容,那么這個Activity只需要發(fā)出 WEB_SEARCH_ACTION給Android
    • Android就會根據(jù)Intent的請求內(nèi)容,查詢各組件注冊時聲明的 IntentFilter,找到網(wǎng)頁瀏覽器的Activity來瀏覽網(wǎng)頁
  • Intent可以傳遞的數(shù)據(jù)基本數(shù)據(jù)類型的數(shù)據(jù),數(shù)組,還有集合,還有序列化的對象
    • 序列化:表示將一個對象轉(zhuǎn)換成可存儲或可傳輸?shù)臓顟B(tài)
    • Android中序列化對象方式:技術(shù)博客大總結(jié)
      • 第一種:JAVA中的Serialize機制,譯成串行化、序列化……,其作用是能將數(shù)據(jù)對象存入字節(jié)流當中,在需要時重新生成對象。主要應(yīng)用是利用外部存儲設(shè) 備保存對象狀 態(tài),以及通過網(wǎng)絡(luò)傳輸對象等。
      • 第二種:在Android系統(tǒng)中,定位為針對內(nèi)存受限的設(shè)備,因此對性能要求更高,另外系統(tǒng)中采用了新的IPC(進程間通信)機制,必然要求使用性能更出色的對象傳輸方式。

1.0.1.2 Activity如與Service通信?Service的生命周期與啟動方法由什么區(qū)別?

可以通過bindService的方式,先在Activity里實現(xiàn)一個ServiceConnection接口,并將該接口傳遞給bindService()方法,在ServiceConnection接口的onServiceConnected()方法
里執(zhí)行相關(guān)操作。

Service的生命周期與啟動方法由什么區(qū)別?
    startService():開啟Service,調(diào)用者退出后Service仍然存在。
    bindService():開啟Service,調(diào)用者退出后Service也隨即退出。

Service生命周期:
    只是用startService()啟動服務(wù):onCreate() -> onStartCommand() -> onDestory
    只是用bindService()綁定服務(wù):onCreate() -> onBind() -> onUnBind() -> onDestory
    同時使用startService()啟動服務(wù)與bindService()綁定服務(wù):onCreate() -> onStartCommnad() -> onBind() -> onUnBind() -> onDestory

1.1.0.4 廣播有哪些注冊方式?有什么區(qū)別?廣播發(fā)送和接收原理是什么[binder如何運作的]?

  • 廣播有哪些注冊方式?
    • 靜態(tài)注冊:常駐系統(tǒng),不受組件生命周期影響,即便應(yīng)用退出,廣播還是可以被接收,耗電、占內(nèi)存。
    • 動態(tài)注冊:非常駐,跟隨組件的生命變化,組件結(jié)束,廣播結(jié)束。在組件結(jié)束前,需要先移除廣播,否則容易造成內(nèi)存泄漏。
  • 廣播發(fā)送和接收原理是什么[binder如何運作的]?
    • 繼承BroadcastReceiver,重寫onReceive()方法。
    • 通過Binder機制向ActivityManagerService注冊廣播。
    • 通過Binder機制向ActivityMangerService發(fā)送廣播。
    • ActivityManagerService查找符合相應(yīng)條件的廣播(IntentFilter/Permission)的BroadcastReceiver,將廣播發(fā)送到BroadcastReceiver所在的消息隊列中。
    • BroadcastReceiver所在消息隊列拿到此廣播后,回調(diào)它的onReceive()方法。

1.0.4.1 mipmap系列中xxxhdpi、xxhdpi、xhdpi、hdpi、mdpi和ldpi存在怎樣的關(guān)系?

  • 表示不同密度的圖片資源,像素從高到低依次排序為xxxhdpi>xxhdpi>xhdpi>hdpi>mdpi>ldpi,根據(jù)手機的dpi不同加載不同密度的圖片

1.0.4.2 res目錄和assets目錄的區(qū)別?

  • assets:不會在 R文件中生成相應(yīng)標記,存放到這里的資源在打包時會打包到程序安裝包中。(通過 AssetManager 類訪問這些文件)
  • res:會在 R 文件中生成 id標記,資源在打包時如果使用到則打包到安裝包中,未用到不會打入安裝包中。
  • res/anim:存放動畫資源
  • res/raw:和 asset下文件一樣,打包時直接打入程序安裝包中(會映射到 R文件中)

1.0.4.3 Context是什么?Context有哪些類型,分別作用是什么?Context下有哪些子類?哪些場景只能用activity上下文?

  • Context是什么?
    • Context是一個抽象基類。在翻譯為上下文,也可以理解為環(huán)境,是提供一些程序的運行環(huán)境基礎(chǔ)信息。
  • Context有哪些類型,分別作用是什么?
    • Context下有兩個子類,ContextWrapper是上下文功能的封裝類,而ContextImpl則是上下文功能的實現(xiàn)類。
    • ContextWrapper又有三個直接的子類,ContextThemeWrapper、Service和Application。其中,ContextThemeWrapper是一個帶主題的封裝類,而它有一個直接子類就是Activity,所以Activity和Service以及Application的Context是不一樣的,只有Activity需要主題,Service不需要主題。
  • Context下有哪些子類,主要是干什么的?
    • Context一共有三種類型,分別是Application、Activity和Service。
    • 這三個類雖然分別各種承擔著不同的作用,但它們都屬于Context的一種,而它們具體Context的功能則是由ContextImpl類去實現(xiàn)的,因此在絕大多數(shù)場景下,Activity、Service和Application這三種類型的Context都是可以通用的。
    • 不過有幾種場景比較特殊,比如啟動Activity,還有彈出Dialog。出于安全原因的考慮,Android是不允許Activity或Dialog憑空出現(xiàn)的,一個Activity的啟動必須要建立在另一個Activity的基礎(chǔ)之上,也就是以此形成的返回棧。而Dialog則必須在一個Activity上面彈出(除非是系統(tǒng)級別吐司),因此在這種場景下,我們只能使用Activity類型的Context,否則將會出錯。

1.0.4.4 ActivityThread的main()的流程大概是怎么樣的?

  • ActivityThread的main()的流程大概是怎么樣的?
    • image

1.0.5.0 序列化的方式有哪些?效率對比有何優(yōu)勢?如何做性能上分析的?

  • 序列化的方式有哪些
    • Parcelable
      • Parcelable是Android特有的一個實現(xiàn)序列化的接口,在Parcel內(nèi)部包裝了可序列化的數(shù)據(jù),可以在Binder中自由傳輸。序列化的功能由writeToParcel方法來完成,最終通過Parcel的一系列write方法完成。反序列化功能由CREAOR來完成,其內(nèi)部標明了如何創(chuàng)建序列化對象和數(shù)組,并通過Parcel的一系列read方法來完成反序列化的過程。
    • Serializable
      • Serializable是Java提供的一個序列化接口,是一個空接口,用于標示對象是否可以支持序列化,通過ObjectOutputStrean及ObjectInputStream實現(xiàn)序列化和反序列化的過程。注意可以為需要序列化的對象設(shè)置一個serialVersionUID,在反序列化的時候系統(tǒng)會檢測文件中的serialVersionUID是否與當前類的值一致,如果不一致則說明類發(fā)生了修改,反序列化失敗。因此對于可能會修改的類最好指定serialVersionUID的值。

1.0.5.9 界面的刷新為什么需16.6ms?畫面的顯示需要哪些步驟?界面保持不變時還會16.6ms刷新一次屏幕嗎?

  • 界面的刷新為什么需16.6ms?
    • 系統(tǒng)每16.6ms會發(fā)出一個VSYNC信號,發(fā)出信號后,才會開始進行測量、布局和繪制。
    • 發(fā)出VSYNC信號時,還會將此時顯示器的buffer緩沖區(qū)的數(shù)據(jù)取出,并顯示在屏幕上。
  • 畫面的顯示需要哪些步驟?
    • CPU計算數(shù)據(jù)(View樹遍歷并執(zhí)行三大流程:測量、布局和繪制),然后將數(shù)據(jù)交給GPU“
    • GPU渲染處理,然后將數(shù)據(jù)放到Buffer中。
    • 顯示屏(display)從buffer中取出數(shù)據(jù),并進行顯示。
  • 界面保持不變時還會16.6ms刷新一次屏幕嗎?技術(shù)博客大總結(jié)
    • 對于底層顯示器,每間隔16.6ms接收到VSYNC信號時,就會用buffer中數(shù)據(jù)進行一次顯示。所以一定會刷新。
  • 界面刷新的本質(zhì)流程
    • 通過ViewRootImpl的scheduleTraversals()進行界面的三大流程。
    • 調(diào)用到scheduleTraversals()時不會立即執(zhí)行,而是將該操作保存到待執(zhí)行隊列中。并給底層的刷新信號注冊監(jiān)聽。
    • 當VSYNC信號到來時,會從待執(zhí)行隊列中取出對應(yīng)的scheduleTraversals()操作,并將其加入到主線程的消息隊列中。
    • 主線程從消息隊列中取出并執(zhí)行三大流程: onMeasure()-onLayout()-onDraw()

1.0.6.0 Android中日志級別有哪幾種?開發(fā)中需要注意什么問題,打印日志源碼分析原理是什么?

  • Android中日志級別有哪幾種?
    • 1.Log.v 的輸出顏色為黑色的,輸出大于或等于VERBOSE日志級別的信息,也就是可見級別,一般是最低的信息提示
    • 2.Log.d的輸出顏色是藍色的,也就是調(diào)式級別,一般不會中止程序,一般是程序員為了調(diào)試而打印的log
    • 3.Log.i的輸出為綠色,輸出大于或等于INFO日志級別的信息,也就是信息界級別,不會中止程序,一般是系統(tǒng)中執(zhí)行操作的信息提示
    • 4.Log.w的輸出為橙色, 輸出大于或等于WARN日志級別的信息,也就是警告級別,一般不會中止程序,但是可能會影響程序執(zhí)行結(jié)果
    • 5.Log.e的輸出為紅色,僅輸出ERROR日志級別的信息,也就是錯誤級別,一般會中止程序運行,是最嚴重的Log級別。
    • 解釋:
      • verbose
      • debug調(diào)試
      • info信息
      • warn警告
      • error誤差
  • 通過查看源代碼我們發(fā)現(xiàn)Log類中所有的靜態(tài)日志方法Log.v(),Log.d(),Log.i(),Log.w(),Log.e()等方法都是底層都是調(diào)用了println方法,然后在源碼中查看,其實其內(nèi)部調(diào)用的是println_native方法,也就是通過JNI調(diào)用底層的c++輸出日志。

關(guān)于其他內(nèi)容介紹

01.關(guān)于博客匯總鏈接

02.關(guān)于我的博客

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

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

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