01.Android之基礎組件問題

目錄介紹

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

好消息

  • 博客筆記大彙總【15年10月到至今】,包括Java基礎及深刻知識點,Android技術博客,Python學習筆記等等,還包括平時開發中遇到的bug彙總,固然也在工做之餘收集了大量的面試題,長期更新維護而且修正,持續完善……開源的文件是markdown格式的!同時也開源了生活博客,從12年起,積累共計500篇[近100萬字],將會陸續發表到網上,轉載請註明出處,謝謝!
  • 連接地址:https://github.com/yangchong211/YCBlogs
  • 若是以爲好,能夠star一下,謝謝!固然也歡迎提出建議,萬事起於忽微,量變引發質變!全部的筆記將會更新到GitHub上,同時保持更新,歡迎同行提出或者push不一樣的見解或者筆記!

1.0.0.1 說下Activity的生命週期?屏幕旋轉時生命週期?異常條件會調用什麼方法?

  • 在Activity的生命週期涉及到七大方法,分別是:
    • onCreate()表示Activity 正在建立,常作初始化工做,如setContentView界面資源、初始化數據
    • onStart()表示Activity 正在啓動,這時Activity 可見但不在前臺,沒法和用戶交互
    • onResume()表示Activity 得到焦點,此時Activity 可見且在前臺並開始活動
    • onPause()表示Activity 正在中止,可作 數據存儲、中止動畫等操做
    • onStop()表示activity 即將中止,可作稍微重量級回收工做,如取消網絡鏈接、註銷廣播接收器等
    • onDestroy()表示Activity 即將銷燬,常作回收工做、資源釋放
    • onRestart()表示當Activity由後臺切換到前臺,由不可見到可見時會調用,表示Activity 從新啓動
  • 屏幕旋轉時生命週期
    • 屏幕旋轉時候,若是不作任何處理,activity會通過銷燬到重建的過程。通常這種效果都不是想要的。好比視頻播放器就常常會涉及屏幕旋轉場景。技術博客大總結
    • 第一種狀況:當前的Activity不銷燬【設置Activity的android:configChanges="orientation|keyboardHidden|screenSize"時,切屏不會從新調用各個生命週期,只會執行onConfigurationChanged方法】
      <activity
          android:name=".activity.VideoDetailActivity"
          android:configChanges="orientation|keyboardHidden|screenSize"
          android:screenOrientation="portrait"/>
      • 執行該方法
      //重寫旋轉時方法,不銷燬activity
      @Override
      public void onConfigurationChanged(Configuration newConfig) {
      	super.onConfigurationChanged(newConfig);
      }
    • 第二種狀況:銷燬當前的Activity後重建,這種也儘可能避免。【不設置Activity的android:configChanges時,切屏會從新調用各個生命週期,默認首先銷燬當前activity,而後從新加載】
  • 異常條件會調用什麼方法
    • 當非人爲終止Activity時,好比系統配置發生改變時致使Activity被殺死並從新建立、資源內存不足致使低優先級的Activity被殺死,會調用 onSavaInstanceState() 來保存狀態。該方法調用在onStop以前,但和onPause沒有時序關係。
    • 有人會問,onSaveInstanceState()與onPause()的區別,onSaveInstanceState()適用於對臨時性狀態的保存,而onPause()適用於對數據的持久化保存。
    • 當異常崩潰後App又重啓了,這個時候會走onRestoreInstanceState()方法,能夠在該方法中取出onSaveInstanceState()保存的狀態數據。
  • 何時會引發異常生命週期
    • 資源相關的系統配置發生改變或者資源不足:例如屏幕旋轉,當前Activity會銷燬,而且在onStop以前回調onSaveInstanceState保存數據,在從新建立Activity的時候在onStart以後回調onRestoreInstanceState。其中Bundle數據會傳到onCreate(不必定有數據)和onRestoreInstanceState(必定有數據)。技術博客大總結
    • 防止屏幕旋轉的時候重建,在清單文件中添加配置:android:configChanges="orientation"

