Android 的執行緒是以 Linux pthread 及 Java Thread 實作,從APP的角度來看,有 UI、Binder、Background 執行緒。
分類
- UI Thread
在 APP 開始時被啟動,在 Linux process 生命週期內保持存活,UI Thread 是 APP 的 Main Thread,用來執行 Android Component 以及更新 UI - Binder Thread
用在不同 process 的 thread 之間互相溝通,每一個 process 會維護一個 thread pool,處理從其他 process 進來的 requests,包含系統服務、Intent、Content Provider、Service - Background Thread
APP 建立的執行緒都是背景執行緒,他是 UI Thread 的 child
adb shell ps
用以下的指令可以查看 android device 上的 process 資訊。
# 顯示 thread 資訊
adb shell ps -t
# 顯示 fg, bg
adb shell ps -P
APP 裡面的執行緒跟 Linux 的 niceness value 相對應,可以用這兩個方式調整 Thread priority
java.lang.Thread
setPriority(int priority)
android.os.Process
Process.setThreadPriority(int priority)
Process.setThreadPriority(int threadId, int priority)
Thread.setPriority(int) | Linux niceness |
---|---|
1 (Thread.MIN_PRIORITY) | 19 |
2 | 16 |
3 | 13 |
4 | 10 |
5 (Thread.NORM_PRIORITY) | 0 |
6 | -2 |
7 | -4 |
8 | -5 |
9 | -6 |
10 | -8 |
Android 控制群組
對 APP 來說最重要的兩個控制群組是 foreground 及 background,foreground 表示目前的 APP 是在前景,可視狀態,按下 Home 就會讓 APP 裡面所有的 Thread 都變成 background group。
如果用以下指令,可降低 Thread priority 並讓這個 thread 永遠都在 background group。
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)
Android 的 IPC
當 thread 之間沒有共用的記憶體區塊時,android 透過 binder framework 進行 IPC。
Linux 的 IPC 有: 信號、管道、訊息佇列、semaphore與共用記憶體,而 Android RPC 已經被 binder framework 取代。
RPC 的步驟為
1. marshalling: 封裝方法及資料
2. 將 marshal 的資料傳送到遠端 process
3. 在遠端 process 進行 unmarshalling,並執行 RPC
4. 將處理結果 return value 回傳給原始的 process
Binder
binder 讓 APP 在不同 process 的 thread 之間互相傳遞資料及進行 RPC,資料以 android.os.Parcel 物件組成,內容包含參數以及實作 android.os.Parcelable 介面的自訂物件,由 transact() 直到 onTransact() 到伺服器行程。
Transaction Thread Pool 可同時處理 16個 RPC。
IPC 是雙向的,也可以設定 IBinder.FLAG_ONEWAY 進行單向沒有回傳值的 RPC。
AIDL
AIDL: Android Interface Definition Language
當 process 想要開放功能給其他 process 使用時,可編輯 .aidl 檔案,然後產生 IPC 的 java codes。
AIDL 透過 Proxy 及 Stub 進行 RPC 的通訊過程如下
- 同步 RPC
在 .aidl 定義介面,然後用工具產生 Proxy 與 Stub。
interface ISynchronous {
String getThreadName()
}
由於 Stub 可能會發生:(1) 執行時間很久 (2) Blocking (3) 呼叫共用資料的狀況,最好在客戶端要用 worker thread 進行 RPC 呼叫,而不要用 UI thread。
- 非同步 RPC
可定義整個介面都是非同步的 oneway
oneway interface IAsynchronousInterface {
void method1();
void method2();
}
也可以只定義某個方法是 oneway
interface IAsynchronousInterface {
oneway void method1();
void method2();
}
使用 binder 進行訊息傳遞
在不同 process 的 thread 可透過 binder 傳遞訊息
WorkerThreadService 是在伺服器行程中執行,與客戶端的 Activity 溝通,Service 會實作 Messenger,將它傳遞給 Activity,而 Activity 會回傳 Message 物件給 Service。
public class WorkerThreadService extends Service {
private static final String TAG = "WorkerThreadService";
WorkerThread mWorkerThread;
Messenger mWorkerMessenger;
@Override
public void onCreate() {
super.onCreate();
// 產生 Service 時,就建立 worker thread,bind 過來的客戶端也是使用 worker thread
mWorkerThread = new WorkerThread();
mWorkerThread.start();
}
// Worker thread has prepared a looper and handler.
private void onWorkerPrepared() {
Log.d(TAG, "onWorkerPrepared");
mWorkerMessenger = new Messenger(mWorkerThread.mWorkerHandler);
synchronized(this) {
notifyAll();
}
}
// 繫結過來的客戶端會收到 messenger 的 IBinder 物件,客戶端才能跟 server 溝通
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
synchronized (this) {
while (mWorkerMessenger == null) {
try {
wait();
} catch (InterruptedException e) {
// Empty
}
}
}
return mWorkerMessenger.getBinder();
}
@Override
public void onDestroy() {
super.onDestroy();
mWorkerThread.quit();
}
private class WorkerThread extends Thread {
Handler mWorkerHandler;
@Override
public void run() {
Looper.prepare();
mWorkerHandler = new Handler() {
// worker thread 的 message handler
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
try {
// 雙向訊息溝通的機制,將新的 Message 傳回 Activity
msg.replyTo.send(Message.obtain(null, msg.what, 0, 0));
} catch (RemoteException e) {
Log.e(TAG, e.getMessage());
}
break;
case 2:
Log.d(TAG, "Message received");
break;
}
}
};
onWorkerPrepared();
Looper.loop();
}
public void quit() {
mWorkerHandler.getLooper().quit();
}
}
}
- 單向訊息
在客戶端,Activity繫結到伺服器行程中的 service 並傳遞訊息
public class MessengerOnewayActivity extends Activity {
private boolean mBound = false;
private Messenger mRemoteService = null;
private ServiceConnection mRemoteConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// 連上 service,由伺服器端回傳的 binder 建立 Messenger
mRemoteService = new Messenger(service);
mBound = true;
}
public void onServiceDisconnected(ComponentName className) {
mRemoteService = null;
mBound = false;
}
};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messenger_client);
}
public void onBindClick(View v) {
// 繫結到遠端服務
Intent intent = new Intent("com.eat.chapter5.ACTION_BIND");
bindService(intent, mRemoteConnection, Context.BIND_AUTO_CREATE);
}
public void onUnbindClick(View v) {
if (mBound) {
unbindService(mRemoteConnection);
mBound = false;
}
}
public void onSendClick(View v) {
if (mBound) {
try {
// 點擊按鈕時傳遞訊息
mRemoteService.send(Message.obtain(null, 2, 0, 0));
} catch (RemoteException e) {
// Empty
}
}
}
}
- 雙向訊息
傳遞的 messenge 在 Message.replyTo 裡面存放指向 Messenger 的 reference,可透過它建立雙向溝通機制。
public class MessengerTwowayActivity extends Activity {
private static final String TAG = "MessengerTwowayActivity";
private boolean mBound = false;
private Messenger mRemoteService = null;
private ServiceConnection mRemoteConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mRemoteService = new Messenger(service);
mBound = true;
}
public void onServiceDisconnected(ComponentName className) {
mRemoteService = null;
mBound = false;
}
};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messenger_client);
}
public void onBindClick(View v) {
Intent intent = new Intent("com.eat.chapter5.ACTION_BIND");
bindService(intent, mRemoteConnection, Context.BIND_AUTO_CREATE);
}
public void onUnbindClick(View v) {
if (mBound) {
unbindService(mRemoteConnection);
mBound = false;
}
}
public void onSendClick(View v) {
if (mBound) {
try {
Message msg = Message.obtain(null, 1, 0, 0);
// 建立被傳送到遠端的 Messenger,此 Messenger 存放目前執行緒的 Handler reference,它會執行來自其他 process 的訊息
msg.replyTo = new Messenger(new Handler() {
@Override
public void handleMessage(Message msg) {
Log.d(TAG, "Message sent back - msg.what = " + msg.what);
}
});
mRemoteService.send(msg);
} catch (RemoteException e) {
Log.e(TAG, e.getMessage());
}
}
}
}
沒有留言:
張貼留言