Service 是什麼,啓動方式區別,生命週期,如何停用
- Android 的 Service有兩個作用,後臺或跨進程(AIDL)
- 兩個啓動方法,分別是Context.startService()和Context.bindService()。
- 生命週期根據啓動的方式有兩條
- onCreate(), onStart(),onDestroy()。onCreate()在重複啓動時不會執行。
- onCreate(), onBind(),onUnBind(),onDestroy()。只能綁定一次。
-銷燬方法是onDestroy()。
- 執行耗時操作建議使用Intent Service,自帶多線程且自動停止。
BroadcastReceiver是什麼,種類,註冊方式,生命週期
- BroadcastReceiver系統或應用活動通知接收
- 廣播分類
- 普通廣播:
Context.sendBroadcast(Intent myIntent)
- 有序廣播:
Context.sendOrderedBroadcast(intent, receiverPermission)
第二個參數爲[-1000,1000]的優先級,1000爲最高優先等級。 - 異步廣播:
Context.sendStickyBroadcast(Intent myIntent)
,需要權限<uses-permission android:name="android.permission.BROADCAST_STICKY" />
,需要手動去掉removeStickyBroadcast(intent)
。 - 有序異步廣播:
sendStickyOrderedBroadcast(intent, resultReceiver, scheduler, initialCode, initialData, initialExtras)
- 普通廣播:
- 動態註冊,註冊後才存在,需手動解除註冊;靜態(系統)註冊,App未啓動也存在
- 生命週期會調方法:
void onReceive(Context curContext,Intent broadcastMsg)
,只有10秒時間,如果超過則報ANR錯誤。
Broadcast、EventBus和自己實現觀察者模式的不同
- Observable耦合度三者最高
- Broadcast重量級,消耗資源較多,跨進程傳遞消息。與SDK鏈接緊密,許多系統級事件用廣播通知:網絡變化、電量、短信發送和接受狀態
- EventBus輕量且快速,靈活不依賴Context,使用簡單。採用觀察者可能會造成接口膨脹
現在比較流行的開源控件RxJava也是用的觀察者模式,可以很方便的使用RxJava實現個RxBus取代EventBus。
ContentProvider
- ContentProvider使一個應用程序的指定數據集提供給其他應用程序。這些數據可以存儲在文件系統中、在一個SQLite數據庫、或以任何其他合理的方式。其他應用可以通過ContentResolver類(見ContentProviderAccessApp例子)從該內容提供者中獲取或存入數據
- 通過Uri進行訪問。
Uri uri = Uri.parse("content://com.bing.provider.personprovider/person")
- ContentUris類使用
Uri uri = Uri.parse("content://com.bing.provider.personprovider/person");
Uri resultUri = ContentUris.withAppendedId(uri, 10);
//生成後的Uri爲:content://com.bing.provider.personprovider/person/10
Uri uri = Uri.parse("content://com.ljq.provider.personprovider/person/10")
long personid = ContentUris.parseId(uri);
//獲取的結果爲:10
Android系統中GC什麼情況下會出現內存泄露呢
導致內存泄露主要的原因是:沒有釋放申請的內存空間,垃圾回收器GC無法回收內存。如下情況能導致內存溢出:
- 數據鏈接沒有關閉。如數據庫contentprovider,io,sokect,cursor等
- (匿名)內部類對象會持有宿主類的強應用this。如果是new Thread這類操作,線程沒有執行結束時當前Activity不會被回收。(常見Handler操作)
- Context引用。TextView等等都會持有上下文引用,如果有static drawable,就會導致內存無法釋放
- 靜態集合類。,ashMap,Vector等。如果是靜態集合,要及時setnull,否則就會一直持有這些對象
- observer 我們在使用監聽器的時候,addxxxListener(),記得不用時removexxxListener,否則內存leak
- Bitmap對象不使用時,採用recycle()釋放內存
Android UI中的View如何刷新
要分清View刷新的情景:多線程和雙緩衝。
- 不使用多線程和雙緩衝。View發生改變重繪,使用View.invalidate()激活View.onDraw()方法。
- 使用多線程和不使用雙緩衝。注意非UI線程不能對UI進行直接操作,需要用Handler進行線程通訊,在UI線程對View進行重繪。
- 使用多線程和雙緩衝。SurfaceView直接實現了雙緩衝,實現Surfaceholder.Callback接口。
Surfaceholder.lockCanvas()
鎖定畫布,Surfaceholder.unlockCanvasandPost()
解鎖畫布。
事件分發機制
Handler機制,線程通訊
Android提供Handler來滿足線程間的通訊。
- Handler:Message處理和發送。
- 通過Looper獲取MessageQueue中的消息(FIFO)
- 通過Looper將消息放入MessageQueue
- Looper:輪詢器
- 每個線程有且只有一個私人的Looper
- 初始化Looper對象,此對象會擁有一個Message Queue對象
- 主線程(UI線程)會自動初始化Looper。其他線程需要
Looper.prepare()
初始化,Looper.loop()
開始輪詢
- MessageQueue:消息隊列
- 存放一個線程的Message所有
- Message被髮送給Hander並處理後不會回收或刪除,會被標記爲閒置狀態
- Handler發送消息是先檢索Message Queue中沒有沒閒置Message,有直接複用,否則新建Message。減少GC回收工作壓力,增加內存Leak危險
Handler使用時要特別注意內存Leak:
- 要使用 static 靜態類定義Handler派生類
- static 下訪問當前對象的字段屬性時需要弱引用(WeakReference)
- 在Activity銷燬時調用 Handler.removeMessages()將MessageQueue中的消息全部移除
- 自定義控件在定義Handler時,儘量使用new Handler(Looper.getMainLooper()), 不要使用new Handler()。因爲後者默認在主線程中執行,事實上有些View的創建在子線程中執行。
進程通訊(AIDL等)
- 訪問其他App的Activity:需要App開放支持
- 內容提供者Content Provider :使用Content Provider提供數據,使用Content Resolver讀取數據。
- 廣播Broadcast:被動接受信息
- AIDL服務:Android Interface Definition Language 安卓接口定義語言
- AIDL服務提供程序:建立AIDL文件;在文件中創建接口申明方法;註冊Service實現聲明的接口方法
- AIDL服務使用程序:copy自動生成的Java文件;建立ServiceConnection對象並綁定AIDL服務;獲取AIDL中的接口對象並調用放發獲取Value
AIDL步驟(一):提供AIDL服務
在package目錄下建立aidl.aidl文件,申明方法,類似接口
package 包名.aidl;
interface IMyService {
//爲AIDL服務的接口方法,調用AIDL服務的程序需要調用該方法
String getValue();
}
ODT會在gen目錄下產生一個IMyService.java文件,此文件ODT自動維護,開發者無需在意。
public class MyService extends Service {
// IMyService.Stub類是根據IMyService.aidl文件生成的類
// 該類中包含了接口方法(getValue)
public class MyServiceImpl extends IMyService.Stub {
@Override
public String getValue() throws RemoteException {
return "從AIDL服務獲得的值." ;
}
}
@Override
public IBinder onBind(Intent intent) {
//該方法必須返回MyServiceImpl類的對象實例
return new MyServiceImpl();
}
}
manifest配置信息
<!-- 註冊服務 -->
<service android:name=".MyService" >
<intent-filter>
<!-- 指定調用AIDL服務的ID -->
<action android:name="net.blogjava.mobile.aidlservice.IMyService" />
</intent-filter>
</service>
AIDL步驟(二):使用AIDL服務
public class Main extends Activity implements OnClickListener {
private IMyService myService = null;
// 創建ServiceConnection對象
private ServiceConnection serviceConnection = new ServiceConnection(){
@Override
public void onServiceConnected(ComponentName name, IBinder service){
// 獲得AIDL服務對象
// IMyService.java是AIDL提供工程中自動生成的
myService = IMyService.Stub.asInterface(service);
try {
// 調用AIDL服務對象中的getValue方法
// 並以對話框中顯示該方法的返回值
new AlertDialog
.Builder(Main.this)
.setMessage(myService.getValue())
.setPositiveButton("確定", null)
.show();
}catch (Exception e) {
}
}
@Override
public void onServiceDisconnected(ComponentName name)
{
}
};
@Override
public void onClick(View view){
//綁定AIDL服務
bindService(new Intent("提供程序包名.aidl.IMyService"),
serviceConnection, Context.BIND_AUTO_CREATE);
}
}
如何對 Android 應用進行性能分析
android 性能主要之響應速度 和UI刷新速度。
可以參考博客:Android系統性能調優工具介紹
首先從函數的耗時來說,有一個工具TraceView 這是androidsdk自帶的工作,用於測量函數耗時的。
UI佈局的分析,可以有2塊,一塊就是Hierarchy Viewer 可以看到View的佈局層次,以及每個View刷新加載的時間。
這樣可以很快定位到那塊layout & View 耗時最長。
還有就是通過自定義View來減少view的層次。
請介紹下Android的數據存儲方式。
- 使用Shared Preferences存儲數據,用來存儲key-value,pairs格式的數據,它是一個輕量級的鍵值存儲機制,只可以存儲基本數據類型。
- 使用文件存儲數據,通過FileInputStream和FileOutputStream對文件進行操作。在Android中,文件是一個應用程序私有的,一個應用程序無法讀寫其他應用程序的文件。
- 使用SQLite數據庫存儲數據,Android提供的一個標準數據庫,支持SQL語句。
- 使用Content Provider存儲數據,是所有應用程序之間數據存儲和檢索的一個橋樑,它的作用就是使得各個應用程序之間實現數據共享。它是一個特殊的存儲數據的類型,它提供了一套標準的接口用來獲取數據,操作數據。系統也提供了音頻、視頻、圖像和個人信息等幾個常用的Content Provider。如果你想公開自己的私有數據,可以創建自己的Content Provider類,或者當你對這些數據擁有控制寫入的權限時,將這些數據添加到Content Provider中實現共享。外部訪問通過Content Resolver去訪問並操作這些被暴露的數據。
- 使用網絡存儲數據
描述一下Intent 和 Intent Filter
- Intent在Android中被翻譯爲”意圖”,他是三種應用程序基本組件-Activity,Service和broadcast receiver之間相互激活的手段。在調用Intent名稱時使用ComponentName也就是類的全名時爲顯示調用。這種方式一般用於應用程序的內部調用,因爲你不一定會知道別人寫的類的全名。
- Intent Filter是指意圖過濾,不出現在代碼中,而是出現在android Manifest文件中,以
<intent-filter>
的形式。(有一個例外是broadcast receiver的intent
filter是使用Context.registerReceiver()來動態設定的,其中intent filter也是在代碼中創建的)而一個intent有action,data,category等字段。一個隱式intent爲了能夠被某個intent filter接收,必須通過3個測試,一個intent爲了被某個組件接收,則必須通過它所有的intent filter中的一個。
談談對Android NDK的理解。
android NDK是一套工具,允許Android應用開發者嵌入從C、C++源代碼編譯來的本地機器代碼到各自的應用軟件包中。
1、 NDK是一系列工具的集合。
NDK提供了一系列的工具,幫助開發者快速開發C(或C++)的動態庫,並能自動將so和java應用一起打包成apk。這些工具對開發者幫助時巨大的。
NDK集成了交叉編輯器,並提供了相應的mk文件隔離CPU、平臺、API等差異,開發人員只需要簡單修改mk文件(指出“那些文件需要編譯”、“編譯特性要求”等),就可以創建出so。NDK可以自動將so和Java應用一起打包,極大的減輕了開發人員的打包工作。
2、NDK提供了一份穩定、功能有限的API頭文件聲明。
這些API支持的功能非常有限,包含有:C標準庫(libc)、標準數學庫(libm)、壓縮庫(libz)、log庫(liblog)。