索引:
- Binder機制框全,共享內(nèi)存實現(xiàn)原理
- ActivityThread工作原理
- 嵌套滑動實現(xiàn)原理
- View的繪制原理,自定義View拆撼,自定義ViewGroup
- View闸度、SurfaceView 與 TextureView
- 主線程Looper.loop為什么不會造成死循環(huán)
- ViewPager的原理
- BroadcastReceiver使用總結(jié)
- AndroidP新特性
- Asset目錄與res目錄的區(qū)別
11. Binder機制蚜印,共享內(nèi)存實現(xiàn)原理
??Binder是跨進程通信(IPC)的一種解決方案窄赋。Binder中文即粘合劑楼熄,意思是粘合兩個不同的進程孝赫。從定義來講Binder是一種Android中實現(xiàn)跨進程的方式青柄;也是一種虛擬的物理設(shè)備驅(qū)動预侯,連接Service進程萎馅、Client進程和ServiceManager進程;而對于Android代碼來說飒货,Binder是一個類塘辅,實現(xiàn)了IBinder接口皆撩,將Binder機制模型以代碼的形式具體實現(xiàn)的Android中。
??一個進程空間分為用戶空間和內(nèi)和空間呻惕,進程間用戶空間數(shù)據(jù)不可共享而內(nèi)核空間是可以共享的亚脆,因為所有進程共用一個內(nèi)核空間濒持。用戶空間可以和內(nèi)核空間通過系統(tǒng)調(diào)用交互,從而實現(xiàn)內(nèi)存共享弥喉。
copy_from_user()
:將用戶空間的數(shù)據(jù)拷貝到內(nèi)核空間
copy_to_user()
:將內(nèi)核空間的數(shù)據(jù)拷貝到用戶空間
12. ActivityThread工作原理
??ActivityThread是Android應(yīng)用程序的主線程(UI線程)玛迄。理解ActivityThread類似理解Android線程管理的關(guān)鍵蓖议。
??從源碼我們可以看到ActivityThred在main函數(shù)中創(chuàng)建了Looper勒虾,這也是為什么我們再主線程使用Handler不需要自己構(gòu)建Looper的原因。然后main()通過thread.attach(false)
綁定應(yīng)用進程笛钝。
??主線程的消息機制還是又Handler去執(zhí)行的愕宋。Looper的loop()方法則是起點和和興。首先通過myLooper()方法獲取Looper對象囤捻,取出Looper持有的MessageQueue。然后從MessageQueue取出Message蒜撮,如果為null淀弹,說明線程正在推出菌赖。Message不為空邑时,則調(diào)用Message的target handler對該Meeage分發(fā)浅浮,處理完畢后調(diào)用recycle()方法進行回收郁油。
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
AndroidKeyStoreProvider.install();
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
13. 嵌套滑動實現(xiàn)原理
??嵌套滑動的實現(xiàn)與傳統(tǒng)的事件分發(fā)不同,嵌套滑動式從子View傳遞給父View炒刁,從下到上的一個順序。實現(xiàn)嵌套滑動,需要我們外層父布局實現(xiàn)NestedScrollingParent肩碟,內(nèi)層子View實現(xiàn)NestedScrollingChild。
??NestedScrollingParent接口需要涉及兩個方法叙凡。首先是onStartNestedScroll(View child, View target, int nestedScrollAxes):
nestedChild想要進行嵌套滾動時新啼,會調(diào)用nestedParent的這個方法。這個芳法用于指示是否支持嵌套滾動。第二個是onNestedPreScroll(View target, int dx, int dy, int[] consumed):
當(dāng)我們滾動nestedChild時奈搜,nestedChild進行實際的滾動前京髓,會先調(diào)用nestParent的這個方法。nestedParent在這個方法中可以把子View想要滾動的距離消耗掉一部分或是全部消耗蒋困。
??關(guān)于原理,事實上打洼,是nestedChild的onTouchEvent()方法中會對發(fā)生的Touch事件進行判斷募疮,若為DOWN事件則會調(diào)用startNestedScroll()方法酝锅;若為MOVE事件則會調(diào)用dispatchNestedPreScroll()方法蟋字。
參考文章:十分鐘Android中的嵌套滾動機制
14. View的繪制原理鹊奖,自定義View,自定義ViewGroup
??View的繪制主要分為View的繪制和ViewGroup的繪制巡社。對于單一View的繪制气笙,在draw方法中怯晕,依次繪制背景堵第、內(nèi)容阀捅、裝飾针余。而我們經(jīng)常重寫的onDraw方法其實就是繪制內(nèi)容。而ViewGroup的繪制會掃尾復(fù)雜一些忍级,首先還是繪制自身轴咱,依次是背景朴肺、內(nèi)容戈稿、子View器瘪、裝飾橡疼。繪制子View的時候ViewGroup會遍歷子View欣除,然后挨個繪制。整個繪制自上而下历帚,樹形結(jié)構(gòu)循環(huán)滔岳。
15. View、SurfaceView 與 TextureView
??SurfaceView與TextrueView是View的子類挽牢,特點是能夠在獨立線程中繪制和渲染谱煤,在專用的GPU線程中大大提高渲染的性能。
??SurfaceView:可以通過SurfaceHolder.addCallBack在子線程中更新UI,由于SurfaceHolder的雙緩沖功能禽拔,可以是畫面更加流暢的運行刘离,但是由于holder的存在導(dǎo)致畫面更新存在間隔,并且同樣因為holder導(dǎo)致SurfaceView不能進行像View一樣setAlpha和setRotation睹栖。比較適用于類似坦克大戰(zhàn)等需要不斷告訴畫布更新的游戲硫惕。
??TextrueView:可以通過TextureView.setSurfaceTextureListener在子線程更新UI。適用于音視頻播放器或相機應(yīng)用的開發(fā)野来。
16. 主線程Looper.loop為什么不會造成死循環(huán)
??首先曼氛,結(jié)論是主線程確實阻塞了,但是主線程在初始化過程中由ActivityThread的main()方法中會創(chuàng)建一套消息循環(huán)組件包括Looper,MessageQueue,Handler,然后由MessageQueue中的next()調(diào)用底層MessageQueue,通過epoll進行阻塞,有主線程消息的時候通過發(fā)送消息激活主線程灰追。主線程被喚醒只是為了讀取消息,當(dāng)消息讀取完畢,再次睡眠团滥。因此loop的循環(huán)并不會對CPU性能有過多的消耗,也就不會造成ANR力惯。
17. ViewPager的原理
??ViewPager實現(xiàn)視圖左右滑動弄跌,原理在于創(chuàng)建了三個視圖茎匠,屏幕中間展示的是中間的視圖凯肋,而屏幕兩側(cè)隱藏著的則是預(yù)加載的視圖,當(dāng)左右滑動時,將預(yù)加載的視圖顯示出來,并且緩存當(dāng)前視圖。
18. BroadcastReceiver使用總結(jié)
??首先自定義MyBroadcastReceiver繼承BroadcastReceiver览徒,作為接收者纽什。并且注冊需要接收的Intent意圖押赊,即廣播。
public class MyBroadcastReceiver extends BroadcastReceiver {
public static final String TAG = "MyBroadcastReceiver";
public static int m = 1;
@Override
public void onReceive(Context context, Intent intent) {
Log.w(TAG, "intent:" + intent);
String name = intent.getStringExtra("name");
Log.w(TAG, "name:" + name + " m=" + m);
m++;
Bundle bundle = intent.getExtras();
}
}
??其次,廣播分為靜態(tài)注冊和動態(tài)注冊。當(dāng)接受有序廣播時栖疑,在權(quán)限值相同時萝快,動態(tài)注冊的接收者優(yōu)先接收廣播。
//靜態(tài)注冊
<receiver android:name=".MyBroadcastReceiver" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
//動態(tài)注冊
mBroadcastReceiver = new MyBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BROADCAST_ACTION);
registerReceiver(mBroadcastReceiver, intentFilter);
??最后通過
sendBoradcast(Inteng i)
方法發(fā)送廣播的就可以了锨侯,如果要發(fā)送有序廣播深滚,則調(diào)用sendOrderedBroadcast(intent, receiverPermission, ...)
19. AndroidP新特性
1 室內(nèi)WIFI定位 官册。該功能API在android.net.wifi.rtt下
2 劉海平的支持。能夠通過windowInsets.getDisplayCutout()
獲取一些不應(yīng)該繪制的部分屏幕击敌。
3 增加了多許多通知的支持,優(yōu)化了通知渠道。
4 新的圖片解碼類ImageDecoder
5 Android P引入了一個新的AnimatedImageDrawable類來繪制和顯示GIF和WebP動畫圖像。
20. Asset目錄與res目錄的區(qū)別
** 注意: **
1 assets目錄下的資源文件不會在R.java自動生成ID寿烟,所以讀取assets目錄下的文件必須指定文件的路徑徘六。可以通過AssetManager類來訪問這些文件。比如要讀取assets目錄下的background.png:
Bitmap bgImg = getImageFromAssetFile( "background.png" );
/**
* 從assets中讀取圖片
*/
private Bitmap getImageFromAssetsFile(String fileName)
{
Bitmap image = null;
AssetManager am = getResources().getAssets();
try
{
InputStream is = am.open(fileName);
image = BitmapFactory.decodeStream(is);
is.close();
}
catch (IOException e)
{
e.printStackTrace();
}
return image;
}
2 如果在res/drawable目錄下建了一個名為ppt的子目錄随常,則通過
R.drawable.ppt.xxx
是獲取不到ppt目錄下的xxx文件的,會報 "R.layout.ppt cannot be resolved
" 的錯誤。若在assets目錄下建立一個名為ppt的子目錄逗旁,并將background.png放入其中昙读,則代碼Bitmap bgImg = getImageFromAssetFile( "ppt/background.png" );
可正常運行。
End
筆者的Github Blog,希望各位大大提意見,點個star,謝謝
傳送門:WusyBlog求互粉互贊祸穷,互贊所有文章可以私聊我呆万。哈哈,希望我們的原創(chuàng)文章能讓更多朋友看到,一起變強技矮。
筆者新開通了微信公眾號——飲水思源|wusy 計劃持續(xù)運營,每日為您分享Android干貨、原創(chuàng)文章豌习。微信掃描下方的二維碼關(guān)注我,開發(fā)學(xué)習(xí)路上不迷路。謝謝各位