1.0.0.2 後臺的Activity被系統回收怎麼辦?說一下onSaveInstanceState()和onRestoreInstanceState()方法特色?

  • 後臺的Activity被系統回收怎麼辦?
    • Activity中提供了一個 onSaveInstanceState()回調方法,這個方法會保證必定在活動被回收以前調用,能夠經過這個方法來解決活動被回收時臨時數據得不到保存的問題。onSaveInstanceState()方法會攜帶一個Bundle類型的參數,Bundle提供了一系列的方法用於保存數據,好比可使用putString()方法保存字符串,使用putInt()方法保存整型數據。每一個保存方法須要傳入兩個參數,第一個參數是鍵,用於後面從 Bundle中取值,第二個參數是真正要保存的內容。技術博客大總結
  • 說一下onSaveInstanceState()和onRestoreInstanceState()方法特色?
    • Activity的 onSaveInstanceState()和onRestoreInstanceState()並非生命週期方法,它們不一樣於onCreate()、onPause()等生命週期方法,它們並不必定會被觸發。
      //保存數據
      @Override
      protected void onSaveInstanceState(Bundle outBundle) {
      	super.onSaveInstanceState(outBundle);
       	outBundle.putBoolean("Change", mChange);
      }
      
      //取出數據
      @Override 
      protected void onRestoreInstanceState(Bundle savedInstanceState) {
      	super.onRestoreInstanceState(savedInstanceState);
      	mChange = savedInstanceState.getBoolean("Change");
      }
      
      //或者在onCreate方法取數據也能夠
      //onCreate()方法其實也有一個Bundle類型的參數。這個參數在通常狀況下都是null,
      //可是當活動被系統回收以前有經過 onSaveInstanceState()方法來保存數據的話,這個參就會帶有以前所保存的所有數據
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          if (savedInstanceState != null) {
              String data = savedInstanceState.getString("data");
          }
      }
  • 何時會觸發走這兩個方法?
    • 當應用遇到意外狀況(如:內存不足、用戶直接按Home鍵)由系統銷燬一個Activity,onSaveInstanceState() 會被調用。可是當用戶主動去銷燬一個Activity時,例如在應用中按返回鍵,onSaveInstanceState()就不會被調用。除非該activity是被用戶主動銷燬的,一般onSaveInstanceState()只適合用於保存一些臨時性的狀態,而onPause()適合用於數據的持久化保存。
  • onSaveInstanceState()被執行的場景有哪些?
    • 系統不知道你按下HOME後要運行多少其餘的程序,天然也不知道activityA是否會被銷燬,所以系統都會調用onSaveInstanceState(),讓用戶有機會保存某些非永久性的數據。如下幾種狀況的分析都遵循該原則當用戶按下HOME鍵時
      • 長按HOME鍵,選擇運行其餘的程序時
      • 鎖屏時
      • 從activity A中啓動一個新的activity時
      • 屏幕方向切換時

