Android優(yōu)化工具
TraceView
raceview 是Android SDK中自帶的一個(gè)工具,可以 對(duì)應(yīng)用中方法調(diào)用耗時(shí)進(jìn)行統(tǒng)計(jì)分析,是Android性能優(yōu)化和分析時(shí)一個(gè)很重要的工具。使用方法:第一種是在相應(yīng)進(jìn)行traceview分析的開始位置和結(jié)束位置分別調(diào)用startMethodTracing和stopMethodTracing方法。第二種是在ddms中直接使用,即在ddms中在選中某個(gè)要進(jìn)行監(jiān)控的進(jìn)程后,點(diǎn)擊如圖所示的小圖標(biāo)開始監(jiān)控,在監(jiān)控結(jié)束時(shí)再次點(diǎn)擊小圖標(biāo),ddms會(huì)自動(dòng)打開traceview視圖。
Systrace
Systrace是Android4.1中新增的性能數(shù)據(jù)采樣和分析工具。它可幫助開發(fā)者收集Android關(guān)鍵子系統(tǒng)(如surfaceflinger、WindowManagerService等Framework部分關(guān)鍵模塊、服務(wù))的運(yùn)行信息,從而幫助開發(fā)者更直觀的分析系統(tǒng)瓶頸,改進(jìn)性能。
Systrace的功能包括跟蹤系統(tǒng)的I/O操作、內(nèi)核工作隊(duì)列、CPU負(fù)載以及Android各個(gè)子系統(tǒng)的運(yùn)行狀況等。
Dalvik與ART的區(qū)別?
Dalvik是Google公司自己設(shè)計(jì)用于Android平臺(tái)的Java虛擬機(jī)。Dalvik虛擬機(jī)是Google等廠商合作開發(fā)的Android移動(dòng)設(shè)備平臺(tái)的核心組成部分之一,它可以支持已轉(zhuǎn)換為.dex(即Dalvik Executable)格式的Java應(yīng)用程序的運(yùn)行,.dex格式是專為Dalvik應(yīng)用設(shè)計(jì)的一種壓縮格式,適合內(nèi)存和處理器速度有限的系統(tǒng)。Dalvik經(jīng)過優(yōu)化,允許在有限的內(nèi)存中同時(shí)運(yùn)行多個(gè)虛擬機(jī)的實(shí)例,并且每一個(gè)Dalvik應(yīng)用作為獨(dú)立的Linux進(jìn)程執(zhí)行。獨(dú)立的進(jìn)程可以防止在虛擬機(jī)崩潰的時(shí)候所有程序都被關(guān)閉。
ART代表Android Runtime,其處理應(yīng)用程序執(zhí)行的方式完全不同于Dalvik,Dalvik是依靠一個(gè)Just-In-Time(JIT)編譯器去解釋字節(jié)碼。開發(fā)者編譯后的應(yīng)用代碼需要通過一個(gè)解釋器在用戶的設(shè)備上運(yùn)行,這一機(jī)制并不高效,但讓應(yīng)用能更容易在不同硬件和架構(gòu)上運(yùn)行。ART則完全改變了這套做法,在應(yīng)用安裝的時(shí)候就預(yù)編譯字節(jié)碼到機(jī)器語言,這一機(jī)制叫 Ahead-Of-Time(AOT) 編譯 。在移除解釋代碼這一過程后,應(yīng)用程序執(zhí)行將更有效率,啟動(dòng)更快。
ART優(yōu)點(diǎn):
- 系統(tǒng)性能的顯著提升
- 應(yīng)用啟動(dòng)更快、運(yùn)行更快、體驗(yàn)更流暢、觸感反饋更及時(shí)
- 更長(zhǎng)的電池續(xù)航能力
4.支持更低的硬件
ART缺點(diǎn):
- 更大的存儲(chǔ)空間占用,可能會(huì)增加10%-20%
- 更長(zhǎng)的應(yīng)用安裝時(shí)間
Android動(dòng)態(tài)權(quán)限?
Android 6.0 動(dòng)態(tài)權(quán)限,這里以撥打電話的權(quán)限為例,首先需要在Manifest里添加android.permission.CALL_PHONE權(quán)限。
int checkCallPhonePermission = ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE);
if (checkCallPhonePermission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
this, new String[]{Manifest.permission.CALL_PHONE}, REQUEST_CODE_ASK_CALL_PHONE);
return;
}
```
在獲取權(quán)限后,可以重寫Activity.onRequestPermissionsResult方法來進(jìn)行回調(diào)。
```
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
switch (requestCode) {
case REQUEST_CODE_ASK_CALL_PHONE:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission Granted
Toast.makeText(MainActivity.this, "CALL_PHONE Granted", Toast.LENGTH_SHORT)
.show();
} else {
// Permission Denied
Toast.makeText(MainActivity.this, "CALL_PHONE Denied", Toast.LENGTH_SHORT)
.show();
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
ViewPager如何判斷左右滑動(dòng)?
實(shí)現(xiàn)OnPageChangeListener并重寫onPageScrolled方法,通過參數(shù)進(jìn)行判斷。
ListView與RecyclerView
ViewHolder:在ListView中,ViewHolder需要自己來定義,且這只是一種推薦的使用方式,不使用當(dāng)然也可以,這不是必須的。而在RecyclerView中使用 RecyclerView.ViewHolder 則變成了必須,盡管實(shí)現(xiàn)起來稍顯復(fù)雜,但它卻解決了ListView面臨的上述不使用自定義ViewHolder時(shí)所面臨的問題。
LayoutManager:RecyclerView提供了更加豐富的布局管理。LinearLayoutManager,可以支持水平和豎直方向上滾動(dòng)的列表。StaggeredGridLayoutManager,可以支持交叉網(wǎng)格風(fēng)格的列表,類似于瀑布流或者Pinterest。GridLayoutManager,支持網(wǎng)格展示,可以水平或者豎直滾動(dòng),如展示圖片的畫廊。
ItemAnimator:相比較于ListView,RecyclerView.ItemAnimator 則被提供用于在RecyclerView添加、刪除或移動(dòng)item時(shí)處理動(dòng)畫效果。
ItemDecoration:RecyclerView在默認(rèn)情況下并不在item之間展示間隔符。如果你想要添加間隔符,你必須使用RecyclerView.ItemDecoration類來實(shí)現(xiàn)。
ListView可以設(shè)置選擇模式,并添加MultiChoiceModeListener,RecyclerView中并沒有提供這樣功能。
SpannableString
TextView通常用來顯示普通文本,但是有時(shí)候需要對(duì)其中某些文本進(jìn)行樣式、事件方面的設(shè)置。Android系統(tǒng)通過SpannableString類來對(duì)指定文本進(jìn)行相關(guān)處理??梢酝ㄟ^SpannableString來對(duì)TextView進(jìn)行富文本設(shè)置,包括但不限于文本顏色,刪除線,圖片,超鏈接,字體樣式
描述一下Android手機(jī)啟動(dòng)過程和App啟動(dòng)過程?
Android手機(jī)啟動(dòng)過程
當(dāng)我們開機(jī)時(shí),首先是啟動(dòng)Linux內(nèi)核,在Linux內(nèi)核中首先啟動(dòng)的是init進(jìn)程,這個(gè)進(jìn)程會(huì)去讀取配置文件system\core\rootdir\init.rc配置文件,這個(gè)文件中配置了Android系統(tǒng)中第一個(gè)進(jìn)程Zygote進(jìn)程。
啟動(dòng)Zygote進(jìn)程 --> 創(chuàng)建AppRuntime(Android運(yùn)行環(huán)境) --> 啟動(dòng)虛擬機(jī) --> 在虛擬機(jī)中注冊(cè)JNI方法 --> 初始化進(jìn)程通信使用的Socket(用于接收AMS的請(qǐng)求) --> 啟動(dòng)系統(tǒng)服務(wù)進(jìn)程 --> 初始化時(shí)區(qū)、鍵盤布局等通用信息 --> 啟動(dòng)Binder線程池 --> 初始化系統(tǒng)服務(wù)(包括PMS,AMS等等) --> 啟動(dòng)Launcher
App啟動(dòng)過程
應(yīng)用的啟動(dòng)是從其他應(yīng)用調(diào)用startActivity開始的。通過代理請(qǐng)求AMS啟動(dòng)Activity。
AMS創(chuàng)建進(jìn)程,并進(jìn)入ActivityThread的main入口。在main入口,主線程初始化,并loop起來。主線程初始化,主要是實(shí)例化ActivityThread和ApplicationThread,以及MainLooper的創(chuàng)建。ActivityThread和ApplicationThread實(shí)例用于與AMS進(jìn)程通信。
應(yīng)用進(jìn)程將實(shí)例化的ApplicationThread,Binder傳遞給AMS,這樣AMS就可以通過代理對(duì)應(yīng)用進(jìn)程進(jìn)行訪問。
AMS通過代理,請(qǐng)求啟動(dòng)Activity。ApplicationThread通知主線程執(zhí)行該請(qǐng)求。然后,ActivityThread執(zhí)行Activity的啟動(dòng)。
Activity的啟動(dòng)包括,Activity的實(shí)例化,Application的實(shí)例化,以及Activity的啟動(dòng)流程:create、start、resume。
可以看到 入口Activity其實(shí)是先于Application實(shí)例化,只是onCreate之類的流程,先于Activity的流程。另外需要scheduleLaunchActivity,在ApplicationThreaad中,對(duì)應(yīng)AMS管理Activity生命周期的方法都以scheduleXXXActivity,ApplicationThread在Binder線程中,它會(huì)向主線程發(fā)送消息,ActivityThread的Handler會(huì)調(diào)用相應(yīng)的handleXXXActivity方法,然后會(huì)執(zhí)行performXXXActivity方法,最終調(diào)用Activity的onXXX方法
Include、Merge、ViewStub的作用
Include:布局重用
<include />標(biāo)簽可以使用單獨(dú)的layout屬性,這個(gè)也是必須使用的。
可以使用其他屬性。<include />標(biāo)簽若指定了ID屬性,而你的layout也定義了ID,則你的layout的ID會(huì)被覆蓋,解決方案。
在<include />標(biāo)簽中所有的android:layout_*都是有效的,前提是必須要寫layout_width和layout_height兩個(gè)屬性。
布局中可以包含兩個(gè)相同的include標(biāo)簽
Merge:減少視圖層級(jí),多用于替換FrameLayout或者當(dāng)一個(gè)布局包含另一個(gè)時(shí),<merge/>標(biāo)簽消除視圖層次結(jié)構(gòu)中多余的視圖組。
例如:你的主布局文件是垂直布局,引入了一個(gè)垂直布局的include,這是如果include布局使用的LinearLayout就沒意義了,使用的話反而減慢你的UI表現(xiàn)。這時(shí)可以使用標(biāo)簽優(yōu)化。
ViewStub:需要時(shí)使用。優(yōu)點(diǎn)是當(dāng)你需要時(shí)才會(huì)加載,使用他并不會(huì)影響UI初始化時(shí)的性能。需要使用時(shí)調(diào)用inflate()。
Asset目錄與res目錄的區(qū)別
assets 目錄:不會(huì)在R.java文件下生成相應(yīng)的標(biāo)記,assets文件夾可以自己創(chuàng)建文件夾,必須使用AssetsManager類進(jìn)行訪問,存放到這里的資源在運(yùn)行打包的時(shí)候都會(huì)打入程序安裝包中,
res 目錄:會(huì)在R.java文件下生成標(biāo)記,這里的資源會(huì)在運(yùn)行打包操作的時(shí)候判斷哪些被使用到了,沒有被使用到的文件資源是不會(huì)打包到安裝包中的。
res/raw 和 assets文件夾來存放不需要系統(tǒng)編譯成二進(jìn)制的文件,例如字體文件等
res/raw不可以有目錄結(jié)構(gòu),而assets則可以有目錄結(jié)構(gòu),也就是assets目錄下可以再建立文件夾
System.gc && Runtime.gc
System.gc和Runtime.gc是等效的,在System.gc內(nèi)部也是調(diào)用的Runtime.gc。調(diào)用兩者都是通知虛擬機(jī)要進(jìn)行g(shù)c,但是否立即回收還是延遲回收由JVM決定。兩者唯一的區(qū)別就是一個(gè)是類方法,一個(gè)是實(shí)例方法。
Application 在多進(jìn)程下會(huì)多次調(diào)用 onCreate() 么?
當(dāng)采用多進(jìn)程的時(shí)候,比如下面的Service 配置:
<service
android:name=".MyService"
android:enabled="true"
android:exported="false"
android:process=":remote" />
android:process 屬性中 :的作用就是把這個(gè)名字附加到你的包所運(yùn)行的標(biāo)準(zhǔn)進(jìn)程名字的后面作為新的進(jìn)程名稱。
這樣配置會(huì)調(diào)用 onCreate() 兩次。
Theme && Style
Style 是一組外觀、樣式的屬性集合,適用于 View 和 Window 。
Theme 是一種應(yīng)用于整個(gè) Activity 或者 Application ,而不是獨(dú)立的 View。
SQLiteOpenHelper.onCreate() 調(diào)用時(shí)機(jī)?
在調(diào)getReadableDatabase或getWritableDatabase時(shí),會(huì)判斷指定的數(shù)據(jù)庫是否存在,不存在則調(diào)SQLiteDatabase.onCreate創(chuàng)建, onCreate只在數(shù)據(jù)庫第一次創(chuàng)建時(shí)才執(zhí)行。
Removecallback 失效?
Removecallback 必須是同一個(gè)Handler才能移除。
Toast 如果會(huì)短時(shí)間內(nèi)頻繁顯示怎么優(yōu)化?
public void update(String msg){
toast.setText(msg);
toast.show();
}
Notification 如何優(yōu)化?
可以通過 相同 ID 來更新 Notification 。
應(yīng)用怎么判斷自己是處于前臺(tái)還是后臺(tái)?
主要是通過 getRunningAppProcesses() 方法來實(shí)現(xiàn)。
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.processName.equals(getPackageName())) {
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
Log.d(TAG, String.format("Foreground App:%s", appProcess.processName));
} else {
Log.d(TAG, "Background App:" + appProcess.processName);
}
}
}
FragmentPagerAdapter 和 FragmentStateAdapter 的區(qū)別?
FragmentStatePagerAdapter 是 PagerAdapter 的子類,這個(gè)適配器對(duì)實(shí)現(xiàn)多個(gè) Fragment 界面的滑動(dòng)是非常有用的,它的工作方式和listview是非常相似的。當(dāng)Fragment對(duì)用戶不可見的時(shí)候,整個(gè)Fragment會(huì)被銷毀,只會(huì)保存Fragment的保存狀態(tài)?;谶@樣的特性,F(xiàn)ragmentStatePagerAdapter 比 FragmentPagerAdapter 更適合用于很多界面之間的轉(zhuǎn)換,而且消耗更少的內(nèi)存資源。
Bitmap的本質(zhì)?
本質(zhì)是 SkBitmap 詳見 Pocket
SurfaceView && View && GLSurfaceView
View:顯示視圖,內(nèi)置畫布,提供圖形繪制函數(shù)、觸屏事件、按鍵事件函數(shù)等;必須在UI主線程內(nèi)更新畫面,速度較慢。
SurfaceView:基于view視圖進(jìn)行拓展的視圖類,更適合2D游戲的開發(fā);View的子類,類似使用雙緩機(jī)制,在新的線程(也可以在UI線程)中更新畫面所以刷新界面速度比 View 快,但是會(huì)涉及到線程同步問題。
GLSurfaceView:openGL專用?;赟urfaceView視圖再次進(jìn)行拓展的視圖類,專用于3D游戲開發(fā)的視圖。
文末送福利啦??!
我總結(jié)出了互聯(lián)網(wǎng)公司Android程序員面試涉及到的絕大部分面試題及答案,并整理做成了文檔,以及系統(tǒng)的進(jìn)階學(xué)習(xí)視頻資料,免費(fèi)分享給大家。
(包括Java在Android開發(fā)中應(yīng)用、APP框架知識(shí)體系、高級(jí)UI、全方位性能調(diào)優(yōu),NDK開發(fā),音視頻技術(shù),人工智能技術(shù),跨平臺(tái)技術(shù)等技術(shù)資料),希望能幫助到你面試前的復(fù)習(xí),且找到一個(gè)好的工作,也節(jié)省大家在網(wǎng)上搜索資料的時(shí)間來學(xué)習(xí)。
資料領(lǐng)取方式:點(diǎn)擊鏈接加入群聊【Android開發(fā)交流】:https://jq.qq.com/?_wv=1027&k=57fcAxd,找群管理免費(fèi)領(lǐng)取。備注一下簡(jiǎn)書看到的來領(lǐng)取資料就可以了!