BAT大咖助力 全面升級Android面試筆記 (自己補充)
阿新 • • 發佈:2018-11-11
https://blog.csdn.net/qq_23575921/article/details/78947051 原文 補充
Android任務棧
singletop(棧頂複用):Android系統內建的書籤應用
singletask(棧內複用):商城首頁,在分頁中點了主頁其他的分頁全部出棧
scheme跳轉協議
- 在不知道對方的包名,類名的情況下要開啟對方,不如瀏覽器要開啟其他的app,或者本應用 開啟 其他的應用的時候就可以採用這種方法;他是通過在activity中註冊intent-filter來實現的包含 data(含scheme),cataglory,action
Fragmen相關
- addToBackStack 加入棧中,返回的時候銷燬Fragment
Service和Broadcast都是執行在mainThread中所以不能做耗時操作
資料庫相關
- SQLiteOpenHelper 構造方法建立資料庫(方法引數一樣只會呼叫一次,當版本號不一樣的時候會呼叫onUpgrade方法),用這個物件的拿資料庫會掉onCreate方法,這個方法裡建立資料庫表
- helper物件拿db物件,db物件操作資料庫,這些操作的方法封裝到Dao裡面提供給外面呼叫
獲取 Message 的方法
- 在 Hanlder 機制中都需要用到 Message 物件,該物件的建立或者獲取有多種方式。
- Message msg = new Message(); 直接建立一個新的 Message 物件。
- Message msg = handler.obtainMessage(); 通過 handler 物件獲取一個 Message 物件,該物件從訊息快取池中獲取的,可以提高 Message 的使用率,減少垃圾回收次數。
- handler.post(Runnable r); post()方法中傳遞一個 Runnable 物件,那麼該物件會被主執行緒執行。該方法表面上看跟 Message 沒任何關係,但是其內部幫我們封裝了 Message。
- 同樣View.post 也是同樣的機制
常用的執行緒排程操作
- 通過View物件執行延時操作
View view = ...;
view.postDelayed(new Runnable() {
@Override
public void run() {
// 這裡的程式碼在200毫秒後執行在主執行緒
}
}, 200);
- 通過Handler傳送延時請求(可以在子執行緒發出)
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
// 這裡的程式碼在3秒後執行在主執行緒
}
}, 3000);
本質是sendmessage,讓後把runnable一起傳出去,代替了handlemessage
- 在子執行緒執行Activity中的runOnUiThread方法
new Thread(){
public void run() {
// 這個方法只能在Activity裡呼叫
runOnUiThread(new Runnable() {
@Override
public void run() {
// 這裡的程式碼可以執行在主執行緒
}
});
};
}.start();
### 有關動畫
- 屬性動畫animator:是為動畫設定執行的客體,然後指向動畫
- 補間動畫animation:是為客體指定要執行的動畫
廣播:要註冊清單檔案
- 註冊廣播:寫好廣播接受者類,完成onrecevie方法
- 靜態註冊:在清單檔案裡註冊廣播寫好意圖過濾(殺死程序,都可以收到廣播,但是不靈活)
- 動態註冊:在程式碼中注測action嗎(受activity生命週期影響)
- 實現機制
- 通過binder向AMS註冊廣播接收者 :登記接收者
- 通過binder向AMS發廣播:登記廣播
- AMS找到對應的接收者,把廣播放在接收者的訊息佇列中
- 接收者回調onreciver
myReceiver = new OutCallReceiver();
IntentFilter intentFilter=new IntentFilter(Intent.ACTION_NEW_OUTGOING_CALL);
intentFilter.setPriority(Integer.MAX_VALUE);
registerReceiver(myReceiver,intentFilter);
- 傳送廣播:
- 無序:
Intent intent = new Intent();
// 設定動作, 廣播頻道
intent.setAction("com.itheima.cnr.XWLB");
// 新增一些資料
intent.putExtra("content", "這裡是中央人民廣播電臺! 歡迎收聽!");
// 傳送廣播
sendBroadcast(intent);
- 有序:各級接受者要配置priority,高的可以中斷廣播,內線一定可以接收到最後一個結果
// intent 要傳送的意圖
// receiverPermission 接收者需要配置的許可權
// resultReceiver 結果接收者, 一定可以在最後收到訊息
// scheduler 執行緒排程器new Handler()
// initialCode 結果碼
// initialData 初始資料
// initialExtras 額外的引數 Bundle -> map
// 傳送廣播
sendOrderedBroadcast(
intent,
null,
new NeixianReceiver(),
null,
1,
"中央下發糧食了, 每人1000斤, 大家吃好喝好!",
null
);
- localbroadcastmanager(本地廣播)
- 防止反編譯到action,利用你的app分享他自己的連線(植入廣告)
- 比系統廣播更高效
- 別的app無法向你發廣播。只在本app傳播
- 不同於系統廣播發送通過binder,本地廣播發送是通過handler
android中任務棧情況,但是程序依然保留(為了下次開啟快)
- 一個應用可以run在多個程序中
- 前臺程序(可以操作),可視程序(被透明的前臺遮擋,不能操作),服務程序(沒有介面的程式),後臺程序(home鍵回到主介面),空程序(任務棧清空,按返回鍵造成)—按優先順序回收
服務:要註冊清單檔案
- 啟動和顯示意圖的activity一樣,反覆開啟(startservice)不會走oncreate,只會執行onstartcommand
- 關閉要到設定裡,或者手動調stopservice走一次ondestroy
繫結服務的方法
- 建立連線物件,實現連上和解開兩個方法,在服務的繫結和解綁服務中被回撥
- 繫結服務傳入的是conn和service
- 服務被繫結要傳回一個ibinder物件,用這個ibinder來通訊
- 要解綁,否則聯結器會leak,服務會自動銷燬
- 服務是被start開啟的,主程式意外退出,服務不會退出;如果服務是bind方式開啟,主程式意外退出(沒有手動unbind),服務會自動解綁並且destroy
- 總結是前臺程序通過繫結conn和服務的方式啟動服務,服務返回ibinder物件給前臺程序,ibinder物件可以帶上服務裡的方法給前臺程序呼叫
- 當 service 同時被 startService 和 bindService 啟動時,只有 stopService 和
unbindService 都被呼叫後,service 才會被銷燬。
單例吐司
if(toast == null){
toast = Toast.makeText(context, "", Toast.LENGTH_SHORT);
}
toast.setText(string);
toast.show();
隱式意圖應用間用,用了意圖過濾器or export=true那麼就可以被其他應用開啟;顯示意圖預設是應用內部用
aidl(服務程式碼在另一個應用中 介面定義語言)
- 是一種採用共享儲存區的IPC通訊方法,通過asinterface的方法用key值在共享檔案binder中找到服務介面,返回給呼叫物件使用;呼叫者用aidl生成的類裡的方法處理返回的binder物件可以生成遠端服務指定的介面類,並呼叫其中的方法,達到呼叫服務裡方法的目的
既然service不能做耗時操作,也要new thread 那麼為什麼不直接在 activity中new thread;
- 因為activity會銷燬finish ,很難對執行緒做到很好的管理,但是service就不同,可以長時間在後臺執行,完成對thread的管理。比如音樂播放器、資料統計。
- activity與service的通訊用的是binder機制,這本身就是IPC通訊的原理,應為activity和service完全可以執行在不同的程序當中。
服務可以不用直接和activity互動,通過startservice方式啟動的服務,可以傳送廣播給接收者,讓廣播處理相應的業務。讓activity和service之間解綁。
webview
- 記憶體洩漏:自己會開闢執行緒(類似匿名內部類持有外部類的引用)不懂
- 動態通過viewgroup新增,銷燬前remove
- 獨立程序
- 渲染:關閉硬體加速
- 耗電:
binder機制
- Linux是程序間隔離的,程序之間沒有辦法傳資料
- 所以通過第三者servicemanager來管理,傳回一個代理物件給client
- client把代理物件調的結果告訴binder,binder調service裡的真方法
aidl機制
- stub實現了IService介面,
- 在asinterface裡面按照key查詢本地的介面,如果有就表示是本地的呼叫直接返回,如果沒有則返回proxy代理物件
- 代理物件實現的方法是個空方法,呼叫了transact,最終回到onTranact,呼叫的還是本地的方法,中間通過了Ibinder
記憶體洩漏https://blog.csdn.net/bigbangwqf/article/details/51329223
- 非靜態內部類持有外部類的引用(靜態的不會持有,跟物件無關):handle
- 可以關閉的時候銷燬掉 handle.removecallback()
- 可以弱引用
- 可以靜態化(這樣調不了外部類的方法)
- 匿名內部類持有外部類的引用:webview
AsyncTask使用方法
- 三個引數(傳入,進度,結果)
- 五個方法:
- onPreExecute:在UI執行緒呼叫,任務前準備工作
- doinbackground<第1個引數>:耗時
- 結果傳入:onPostExecute<第3個引數>
- 更新進度:publishProgress(內部),onProgressUpdate<第2個引數>(外部跟新)
- 原理:內部封裝執行緒池,用handle實現子執行緒和ui執行緒的傳遞
- 洩漏:cancel
HandlerThread相關https://blog.csdn.net/u011240877/article/details/72905631
- 處理序列的子執行緒呼叫
- 繼承類訊息群是在prepare裡完成插入,同時建立handle,定義處理訊息的處理方式handlemessage
IntentService相關
- https://blog.csdn.net/iromkoear/article/details/63252665
- 訊息群是在onstart裡完成插入(IntentService已經插入), 繼承類定義處理訊息的處理方式onhandleintent
Android studio
- classpath ‘com.android.tools.build:gradle:3.0.1’ 這個跟Android studio的版本一樣
- compileSdkVersion :sdk/plateform
- buildToolsVersion :sdk/build-toos
- 目錄:
- .gradle:構建檔案
- gradle:由於gradle更新的速度超過Androidstudio所以弄了個包裝類wrapper來跟上進度。
- .idea:Androidstudio自己要用的工具
listView 優化
- convertview重用: 不用new
- viewHolder : 不用找
- 圖片快取 :不用每次都載入
- 滑動監聽:儘量不要做耗時操作,一定要做的話,加滑動監聽,停下來的時候在請求網路等等
類載入器的雙親委託模型
- 先交給最頂層的載入器載入
- 步驟:
- 載入
- 驗證
- 準備:賦值,區域性變數一定要賦值才能使用,否則編譯不通過,其他的按照jvm的規則進行賦值or預設值;同時被static和final修飾的要在宣告是就賦值,final修飾的要在初始化前賦值;
- 解析:解析類、方法、變數,方法先找類
- 初始化
- 使用
- 解除安裝
記憶體管理
- 靜態儲存器(方法區):靜態資料,常量;存在於整個生命區
- 棧區:基本型別變數,物件引用
- 堆區(動態儲存器):
- 回收機制
- 用有向圖是否可達類管理記憶體
git 命令
- git init
- git status
- git diff
- git add
- git commit
- git clone
- git branch
- git checkout
- 下面的模型區別於傳統的直接跟遠端倉庫打交道,忽略了程式碼管理員的角色,增加了fork和pull
proguard
- 壓縮
- 優化
- 混淆
- 預檢測
- entrypoint
框架
volley
-支援圖片載入
- 使用:
- 建立請求佇列
- 建立請求
- 把請求加入請求佇列
- 原始碼:
- 建立請求佇列:封裝了httpclientstack,建立了queue開啟並返回
- queue開啟建立了兩個執行緒死迴圈,一個是快取執行緒,一個是網路請求執行緒
- 在請求加入請求佇列後
- 判斷是否要快取,要就加入快取執行緒
- 加入網路請求執行緒
- 其中快取執行緒的run方法會先按照key從快取佇列中拿,返回為空,就把他加入網路請求佇列。發出返回結果,觸發回撥函式
- 而網路請求佇列是直接加入請求,發出返回結果,觸發回撥函式
butterknife
- 是用註解在編譯期完成的,並非執行時反射的
- 變數要是public否則只能反射才能獲得
開發架構
MVC
- M:業務邏輯,耗時,資料庫
- V:顯示,xml
- C:activity 處理互動,從v拿到使用者輸入的資料,交給m查資料庫or請求伺服器,返回的結果交給v顯示;解耦v 和 m
MVP
-
由於Android的v(xml)所做的的詳情,相比於web來說非常有限。很多工作交給了c層的activity實現導致C太耦合了,所以引入MVP
-
在MVP中activity變成了v,他原本的處理互動的工作交給了presenter來處理
-
M:網路請求,資料庫查詢,資料bean
-
V:activity
-
P:業務層,徹底分開view和model
-
上圖可以清晰的看到presenter要調view,只能通過定義好的介面,限制好能做的事
-
**特點:**與業務有關的M(網路請求,資料庫查詢)或V(成功返回,失敗返回,顯示關閉進度條) 都是要在介面中定義好交給對應的M 或者V (activity)實現,讓程式碼看的結構清晰。就是P要呼叫v還是M都是介面定義好的只要看介面就知道要做什麼事。
-
介面回撥:網路請求為例,我不知道請求幾時能結束,所以把結束要做的事的函式跟著網路請求一起傳給請求函式,請求結果出來了由他回撥。在Android裡這個回撥方法執行一般要更新ui,所以要交給handler處理(runonuithread就是這麼封裝的)。
PathClassLoader,DexClassLoader
- DexClassLoader:載入dex位元組碼裡的類(動態)
- PathClassLoader:載入檔案目錄裡的類
有關程序的優先順序
- 空程序的存在是為了快取,下次開啟apk快一些,不包含任何元件
- 程序回收:low memory kill 打分
- 保活:service拉活,native拉活
###Android中哪些操作在主執行緒
- Activity的所有生命週期方法
- Service執行
- 廣播的onReceive
- 沒有使用子執行緒的Looper的Handler的HandleMessage,post是執行在主執行緒的
- AsyncTast的回撥中除了doInbackgound,其他都是在主執行緒的
如何解決ANR
- 使用AsyncTast處理IO操作
- 使用Thread或者HandlerThread提高優先順序
- 是哦用Handler來處理工作執行緒的耗時任務
- Activity的onCreate和onResume回撥中儘量避免耗時的程式碼
oom
- 當前佔用的記憶體加上我們申請的記憶體資源超過了Dalvik虛擬機器的最大記憶體限制就會丟擲Out Of Memory異常
記憶體洩漏:
- 單例:單例是靜態的,傳入的context用application。
- 匿名內部類(就跟非靜態的內部類洩漏是一樣的原因,預設持有外部類的引用,不是說靜態的就不可以持有,如果構造方法傳進去了就會持有,但是可以改成弱引用):非靜態的都會持有外部類的引用。內部不消失,外部不消失
- 匿名內部類指的是類定義的時候沒有給名字,而不是這個類生成的物件沒有給名字。通常類在定義的時候就new了比如thread。
- 所以有:匿名內部類訪問方法成員變數需要加final的原因及證明
- 解法:。弱引用
- handle:定義在activity的匿名handle內部類,生命週期和activity不一樣,他是被訊息佇列持有,只要佇列的訊息沒完就不會消失。
- 解法:靜態,對持有外部類的引用改為弱應用弱引用
- static成員變數:避免使用
- 資源沒有關閉
- asynctask,可以在onDestroy 取消任務