1.0.0.3 如何避免配置改變時Activity重建?優先級低的Activity在內存不足被回收後怎樣作能夠恢復到銷燬前狀態?

  • 如何避免配置改變時Activity重建
    • 爲了不因爲配置改變致使Activity重建,可在AndroidManifest.xml中對應的Activity中設置android:configChanges="orientation|screenSize"。此時再次旋轉屏幕時,該Activity不會被系統殺死和重建,只會調用onConfigurationChanged。所以,當配置程序須要響應配置改變,指定configChanges屬性,重寫onConfigurationChanged方法便可。
    • 使用場景,好比視頻播放器橫豎屏切換播放視頻,就須要設置這種屬性。具體能夠看我封裝的視頻播放器庫,地址:https://github.com/yangchong211/YCVideoPlayer
  • 優先級低的Activity在內存不足被回收後怎樣作能夠恢復到銷燬前狀態
    • 優先級低的Activity在內存不足被回收後從新打開會引起Activity重建。Activity被從新建立時會調用onRestoreInstanceState(該方法在onStart以後),並將onSavaInstanceState保存的Bundle對象做爲參數傳到onRestoreInstanceState與onCreate方法。所以可經過onRestoreInstanceState(Bundle savedInstanceState)和onCreate((Bundle savedInstanceState)來判斷Activity是否被重建,並取出數據進行恢復。但須要注意的是,在onCreate取出數據時必定要先判斷savedInstanceState是否爲空。
  • 如何判斷activity的優先級?技術博客大總結
    • 除了在棧頂的activity,其餘的activity都有可能在內存不足的時候被系統回收,一個activity越處於棧底,被回收的可能性越大.若是有多個後臺進程,在選擇殺死的目標時,採用最近最少使用算法(LRU)。

1.0.0.4 app切換到後臺,當前activity會走onDestory方法嗎?通常在onstop方法裏作什麼?什麼狀況會致使app會被殺死,這時候會走onDestory嗎?

  • app切換到後臺,當前activity會走onDestory方法嗎?
    • 不會走onDestory方法,會前後走onPause和onStop方法。
  • 通常在onstop方法裏作什麼?
    • 好比。寫輪播圖的時候,會在onstop方法裏寫上暫停輪播圖無限輪播,在onStart方法中會開啓自動無限輪播。
    • 再好比,寫視頻播放器的時候,當app切換到後臺,則須要中止視頻播放,也是能夠在onstop中處理的。關於視頻播放器,能夠看我這個開源項目:視頻播放器
  • 什麼狀況會致使app會被殺死,這時候會走onDestory嗎?
    • 系統資源不足,會致使app意外被殺死。應用只有在進程存活的狀況下才會按照正常的生命週期進行執行,若是進程忽然被kill掉,至關於System.exit(0); 進程被殺死,根本不會走(activity,fragment)生命週期。只有在進程不被kill掉,正常狀況下才會執行ondestory()方法。
  • activity被回收如何恢復
    • 當系統內存不足時, activity會被回收,咱們其實能夠覆寫onSaveInstanceState()方法。onSaveInstanceState()方法接受一個Bundle類型的參數, 開發者能夠將狀態數據存儲到這個Bundle對象中,這樣即便activity被系統摧毀,當用戶從新啓動這個activity而調用它的onCreate()方法時,上述的Bundle對象會做爲實參傳遞給onCreate()方法,開發者能夠從Bundle對象中取出保存的數據, 而後利用這些數據將activity恢復到被摧毀以前的狀態。

1.0.0.5 Activity的啓動過程是有幾種方式?從桌面launcher上點擊應用圖標會幹啥,調用startActivty()又會作什麼?

  • Activity的啓動過程是怎樣的,有幾種方式?
    • 注意是啓動過程,不是生命週期。技術博客大總結
    • app啓動的過程有兩種狀況,第一種是從桌面launcher上點擊相應的應用圖標,第二種是在activity中經過調用startActivity來啓動一個新的activity。
  • 從桌面launcher上點擊應用圖標會幹啥,調用startActivty()又會作什麼?
    • 建立一個新的項目,默認的根activity都是MainActivity,而全部的activity都是保存在堆棧中的,啓動一個新的activity就會放在上一個activity上面,而咱們從桌面點擊應用圖標的時候,因爲launcher自己也是一個應用,當咱們點擊圖標的時候,系統就會調用startActivitySately(),通常狀況下,咱們所啓動的activity的相關信息都會保存在intent中,好比action,category等等。
    • 咱們在安裝這個應用的時候,系統也會啓動一個PackaManagerService的管理服務,這個管理服務會對AndroidManifest.xml文件進行解析,從而獲得應用程序中的相關信息,好比service,activity,Broadcast等等,而後得到相關組件的信息。
    • 當咱們點擊應用圖標的時候,就會調用startActivitySately()方法,而這個方法內部則是調用startActivty(),而startActivity()方法最終仍是會調用startActivityForResult()這個方法。而在startActivityForResult()這個方法。由於startActivityForResult()方法是有返回結果的,因此係統就直接給一個-1,就表示不須要結果返回了。
    • 而startActivityForResult()這個方法實際是經過Instrumentation類中的execStartActivity()方法來啓動activity,Instrumentation這個類主要做用就是監控程序和系統之間的交互。而在這個execStartActivity()方法中會獲取ActivityManagerService的代理對象,經過這個代理對象進行啓動activity。啓動會就會調用一個checkStartActivityResult()方法,若是說沒有在配置清單中配置有這個組件,就會在這個方法中拋出異常了。
    • 固然最後是調用的是Application.scheduleLaunchActivity()進行啓動activity,而這個方法中經過獲取獲得一個ActivityClientRecord對象,而這個ActivityClientRecord經過handler來進行消息的發送,系統內部會將每個activity組件使用ActivityClientRecord對象來進行描述,而ActivityClientRecord對象中保存有一個LoaderApk對象,經過這個對象調用handleLaunchActivity來啓動activity組件,而頁面的生命週期方法也就是在這個方法中進行調用。

1.0.0.6 說下Activity的四種啓動模式?singleTop和singleTask的區別以及應用場景?任務棧的做用是什麼?

  • Activity的四種啓動模式
    • standard標準模式:每次啓動一個Activity就會建立一個新的實例
    • singleTop棧頂複用模式:若是新Activity已經位於任務棧的棧頂,就不會從新建立,並回調 onNewIntent(intent) 方法
    • singleTask棧內複用模式:只要該Activity在一個任務棧中存在,都不會從新建立,並回調 onNewIntent(intent) 方法。若是不存在,系統會先尋找是否存在須要的棧,若是不存在該棧,就建立一個任務棧,並把該Activity放進去;若是存在,就會建立到已經存在的棧中
    • singleInstance單實例模式:具備此模式的Activity只能單獨位於一個任務棧中,且此任務棧中只有惟一一個實例
  • singleTop和singleTask的區別以及應用場景
    • singleTop:同個Activity實例在棧中能夠有多個,便可能重複建立;該模式的Activity會默認進入啓動它所屬的任務棧,即不會引發任務棧的變動;爲防止快速點擊時屢次startActivity,能夠將目標Activity設置爲singleTop
    • singleTask:同個Activity實例在棧中只有一個,即不存在重複建立;可經過android:taskAffinity設定該Activity須要的任務棧,便可能會引發任務棧的變動;經常使用於主頁和登錄頁
  • singleTop或singleTask的Activity在如下狀況會回調onNewIntent()
    • singleTop:若是新Activity已經位於任務棧的棧頂,就不會從新建立,並回調 onNewIntent(intent) 方法
    • singleTask:只要該Activity在一個任務棧中存在,都不會從新建立,並回調 onNewIntent(intent) 方法
  • 任務棧的做用是什麼?技術博客大總結
    • 它是存放 Activity 的引用的,Activity不一樣的啓動模式,對應不一樣的任務棧的存放;可經過 getTaskId()來獲取任務棧的 ID,若是前面的任務棧已經清空,新開的任務棧ID+1,是自動增加的;首先來看下Task的定義,Google是這樣定義Task的:Task其實是一個Activity棧,一般用戶感覺的一個Application就是一個Task。從這個定義來看,Task跟Service或者其餘Components是沒有任何聯繫的,它只是針對Activity而言的。

1.0.0.7 兩個Activity之間怎麼傳遞數據?intent和bundle有什麼區別?爲何有了intent還要設計bundle?

  • 兩個Activity之間怎麼傳遞數據?
    • 基本數據類型能夠經過Intent傳遞數據
    • 把數據封裝至intent對象中
      Intent intent = new Intent(content, MeActivity.class);
      intent.putExtra("goods_id", goods_id);
      content.startActivity(intent);
    • 把數據封裝至bundle對象中技術博客大總結
    • 把bundle對象封裝至intent對象中
      Bundle bundle = new Bundle();
      bundle.putString("malename", "李志");
      intent.putExtras(bundle);
      startActivity(intent);
  • intent和bundle有什麼區別?
    • Intent傳遞數據和Bundle傳遞數據是一回事,Intent傳遞時內部仍是調用了Bundle。
      public @NonNull Intent putExtra(String name, String value) {
          if (mExtras == null) {
              mExtras = new Bundle();
          }
          mExtras.putString(name, value);
          return this;
      }
  • 爲何有了intent還要設計bundle?
    • 二者比較
      • Bundle只是一個信息的載體,內部其實就是維護了一個Map<String,Object>。
      • Intent負責Activity之間的交互,內部是持有一個Bundle的。
    • bundle使用場景
      • Fragment之間傳遞數據;好比,某個Fragment中點擊按鈕彈出一個DialogFragment。最便捷的方式就是經過Fragment.setArguments(args)傳遞參數。
      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:對應singleTop啓動模式
    • FLAG_ACTIVITY_NEW_TASK :對應singleTask模式

1.0.1.0 同一程序不一樣的Activity是否能夠放在不一樣的Task任務棧中?

  • 同一程序不一樣的Activity是否能夠放在不一樣的Task任務棧中?
    • 能夠的。好比:啓動模式裏有個Singleinstance,能夠運行在另外的單獨的任務棧裏面。用這個模式啓動的activity,在內存中只有一份,這樣就不會重複的開啓。
    • 也能夠在激活一個新的activity時候,給intent設置flag,Intent的flag添加FLAG_ACTIVITY_NEW_TASK,這個被激活的activity就會在新的task棧裏面

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

  • Service分爲兩種
    • 本地服務,屬於同一個應用程序,經過startService來啓動或者經過bindService來綁定而且獲取代理對象。若是隻是想開個服務在後臺運行的話,直接startService便可,若是須要相互之間進行傳值或者操做的話,就應該經過bindService。
    • 遠程服務(不一樣應用程序之間),經過bindService來綁定而且獲取代理對象。
  • 對應的生命週期以下:
    • context.startService() ->onCreate()- >onStartCommand()->Service running--調用context.stopService() ->onDestroy()
    • context.bindService()->onCreate()->onBind()->Service running--調用>onUnbind() -> onDestroy()
  • 注意
    • Service默認是運行在main線程的,所以Service中若是須要執行耗時操做(大文件的操做,數據庫的拷貝,網絡請求,文件下載等)的話應該在子線程中完成。
  • Service生命週期解釋技術博客大總結
    • onCreate():服務第一次被建立時調用
    • onStartComand():服務啓動時調用
    • onBind():服務被綁定時調用
    • onUnBind():服務被解綁時調用
    • onDestroy():服務中止時調用
  • 說一下onStartCommand()的做用?
  • service如何殺不死?
    • 1.onStartCommand方法,返回START_STICKY(粘性)當service因內存不足被kill,當內存又有的時候,service又被從新建立
    • 2.設置優先級,在服務裏的ondestory裏發送廣播 在廣播裏再次開啓這個服務,雙進程守護

1.0.1.2 一個Activty先start一個Service後,再bind時會回調什麼方法?此時如何作才能回調Service的destory()方法?

  • 關於service中onDestroy()何時會被執行?
    • 當調用了startService()方法後,又去調用stopService()方法,這時服務中的onDestroy()方法就會執行,表示服務已經銷燬了。
    • 相似地,當調用了 bindService()方法後,又去調用unbindService()方法,onDestroy()方法也會執行,這兩種狀況都很好理解。
  • 一個Activty先start一個Service後,再bind時會回調什麼方法?

  • 先start後bind操做service,此時如何作才能回調Service的destory()方法?
    • 徹底有可能對一個服務既調用了startService()方法,又調用了bindService()方法的,這種狀況下該如何才能讓服務銷燬掉呢?根據Android系統的機制,一個服務只要被啓動或者被綁定了以後,就會一直處於運行狀態,必需要讓以上兩種條件同時不知足,服務才能被銷燬。
    • 這種狀況下要同時調用stopService()和unbindService()方法,onDestroy()方法纔會執行這樣就把服務的生命週期完整地走了一遍。技術博客大總結

1.0.1.3 bindService是一個異步的過程嗎?綁定service大概須要經歷那些過程?

1.0.1.4 是否能在Service進行耗時操做?若是非要能夠怎麼作,如何避免service線程卡頓?service裏面能夠彈土司嗎?

  • 是否能在Service進行耗時操做?
    • 默認狀況,若是沒有顯示的指定service所運行的進程,Service和Activity是運行在當前app所在進程的mainThread(UI主線程)裏面。
    • service裏面不能執行耗時的操做(網絡請求,拷貝數據庫,大文件),在Service裏執行耗時操做,有可能出現主線程被阻塞(ANR)的狀況。
  • 若是非要能夠怎麼作,如何避免service線程卡頓?
    • 須要在子線程中執行 new Thread(){}.start();
  • service裏面能夠彈土司嗎?
    • 能夠,可是有條件。通常不多這樣作……技術博客大總結
    • 條件是,service裏面彈toast須要添加到主線程裏執行。
      @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的生命週期與啓動方法有什麼區別?

  • Activity如何與Service通訊?
    • 方法一:
      • 添加一個繼承Binder的內部類,並添加相應的邏輯方法。重寫Service的onBind方法,返回咱們剛剛定義的那個內部類實例。Activity中建立一個ServiceConnection的匿名內部類,而且重寫裏面的onServiceConnected方法和onServiceDisconnected方法,這兩個方法分別會在活動與服務成功綁定以及解除綁定的時候調用,在onServiceConnected方法中,咱們能夠獲得一個剛纔那個service的binder對象,經過對這個binder對象進行向下轉型,獲得咱們那個自定義的Binder實例,有了這個實例,作能夠調用這個實例裏面的具體方法進行須要的操做了
    • 方法二
      • 經過BroadCast(廣播)的形式,當咱們的進度發生變化的時候咱們發送一條廣播,而後在Activity的註冊廣播接收器,接收到廣播以後更新視圖

1.0.2.0 是否瞭解ActivityManagerService,它發揮什麼做用,說一下AMS啓動流程?

  • ActivityManagerService是Android中最核心的服務,主要負責系統中四大組件的啓動、切換、調度及應用進程的管理和調度等工做,其職責與操做系統中的進程管理和調度模塊相似。
  • https://blog.csdn.net/dutedehuai/article/details/53495185

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

  • Android中哪些事件須要用到廣播?
    • Android中:系統在運行過程當中,會產生會多事件,那麼某些事件產生時,好比:電量改變、收發短信、撥打電話、屏幕解鎖、開機,系統會發送廣播,只要應用程序接收到這條廣播,就知道系統發生了相應的事件,從而執行相應的代碼。使用廣播接收者,就能夠收聽廣播
  • 廣播的生命週期是怎樣的?
    • a.廣播接收者的生命週期很是短暫的,在接收到廣播的時候建立,onReceive()方法結束以後銷燬;
    • b.廣播接收者中不要作一些耗時的工做,不然會彈出 Application No Response錯誤對話框;
    • c.最好也不要在廣播接收者中建立子線程作耗時的工做,由於廣播接收者被銷燬後進程就成爲了空進程,很容易被系統殺掉;
    • d.耗時的較長的工做最好放在服務中完成;

1.0.2.3 廣播有幾種形式?他們分別有什麼特色,如何使用廣播?廣播是怎麼實現不一樣進程之間通訊的?

  • 廣播有幾種形式
    • 普通廣播:一種徹底異步執行的廣播,在廣播發出以後,全部的廣播接收器幾乎都會在同一時刻接收到這條廣播消息,所以它們接收的前後是隨機的。
    • 有序廣播:一種同步執行的廣播,在廣播發出以後,同一時刻只會有一個廣播接收器可以收到這條廣播消息,當這個廣播接收器中的邏輯執行完畢後,廣播纔會繼續傳遞,因此此時的廣播接收器是有前後順序的,且優先級(priority)高的廣播接收器會先收到廣播消息。有序廣播能夠被接收器截斷使得後面的接收器沒法收到它。
    • 本地廣播:發出的廣播只可以在應用程序的內部進行傳遞,而且廣播接收器也只能接收本應用程序發出的廣播。
    • 粘性廣播:這種廣播會一直滯留,當有匹配該廣播的接收器被註冊後,該接收器就會收到此條廣播。
  • 廣播的兩種註冊形式技術博客大總結
    • 廣播的註冊有兩種方法:一種在活動裏經過代碼動態註冊,另外一種在配置文件裏靜態註冊。兩種方式的相同點是都完成了對接收器以及它能接收的廣播值這兩個值的定義;不一樣點是動態註冊的接收器必需要在程序啓動以後才能接收到廣播,而靜態註冊的接收器即使程序未啓動也能接收到廣播,好比想接收到手機開機完成後系統發出的廣播就只能用靜態註冊了。
  • 動態註冊
    • 須要使用廣播接收者時,執行註冊的代碼,不須要時,執行解除註冊的代碼。安卓中有一些廣播接收者,必須使用代碼註冊,清單文件註冊是無效的。
      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();
                  }
          }
      }
  • 靜態註冊
    • 可使用清單文件註冊。廣播一旦發出,系統就會去全部清單文件中尋找,哪一個廣播接收者的action和廣播的action是匹配的,若是找到了,就把該廣播接收者的進程啓動起來。

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

  • Fragment與Activity之間是如何傳值的?
    • 1.Activity向Fragment傳值:
      • 步驟:
      • 要傳的值,放到bundle對象裏;
      • 在Activity中建立該Fragment的對象fragment,經過調用
      • fragment.setArguments()傳遞到fragment中;
      • 在該Fragment中經過調用getArguments()獲得bundle對象,就能獲得裏面的值。
    • 2.Fragment向Activity傳值:
      • 第一種:
        • 在Activity中調用getFragmentManager()獲得fragmentManager,,調用findFragmentByTag(tag)或者經過findFragmentById(id)
        • FragmentManager fragmentManager = getFragmentManager();
        • Fragment fragment = fragmentManager.findFragmentByTag(tag);
      • 第二種:
        • 經過回調的方式,定義一個接口(能夠在Fragment類中定義),接口中有一個空的方法,在fragment中須要的時候調用接口的方法,值能夠做爲參數放在這個方法中,而後讓Activity實現這個接口,必然會重寫這個方法,這樣值就傳到了Activity中
  • Fragment與Fragment之間是如何傳值的?
    • 第一種:
      • 經過findFragmentByTag獲得另外一個的Fragment的對象,這樣就能夠調用另外一個的方法了。
    • 第二種:
    • 第三種:
      • 經過setArguments,getArguments的方式。

