[筆記] SIP VoIP in Android background 避免被系統殺掉
在前面一文「SIP Voip 在 Android 系統的開發」中,我設計了一個 SIP VoIP APP,但是遇到一個大問題 ---- 就是 APP 會被系統殺掉。為了解決這個問題,在網路上尋找各種方法,首先我們要先把 APP 拆成 Activity 和 Service 兩個部份,如下圖一所示。Service 負責透過 JNI 介面與底層的 SIP、Media Codec...等通訊,而 Activity 則負責使用者顯示的介面,一旦 Activity 關閉後,至少還有 Service 可以在後台繼續運行。
圖一:SIP VoIP 系統架構圖
Activity 與 Service 間的通訊
兩者之間的通訊分成 Activity 到 Service 的方向,以及 Service 到 Activity 的方向。先說 A 到 S 的方向,第一步就是 Activity bind Service,如下面的代碼。接著,建立一個與 Service 的連線,取得 mService 之後,便可以在 Activity 呼叫 Service 的函式了。可以參考網路上其他人的文章與範例說明。
Intent intent = new Intent("com.altigen.siptalk.SipService");
bindService(intent, sc, Context.BIND_AUTO_CREATE);
private ServiceConnection sc = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBound = true;
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
}
@Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
mBound = false;
}
};
第二步是 Service 到 Activity 的通訊方式,它不是用 bind 的方式,而用一種 Android「廣播器」的方法。從設計觀念來說,Service 端發出一個特定的廣播,然後 Activity 收到這個廣播,再從該廣播中取得資料,完成通訊。「廣播器」的設計, Activity 代碼中必須先註冊一個 Receiver 的廣播器,然後做一個 OnReceiver 的接收器,如下:
receiver = new ActivityReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("com.hanya.siptalk.activity");
this.registerReceiver(receiver, filter);
public class ActivityReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
String a = bundle.getString("Sip_LCD");
mTextView.setText(a);
}
而在 Service 這邊只要產生一個廣播的通訊包 (其實是一個Intent),名為 "com.hanya.siptalk.activity",如此一來 Activity 就能夠收到了,其代碼如下:
{
Intent intent = new Intent();
String str = new String( LcdBuf );
intent.putExtra("Sip_LCD", "" + str);
intent.setAction("com.hanya.siptalk.activity");
sendBroadcast( intent );
}
Service 不被系統殺掉的方法
雖然 Service 已經在後台運行了,但是只要 APP 關閉或者經過一段時間後,Service 還是會被系統移除。另外,除了被系統殺掉之外,執行記憶體清除時,後台的 Service 也容易被一起清除掉。
第一個:提高 service 的優先等級
修改這個 AndroidManifest.xml 檔案,如下的內容。新增欄位 android:priority="1000",<service android:name=".SipService" android:enabled="true">
<intent-filter android:priority="1000">
<action android:name="com.hanya.siptalk.SipService"/>
</intent-filter>
</service>
第二個:修改 onStartCommand 回傳值
雖然第一個的方法提高優先等級,但是測試後的結果,service 仍然可能被系統殺掉。因此,再使用第二個方法,START_STICKY 表示 service 被殺掉後,幾秒後便自動再啟動運行,如下:@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "Service onStartCommand");
return Service.START_STICKY;
}
第三個:將 service 改為前台
雖然同時採用前兩個方法,但是測試後的結果,service 仍然可能被系統殺掉。因此,使用最後一個方法,就是把 service 改成前台,如下:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "Service onStartCommand");
startForeground(startId, new Notification());
return Service.START_STICKY;
startForeground(startId, new Notification());
return Service.START_STICKY;
}
參考資料
參考資料
[2] android如何讓service不被殺死-提高程序優先級
[3] 防止Android Service被系统回收的4个方法
留言