1. 程式人生 > >BAT大咖助力 全面升級Android面試筆記 (自己補充)

BAT大咖助力 全面升級Android面試筆記 (自己補充)

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 也是同樣的機制

常用的執行緒排程操作

  1. 通過View物件執行延時操作
        View view = ...;
        view.postDelayed(new Runnable() {
			
			@Override
			public void run() {
				// 這裡的程式碼在200毫秒後執行在主執行緒
			}
		}, 200);
  1. 通過Handler傳送延時請求(可以在子執行緒發出)
        new Handler().postDelayed(new Runnable() {
			
			@Override
			public void run() {
				// 這裡的程式碼在3秒後執行在主執行緒
			}
		}, 3000);

本質是sendmessage,讓後把runnable一起傳出去,代替了handlemessage

  1. 在子執行緒執行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相關

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 取消任務