1.0.2.9 Activity建立Fragment的方式是什麼?FragmentPageAdapter和FragmentPageStateAdapter的區別?

  • Activity建立Fragment的方式是什麼?
    • 靜態建立具體步驟
      • 首先咱們一樣須要註冊一個xml文件,而後建立與之對應的java文件,經過onCreatView()的返回方法進行關聯,最後咱們須要在Activity中進行配置相關參數即在Activity的xml文件中放上fragment的位置。
    • 動態建立具體步驟
      • (1)建立待添加的碎片實例
      • (2)獲取FragmentManager,在活動中能夠直接經過調用 getSupportFragmentManager()方法獲得。
      • (3)開啓一個事務,經過調用beginTransaction()方法開啓。
      • (4)向容器內添加或替換碎片,通常使用repalce()方法實現,須要傳入容器的id和待添加的碎片實例。
      • (5)提交事務,調用commit()方法來完成。
  • FragmentPageAdapter和FragmentPageStateAdapter的區別?
    • FragmnetPageAdapter在每次切換頁面時,只是將Fragment進行分離,適合頁面較少的Fragment使用以保存一些內存,對系統內存不會多大影響
    • FragmentPageStateAdapter在每次切換頁面的時候,是將Fragment進行回收,適合頁面較多的Fragment使用,這樣就不會消耗更多的內存

