2019年的面試條目總結
一.熟練對Android Q版本適配
-
儲存沙箱化, 每個應用訪問自己沙箱內的檔案。訪問別的沙箱解決辦法類似於FileUriExposedException,用FileProvider將file轉換為content傳遞
-
裝置唯一id獲取,谷歌開放了新的裝置id獲取方式,目前不同手機獲取的方式不同以前的
READ_PHONE_STATE
方式變為了READ_PRIVILEGED_PHONE_STATE
-
非SDK介面的限制,設定禁止對非sdk介面的依賴,主要是一些第三方的熱修復,加固方案使用了這些被限制的SDK介面
-
限制了明文流量,只有使用https才可以訪問
二.安卓各版本的新特性
-
Android 6.0(M) ,完整的許可權控制,危險許可權需要動態獲取。 API 檢測是否有授權,申請授權,許可權失敗解釋
-
Android7.0 (N) , 刪除了三種靜態廣播 網路狀態新照片和新視訊
-
Android8.0(P),自適應的圖示型別,推送和通知的管理
三.Glide原始碼解析
四.EventBus原始碼解析
五.Arouter原始碼解析
六.Retrofit原始碼解析
-
Retrofit使用
Retrofit.create(Class)
方法建立出Service 介面物件,使retrofit可以在Service中進行引數配置 -
然而在
Retrofit.create()
方法中,是使用Proxy.newProxyInstance()
方法來建立Service介面例項,這個例項實現了所有的介面方法,呼叫例項的InvocationHandler
成員變數的invoke()
方法,InvocationHandler
物件就會代理介面中的是設定。 -
invoke()
中的邏輯:-
loadServiceMethod(method)
將interface中的方法資訊讀取並初步分析生成ServiceMethod -
OkHttpCall<Object> okHttpCall = new OkhttpCall<>(serviceMethod,args)
負責將ServiceMethod封裝到retrofit2.call
物件,該物件在enqueue等的時候會呼叫okhttp.call
物件,由它來進行網路請求的發起 -
在
serviceMethod.adapt(okHttpCall)
中,serviceMethod裡面的的callAdapter物件把okHttpCall
轉為新的retrofit.call
型別物件。這個call中,後臺執行緒發起的請求的返回中,呼叫主執行緒回撥方法。還可以生成rxjava的Obervable等
-
七.Okhttp3原始碼解析
-
首先創造出一個OkhttpClient進行網路配置,然後建立一個Request傳入client,client建立一個call開始發起請求。
-
Dispatcher dispatcher
:排程器,排程後臺發起的網路請求,可設定主機請求數和後臺請求數List<Protocol> protocols
:支援的應用層協議版本List<ConnectionSpec> connectionSpecs
:應用層支援的Socket設定,即使用明文傳輸 還是TLSList<Interceptor> interceptors
大多數的Interceptor都會配置在這裡List<Interceptor> networkInterceptors
:直接和網路請求互動的Interceptor配置到這裡CookieJar cookieJar
:管理Cookie的控制器,提供了基礎的存取判斷,剩下的需要自己實現Cache cache
:Cache 儲存的配置。預設是沒有,如果需要⽤,得⾃⼰配置出 Cache 儲存的⽂件位置以及儲存空間上限。HostnameVerifier hostnameVerifier
:⽤於驗證 HTTPS 握⼿過程中下載到的證照所屬者是否和⾃⼰要訪問的主機名⼀致。Authenticator[ɔːˈθɛntɪkeɪtə] authenticator
:用於自動重新認證。配置後收到401時會直接呼叫authenticator,重新發起請求 -
OKHttp3通過攔截鏈的設計,讓請求分成5個攔截器去處理,攔截器各司其職,擴充套件性非常高。攔截鏈是從自定義的攔截器開始,然後再到預設的5個攔截器。一般情況下我們想列印網路請求日誌,所以可以自定義Log攔截器,如果要給所有請求新增Header,同樣可以自定義Header攔截器。
- 失敗重試、重定向攔截器。
- 橋攔截器:主要是新增和刪除一些header
- 快取攔截器:根據快取策略,如果快取可用,直接返回快取資料。
- 連線池攔截器:連線池會快取http連結,連線池的好處是複用連線,少了3次握手,所以請求會更快
- .真正訪問網路的攔截器:內部使用okio去發請求
八.記憶體洩漏優化
九.熟悉TCP/IP,http/https協議,熟悉使用者登入和授權以及使用者行為分析等方式
十.熟悉對稱/非對稱加密、hash、base64的實現方式以及相關應用
十一.Handler和AsyncTask機制
handler機制
方法一:使用sendMessage()
步驟:
步驟一:主執行緒匿名內部類建立Handler物件
步驟二:建立訊息物件
通過Message message=Message.obtain()
建立一個message
步驟三:傳送訊息mHandler.sendMessage(msg);
原理:
UI執行緒建立一個Handler物件,然後在子執行緒中sendMessage傳送到在主執行緒的MessageQueue中,最後通過Lopper(訊息泵)物件去除MessageQueue中的訊息,分發回Handler的handleMessage()
中
AsyncTask機制
AsyncTask的原理 = 執行緒池 + Handler
執行緒池用於執行緒的排程、複用;handler用於非同步通訊
內部有一個SerialExecutor任務佇列執行緒池(任務排程)
和THREAD_POOL_EXECUTOR執行執行緒池(真正執行任務的執行緒池)
和內部handler(非同步通訊+訊息傳遞)
,
類、方法的介紹
AsynTask屬於抽象類需實現子類
execute(Params... params)
:觸發執行非同步執行緒任務,必需在UI執行緒中呼叫
onPreExecute()
:執行執行緒任務前的操作執行任務前呼叫,如顯示進度條等操作
doInBackground(Params params)
:接受輸入引數,執行任務中的耗時操作,返回執行結果。
onPostExecute(Resule result)
:接收執行緒任務執行結果,顯示到UI元件
onCancelled
:將非同步任務設定為取消狀態,doInBackground()
中判斷終止任務
點選檢視AsynTask原理具體說明
原理須知:
同步鎖修飾execute()
從而保證AsyncTask中的任務是序列執行的
十二.MVC以及MVP
MVC的步驟:
首先使用者觸控View層(比如控制元件xml啥的都算view)
Controller層(Activity,Fragment)
做出反應去請求
Model層(http, 資料庫,sp)
的資料,然後返回資料給C層,C層收到資料後通知View層進行更新
MVP的步驟:
首先使用者觸控View層(Activity,Fragment)
如點選請求網路
然後view層呼叫Presenter(橋樑層)
層去Model層(網路請求資料,資料庫資料,sp資料,contentProvider)
拿對應的資料
最後P層通過初始化時持有的View層引用將view的更新通知給V層
十三.元件化、外掛化
元件化
外掛化
將app拆分成很多塊,每個模組都是一個apk,最終打包的時候講宿主apk和外掛apk分開打包,外掛apk通過動態下發到宿主apk。
用的是VirtualAPK
過程
1.宿主Module中的build.gradle中新增配置,apply plugin
2.application中進行初始化
3.適當位置載入外掛
PluginManager pluginManager = PluginManager.getInstance(base);
File apk = new File(Environment.getExternalStorageDirectory(), "plugin.apk");
if (apk.exists()) {
try {
pluginManager.loadPlugin(apk);
} catch (Exception e) {
e.printStackTrace();
}
} else {
Toast.makeText(getApplicationContext(),"SDcard根目錄未檢測到plugin.apk外掛", Toast.LENGTH_SHORT).show();
}
複製程式碼
4.載入外掛
public void click(View view){
Intent intent = new Intent();
intent.setClassName("com.emm.plugin","com.emm.plugin.Main2Activity");
tartActivity(intent);
}
複製程式碼
原理:大致方案如下
原生apk就可作為外掛載入,外掛工程編譯生成apk後,即可通過宿主app載入,並在宿主中建立LoadedPlugin物件。再次啟動就會變得流暢 外掛apk需要在宿主Apk中提前佔坑,通過Hook Activity的啟動過程,“欺上瞞下”啟動外掛Apk中的Activity,其他三大元件都是通過代理的方式。
十四.TCP/IP協議簇,http/https協議,使用者登入授權、行為跟蹤
應用層 HTTP 、FTP 傳輸層 TCP、UDP 網路層 IP、ICMP、ARP 資料鏈路層 FDDI、IEEE 802.1A
使用者登入授權
Cookie是由伺服器端生成,伺服器需要客戶端儲存的內容,放在Set-Cookie
headers裡返回,客戶端會自動儲存
客戶端儲存的Cookie會在之後的所有請求裡攜帶進Cookie
header裡發回給伺服器
客戶端儲存Cookie是按照伺服器域名來分類的
行為跟蹤
簡單的說就是Cookies追蹤,利用第三方cookie來實現這一的機制 很多第三方作為跨域提供了使用者的token
十五.工廠、模板、觀察者、介面卡設計模式
工廠模式:寶馬和賓士類都實現car介面,用CarFactory
返回例項化介面car,相當於一個工廠可以生產不同型別的例項
模板模式:抽象模板角色類,實現了父類所宣告的基本方法。子類實現需要強制實現的邏輯
觀察者模式:
1.抽象被觀察者介面,宣告新增通知刪除觀察者方法
public interface Observerable {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObserver();
}
複製程式碼
2.定義一個抽象觀察者介面
public interface Observer {
public void update(String message);
}
複製程式碼
3.定義被觀察者,實現了Observerable介面,對介面方法進行了具體實現
public class WechatServer implements Observerable {
//注意到這個List集合的泛型引數為Observer介面,設計原則:面向介面程式設計而不是面向實現程式設計
private List<Observer> list;
private String message;
public WechatServer() {
list = new ArrayList<Observer>();
}
@Override
public void registerObserver(Observer o) {
list.add(o);
}
@Override
public void removeObserver(Observer o) {
if(!list.isEmpty())
list.remove(o);
}
//遍歷
@Override
public void notifyObserver() {
for(int i = 0; i < list.size(); i++) {
Observer oserver = list.get(i);
oserver.update(message);
}
}
public void setInfomation(String s) {
this.message = s;
System.out.println("微信服務更新訊息: " + s);
//訊息更新,通知所有觀察者
notifyObserver();
}
}
複製程式碼
4.定義具體觀察者,微信公眾號具體觀察者為使用者User
public class User implements Observer {
private String name;
private String message;
public User(String name) {
this.name = name;
}
@Override
public void update(String message) {
this.message = message;
read();
}
public void read() {
System.out.println(name + " 收到推送訊息: " + message);
}
}
複製程式碼
5.編寫一個測試類,首先註冊了三個使用者,ZhangSan、LiSi、WangWu。公眾號釋出了一條訊息"PHP是世界上最好用的語言!",三個使用者都收到了訊息。 使用者ZhangSan看到訊息後頗為震驚,果斷取消訂閱,這時公眾號又推送了一條訊息,此時使用者ZhangSan已經收不到訊息,其他使用者
public class Test {
public static void main(String[] args) {
WechatServer server = new WechatServer();
Observer userZhang = new User("ZhangSan");
Observer userLi = new User("LiSi");
Observer userWang = new User("WangWu");
server.registerObserver(userZhang);
server.registerObserver(userLi);
server.registerObserver(userWang);
server.setInfomation("PHP是世界上最好用的語言!");
System.out.println("----------------------------------------------");
server.removeObserver(userZhang);
server.setInfomation("JAVA是世界上最好用的語言!");
}
}
複製程式碼
介面卡模式:
十六.viewStub、ViewPager2、CoordinatorLayout
ViewStub:寬高都為 0 的不可見 View. 通過延遲載入佈局的方式優化佈局提升渲染效能,通過setVisibility或者直接呼叫inflate都會渲染布局檔案
ViewPager2:核心為RecyclerView
+LinerLayoutManager
,所以支援橫向和豎向的滾動,viewpager2
可以承載fragment,需要繼承它提供的FragmentStateAdapter
,還可以完整支援notifyDataSetChanged()
CoordinatorLayout:
1.CoordinatorLayout繼承自viewgroup,但是使用類似於framLayout,只有CoordinatorLayout的直接子佈局才能響應。
2.是需要CoordinateLayout
+AppBarLayout
+CollapingToolbarLayout
結合才有效果。
<android.support.design.widget.CoordinatorLayout
android:id="@+id/main_content"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="15dp"
android:src="@drawable/add_2"/>
</android.support.design.widget.CoordinatorLayout>
複製程式碼
- AppBarLayout設定屬性:layout_scrollFlags
scroll|exitUntilCollapsed
,子控制元件可以向上滾動出NestedScrollView父佈局時會摺疊到頂端scroll|enterAlways
:只要向下滾動該佈局就會顯示出來,向上滾動該佈局就會收縮scroll|enterAlwaysCollapsed
:向下滾動到最低端時,該佈局才會顯示出來
十七.jni使用
使用CMake
進行ndk開發,它是一種比nake更高階的編譯配置工具,通過CMakeLists.txt,可以控制生成的Makefile,從而控制編譯過程、生成原始碼包、生成當前平臺安裝包。
使用流程
- 在java檔案中建立本地方法
- build專案後自動生成
.h
檔案 - 建立.cpp檔案,實現.h檔案中的方法
- 配置Cmake檔案,生成
.so
檔案
十八.螢幕適配
- 官方適配方案:
使用dp方式適配
使用資源目錄名加上-1920*1280等欄位
百分比佈局庫
PercentRelativeLayout
、PercentFrameLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#ff0000"
app:layout_heightPercent="30%"
app:layout_widthPercent="70%"
複製程式碼
ConstraintLayout
layout_constraintHorizontal_chainStyle
Guideline
layout_constraintHorizontal_bias layout_constraintVertical_bias
- 開源適配方案:
今日頭條適配方案
px=dp*density
,動態修改裝置的density值,在不同解析度下達到相同的畫素密度
十九.Arouter、RxJava
Arouter
RxJava
二十.動畫、svg自定義控制元件
補間動畫: 主要通過xml中定義具有旋轉、縮放、平移、透明度的動畫
Animation animation = AnimationUtils.loadAnimation(MainActivity.this,R.anim.viewanimation);
textView.startAnimation(animation);
複製程式碼
屬性動畫: 補間動畫只能定義兩個關鍵幀在透明(alpha)、旋轉(rorate)、位移(translate)和縮放(scale)這四個屬性的變換,但是屬性動畫可以定義任何屬性的變化。 補間動畫只能對 UI 元件執行動畫,但屬性動畫可以對任何物件執行動畫。
Animator
: 提供建立屬性動畫的基類,基本不會直接使用這個類。
ValueAnimator
:屬性動畫用到的主要的時間引擎,負責計算各個幀的屬性值。
ObjectAnimator
: ValueAnimator 的子類,對指定物件的屬性執行動畫。
AnimatorSet
:Animator 的子類,用於組合多個 Animator。
二十一.https HTTP over SSL
定義:給HTTP增加一個安全層,用於保障HTTP的加密傳輸,可以接受的對稱加密,非對稱加密,hash演算法 Https在與伺服器進行資料互動之前,會與伺服器進行一次通訊(握手)
1、瀏覽器將自身支援的加密演算法傳送給服務端
2、服務端篩選出一套加密演算法,以證照的形式發給瀏覽器
3、瀏覽器根驗證證照的合法性,據拿到的證照裡的公鑰加密一串訊息發給服務端
4、服務端使用私鑰解密資訊,驗證雜湊,並加密響應訊息給瀏覽器
5、瀏覽器解密響應訊息,並對訊息進行驗證,如果驗證通過,則可以進行加密資料互動
觸控事件的衝突解決
解決觸控事件衝突:
外部攔截。ViewGroup重寫onInterceptTouchEvent方法,預設不攔截,事件往下分發給子View,若返回true,則攔截此次事件,將事件傳給ViewGroup的onTouchEvent處理。
內部攔截。重寫子View的dispatchTouchEvent方法,方法中呼叫getParent().requestDisallowInterceptTouchEvent(true)方法,傳true則代表不希望ViewGroup攔截事件,傳false則代表希望ViewGroup攔截事件。
內部攔截。子View重寫onTouchEvent方法,返回true,則子View消費該次事件,返回false,該次事件返回給ViewGroup的onTouchEvent處理。