1.0.3.0 fragment 特色?說一下Fragment的生命週期?如何解決getActivity爲null的異常問題?

  • fragment 特色
    • Fragment能夠做爲Activity界面的一部分組成出現;
    • 能夠在一個Activity中同時出現多個Fragment,而且一個Fragment也能夠在多個Activity中使用;
    • 在Activity運行過程當中,能夠添加、移除或者替換Fragment;
    • Fragment能夠響應本身的輸入事件,而且有本身的生命週期,它們的生命週期會受宿主Activity的生命週期影響。
  • Fragment從建立到銷燬整個生命週期中涉及到的方法依次爲:
    • onAttach()->onCreate()->onCreateView()->onActivityCreated()->onStart()->onResume()->onPause()->onStop()->onDestroyView()->onDestroy()->onDetach(),其中和Activity有很多名稱相同做用類似的方法,而不一樣的方法有:
      • onAttach():當Fragment和Activity創建關聯時調用
      • onCreateView():當Fragment建立視圖時調用
      • onActivityCreated():當與Fragment相關聯的Activity完成onCreate()以後調用
      • onDestroyView():在Fragment中的佈局被移除時調用
      • onDetach():當Fragment和Activity解除關聯時調用
  • 如何解決getActivity爲null的異常問題技術博客大總結
    @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試圖爲何有的時候會重疊,怎麼產生的,又如何解決?

  • getActivity()空指針:
    • 這種狀況通常發生在在異步任務裏調用getActivity(),而Fragment已經onDetach(),此時就會有空指針,解決方案是在Fragment裏使用一個全局變量mActivity,在onAttach()方法裏賦值,這樣可能會引發內存泄漏,可是異步任務沒有中止的狀況下自己就已經可能內存泄漏,相比直接crash,這種方式顯得更穩當一些。
  • Fragment視圖重疊:
    • 在類onCreate()的方法加載Fragment,而且沒有判斷saveInstanceState==null或if(findFragmentByTag(mFragmentTag) == null),致使重複加載了同一個Fragment致使重疊。(PS:replace狀況下,若是沒有加入回退棧,則不判斷也不會形成重疊,但建議仍是統一判斷下)
    @Override 
    protected void onCreate(@Nullable Bundle savedInstanceState) {
    // 在頁面重啓時,Fragment會被保存恢復,而此時再加載Fragment會重複加載,致使重疊 ;
        if(saveInstanceState == null){
        // 或者 if(findFragmentByTag(mFragmentTag) == null)
           // 正常狀況下去 加載根Fragment 
        } 
    }

1.0.3.2 爲何fragment傳遞數據不用構造方法傳遞?FragmentManager , add 和 replace 有什麼區別?

  • 爲何fragment傳遞數據不用構造方法傳遞?
    • activity給fragment傳遞數據通常不經過fragment的構造方法來傳遞,會經過setArguments來傳遞,由於當橫豎屏會調用fragment的空參構造函數,數據丟失。
  • FragmentManager , add 和 replace 有什麼區別?
    • 使用FragmentTransaction的時候,它提供了這樣兩個方法,一個add,一個replace,add和replace影響的只是界面,而控制回退的,是事務。
    • add 是把一個fragment添加到一個容器container裏。replace是先remove掉相同id的全部fragment,而後在add當前的這個fragment。技術博客大總結
    • 在大部分狀況下,這兩個的表現基本相同。由於,通常,我們會使用一個FrameLayout來當容器,而每一個Fragment被add 或者 replace 到這個FrameLayout的時候,都是顯示在最上層的。因此你看到的界面都是同樣的。可是,使用add的狀況下,這個FrameLayout其實有2層,多層確定要比一層的來得浪費,因此仍是推薦使用replace。固然有時候仍是須要使用add的。好比要實現輪播圖的效果,每一個輪播圖都是一個獨立的Fragment,而他的容器FrameLayout須要add多個Fragment,這樣他就能夠根據提供的邏輯進行輪播了。而至於返回鍵的時候,這個跟事務有關,跟使用add仍是replace沒有任何關係。
    • replace()方法會將被替換掉的那個Fragment完全地移除掉,所以最好的解決方案就是使用hide()和show()方法來隱藏和顯示Fragment,這就不會讓Fragment的生命週期重走一遍了。

1.0.3.9 Activitiy啓動流程中performLaunchActivity的做用?Activity啓動流程中handleResumeActivity的做用?

  • Activitiy啓動流程中performLaunchActivity的做用?
    • 從ActivityClientRecord中獲取到待啓動的Activity的組件信息
    • 使用類加載器建立Activity對象
    • 經過LoadedApk的方法建立Applicayiton對象,該對象惟一,不會重複建立。
    • 會建立ContextImpl而且創建Context和Activity的聯繫,以及建立PhoneWindow,創建Window和Activity的聯繫。
    • 調用Activity的onCreate()
  • Activity啓動流程中handleResumeActivity的做用?
    • 執行onStart()、onResume()—利用Instrucmentation
    • 獲取Window
    • 建立DecorView、設置爲不可見INVISIBLE、創建DecorView和Activity的聯繫。
    • 獲取Activity的WindowManager
    • 調用WindowManager.addView(decorView, ...)將DecorView添加到WM中,完成顯示的工做。
    • image
  • 什麼時候將DecorView設置爲VISIBLE?而且顯示出來?技術博客大總結
    • 也是在handleResumeActivity中
    • 現將DecorView設置爲不可見
    • wm.addView(): 將DecorView添加到Window總
    • 而後執行makeVisible讓DecorView可見
    • image

1.0.4.0 Intent是什麼?Intent能夠傳遞哪些數據?傳遞對象的時候爲何要實例化?

  • Intent是一種運行時綁定(run-time binding)機制,它能在程序運行過程當中鏈接兩個不一樣的組件。
    • 舉例:好比,有一個Activity但願打開網頁瀏覽器查看某一網頁的內容,那麼這個Activity只須要發出 WEB_SEARCH_ACTION給Android
    • Android就會根據Intent的請求內容,查詢各組件註冊時聲明的 IntentFilter,找到網頁瀏覽器的Activity來瀏覽網頁
  • Intent能夠傳遞的數據基本數據類型的數據,數組,還有集合,還有序列化的對象
    • 序列化:表示將一個對象轉換成可存儲或可傳輸的狀態
    • Android中序列化對象方式:技術博客大總結
      • 第一種:JAVA中的Serialize機制,譯成串行化、序列化……,其做用是能將數據對象存入字節流當中,在須要時從新生成對象。主要應用是利用外部存儲設 備保存對象狀 態,以及經過網絡傳輸對象等。
      • 第二種:在Android系統中,定位爲針對內存受限的設備,所以對性能要求更高,另外系統中採用了新的IPC(進程間通訊)機制,必然要求使用性能更出色的對象傳輸方式。

1.0.1.2 Activity如與Service通訊?Service的生命週期與啓動方法由什麼區別?

能夠經過bindService的方式,先在Activity裏實現一個ServiceConnection接口,並將該接口傳遞給bindService()方法,在ServiceConnection接口的onServiceConnected()方法
裏執行相關操做。

Service的生命週期與啓動方法由什麼區別?
    startService():開啓Service,調用者退出後Service仍然存在。
    bindService():開啓Service,調用者退出後Service也隨即退出。

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

1.1.0.4 廣播有哪些註冊方式?有什麼區別?廣播發送和接收原理是什麼[binder如何運做的]?

  • 廣播有哪些註冊方式?
    • 靜態註冊:常駐系統,不受組件生命週期影響,即使應用退出,廣播仍是能夠被接收,耗電、佔內存。
    • 動態註冊:很是駐,跟隨組件的生命變化,組件結束,廣播結束。在組件結束前,須要先移除廣播,不然容易形成內存泄漏。
  • 廣播發送和接收原理是什麼[binder如何運做的]?
    • 繼承BroadcastReceiver,重寫onReceive()方法。
    • 經過Binder機制向ActivityManagerService註冊廣播。
    • 經過Binder機制向ActivityMangerService發送廣播。
    • ActivityManagerService查找符合相應條件的廣播(IntentFilter/Permission)的BroadcastReceiver,將廣播發送到BroadcastReceiver所在的消息隊列中。
    • BroadcastReceiver所在消息隊列拿到此廣播後,回調它的onReceive()方法。

1.0.4.1 mipmap系列中xxxhdpi、xxhdpi、xhdpi、hdpi、mdpi和ldpi存在怎樣的關係?

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

1.0.4.2 res目錄和assets目錄的區別?

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

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

  • Context是什麼?
    • Context是一個抽象基類。在翻譯爲上下文,也能夠理解爲環境,是提供一些程序的運行環境基礎信息。
  • Context有哪些類型,分別做用是什麼?
    • Context下有兩個子類,ContextWrapper是上下文功能的封裝類,而ContextImpl則是上下文功能的實現類。
    • ContextWrapper又有三個直接的子類,ContextThemeWrapper、Service和Application。其中,ContextThemeWrapper是一個帶主題的封裝類,而它有一個直接子類就是Activity,因此Activity和Service以及Application的Context是不同的,只有Activity須要主題,Service不須要主題。
  • Context下有哪些子類,主要是幹什麼的?
    • Context一共有三種類型,分別是Application、Activity和Service。
    • 這三個類雖然分別各類承擔着不一樣的做用,但它們都屬於Context的一種,而它們具體Context的功能則是由ContextImpl類去實現的,所以在絕大多數場景下,Activity、Service和Application這三種類型的Context都是能夠通用的。
    • 不過有幾種場景比較特殊,好比啓動Activity,還有彈出Dialog。出於安全緣由的考慮,Android是不容許Activity或Dialog憑空出現的,一個Activity的啓動必需要創建在另外一個Activity的基礎之上,也就是以此造成的返回棧。而Dialog則必須在一個Activity上面彈出(除非是系統級別吐司),所以在這種場景下,咱們只能使用Activity類型的Context,不然將會出錯。

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

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

1.0.5.0 序列化的方式有哪些?效率對比有何優點?如何作性能上分析的?

  • 序列化的方式有哪些
    • Parcelable
      • Parcelable是Android特有的一個實現序列化的接口,在Parcel內部包裝了可序列化的數據,能夠在Binder中自由傳輸。序列化的功能由writeToParcel方法來完成,最終經過Parcel的一系列write方法完成。反序列化功能由CREAOR來完成,其內部標明瞭如何建立序列化對象和數組,並經過Parcel的一系列read方法來完成反序列化的過程。
    • Serializable
      • Serializable是Java提供的一個序列化接口,是一個空接口,用於標示對象是否能夠支持序列化,經過ObjectOutputStrean及ObjectInputStream實現序列化和反序列化的過程。注意能夠爲須要序列化的對象設置一個serialVersionUID,在反序列化的時候系統會檢測文件中的serialVersionUID是否與當前類的值一致,若是不一致則說明類發生了修改,反序列化失敗。所以對於可能會修改的類最好指定serialVersionUID的值。

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

  • 界面的刷新爲何需16.6ms?
    • 系統每16.6ms會發出一個VSYNC信號,發出信號後,纔會開始進行測量、佈局和繪製。
    • 發出VSYNC信號時,還會將此時顯示器的buffer緩衝區的數據取出,並顯示在屏幕上。
  • 畫面的顯示須要哪些步驟?
    • CPU計算數據(View樹遍歷並執行三大流程:測量、佈局和繪製),而後將數據交給GPU「
    • GPU渲染處理,而後將數據放到Buffer中。
    • 顯示屏(display)從buffer中取出數據,並進行顯示。
  • 界面保持不變時還會16.6ms刷新一次屏幕嗎?技術博客大總結
    • 對於底層顯示器,每間隔16.6ms接收到VSYNC信號時,就會用buffer中數據進行一次顯示。因此必定會刷新。
  • 界面刷新的本質流程
    • 經過ViewRootImpl的scheduleTraversals()進行界面的三大流程。
    • 調用到scheduleTraversals()時不會當即執行,而是將該操做保存到待執行隊列中。並給底層的刷新信號註冊監聽。
    • 當VSYNC信號到來時,會從待執行隊列中取出對應的scheduleTraversals()操做,並將其加入到主線程的消息隊列中。
    • 主線程從消息隊列中取出並執行三大流程: onMeasure()-onLayout()-onDraw()

1.0.6.0 Android中日誌級別有哪幾種?開發中須要注意什麼問題,打印日誌源碼分析原理是什麼?

  • Android中日誌級別有哪幾種?
    • 1.Log.v 的輸出顏色爲黑色的,輸出大於或等於VERBOSE日誌級別的信息,也就是可見級別,通常是最低的信息提示
    • 2.Log.d的輸出顏色是藍色的,也就是調式級別,通常不會停止程序,通常是程序員爲了調試而打印的log
    • 3.Log.i的輸出爲綠色,輸出大於或等於INFO日誌級別的信息,也就是信息界級別,不會停止程序,通常是系統中執行操做的信息提示
    • 4.Log.w的輸出爲橙色, 輸出大於或等於WARN日誌級別的信息,也就是警告級別,通常不會停止程序,可是可能會影響程序執行結果
    • 5.Log.e的輸出爲紅色,僅輸出ERROR日誌級別的信息,也就是錯誤級別,通常會停止程序運行,是最嚴重的Log級別。
    • 解釋:
      • verbose
      • debug調試
      • info信息
      • warn警告
      • error偏差
  • 經過查看源代碼咱們發現Log類中全部的靜態日誌方法Log.v(),Log.d(),Log.i(),Log.w(),Log.e()等方法都是底層都是調用了println方法,而後在源碼中查看,其實其內部調用的是println_native方法,也就是經過JNI調用底層的c++輸出日誌。

關於其餘內容介紹

01.關於博客彙總連接

02.關於個人博客

相關文章
相關標籤/搜索