Andriod死亡通知メカニズムを利用してサービスにクライアントがkillされたと伝えた.
8192 ワード
Androidは、特定のアプリケーションのニーズを満たすために死亡通知と呼ばれるメカニズムを提供しています.
あるプロセスは別のプロセスが生存しているかどうかを知る必要がある.あるいは、あるプロセスがkillされたとき、別のプロセスはこのことを知ることを望んでいます.
一般的には、あるboundサービスがクライアントがkillされているかどうかに関心を持っています.
なぜサービスがクライアントにkillされたのかと聞かれるかもしれません.
適用シーン:
たとえば、boundサービスはbindから来たclientにリソースを割り当てる可能性があります.clientがreleaseまたはunbindを呼び出すとリソースが解放されますが、
ある時clientは確かにkillされ、サービスが知らない場合、割り当てられたリソースは解放されません.
AndroidはDeathRecipientというインタフェースを提供しています.
1.clientで1つのBinderをnewし、次に別のプロセスに送信します.通常はBoundサービスです.
2.別のプロセスの死亡情報に関心を持つプロセス(通常はサービス)でDeathRecipientを実現するだけです
3.クライアントから送信されたbinderを呼び出すlinkToDeathメソッド
public abstract void linkToDeath (IBinder.DeathRecipient recipient, int flags)
Added in API level 1
Register the recipient for a notification if this binder goes away. If this binder object unexpectedly goes away (typically because its hosting process has been killed), then the given
You will only receive death notifications for remote binders, as local binders by definition can't die without you dying as well.
Throws
RemoteException
if the target IBinder's process has already died.
See Also
DeathRecipient is an interface for receiving a callback when the process hosting an IBinder has gone away.
DeathRecipientについては、公式サイトのドキュメントを参照してください.
http://developer.android.com/reference/android/os/IBinder.DeathRecipient.html
-------------------------------------------
テスト手順、appを起動し、startをクリックし、adb shell psでcomを表示します.example.testserviceプロセスID、adb shell kill pidでclient killを落とし、logをチェック
Log.d(TAG, "client has died");printが出てくるかどうか
Sample code:
//Client TestActivity.java
public class TestActivity extends Activity { private String TAG = "TestService"; private Button mStartBtn; private Button mStopBtn; private Button mBindBtn; private Button mUnbindBtn; ClickListener mClickListener = new ClickListener(); private Intent mIntent = new Intent("com.example.action.TEST"); private IBinder mBinder = new Binder(); private ITest mTest = null; private ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { //TODO Auto-generated method stub Log.d(TAG, "onServiceDisconnected"); } @Override public void onServiceConnected(ComponentName name, IBinder service) { //TODO Auto-generated method stub Log.d(TAG, "onServiceConnected:"+ name); mTest = ITest.Stub.asInterface(service); try { mTest.setBinder(mBinder); } catch (RemoteException e) { //TODO Auto-generated catch block e.printStackTrace(); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test_service); mStartBtn = (Button)findViewById(R.id.start); mStopBtn = (Button)findViewById(R.id.stop); mBindBtn = (Button)findViewById(R.id.bind); mUnbindBtn = (Button)findViewById(R.id.unbind); mStartBtn.setOnClickListener(mClickListener); mStopBtn.setOnClickListener(mClickListener); mBindBtn.setOnClickListener(mClickListener); mUnbindBtn.setOnClickListener(mClickListener); } @Override public boolean onCreateOptionsMenu(Menu menu) { //Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.activity_test_service, menu); return true; } private class ClickListener implements OnClickListener{ @Override public void onClick(View v) { int id = v.getId(); if(id == R.id.start){ startService(mIntent); }else if(id == R.id.stop){ stopService(mIntent); }else if(id == R.id.bind){ bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE); }else if(id == R.id.unbind){ unbindService(mServiceConnection); } } } }
//ITest .aidl package com.example.testservice;/** Example service interface */interface ITest {
int getPid(); void setBinder(IBinder client); }
//TestService.java
public class TestService extends Service{ private String TAG = "TestService"; private TestApi mTestApi = new TestApi(); private IBinder mClient = null; @Override public IBinder onBind(Intent intent) { Log.d(TAG, "Onbind() action="+ intent.getAction()); return mTestApi; } private class TestDeathRecipient implements DeathRecipient{ @Override public void binderDied() { Log.d(TAG, "client has died"); } } private class TestApi extends ITest.Stub{ @Override public int getPid() throws RemoteException { return (int)Thread.currentThread().getId(); } @Override public void setBinder(IBinder client) throws RemoteException { mClient = client; mClient.linkToDeath(new TestDeathRecipient(), 0); } } }
//AndroidManifest.xml
package="com.example.testservice" android:versionCode="1" android:versionName="1.0"> android:minSdkVersion="8" android:targetSdkVersion="17"/> android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme"> android:name="com.example.testservice.TestActivity" android:label="@string/app_name"> android:process=":service">
//activity_test_service.xml
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".TestActivity"> android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:text="@string/hello_world"/> android:id="@+id/start" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_toLeftOf="@+id/stop" android:text="start"/> android:id="@+id/bind" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/start" android:layout_below="@+id/start" android:layout_marginTop="23dp" android:text="Bind"/> android:id="@+id/stop" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_alignRight="@+id/textView1" android:text="stop"/> android:id="@+id/unbind" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBottom="@+id/button1" android:layout_toRightOf="@+id/button1" android:text="Unbind"/>
あるプロセスは別のプロセスが生存しているかどうかを知る必要がある.あるいは、あるプロセスがkillされたとき、別のプロセスはこのことを知ることを望んでいます.
一般的には、あるboundサービスがクライアントがkillされているかどうかに関心を持っています.
なぜサービスがクライアントにkillされたのかと聞かれるかもしれません.
適用シーン:
たとえば、boundサービスはbindから来たclientにリソースを割り当てる可能性があります.clientがreleaseまたはunbindを呼び出すとリソースが解放されますが、
ある時clientは確かにkillされ、サービスが知らない場合、割り当てられたリソースは解放されません.
AndroidはDeathRecipientというインタフェースを提供しています.
1.clientで1つのBinderをnewし、次に別のプロセスに送信します.通常はBoundサービスです.
2.別のプロセスの死亡情報に関心を持つプロセス(通常はサービス)でDeathRecipientを実現するだけです
3.クライアントから送信されたbinderを呼び出すlinkToDeathメソッド
public abstract void linkToDeath (IBinder.DeathRecipient recipient, int flags)
Added in API level 1
Register the recipient for a notification if this binder goes away. If this binder object unexpectedly goes away (typically because its hosting process has been killed), then the given
IBinder.DeathRecipient
's DeathRecipient.binderDied()
method will be called. You will only receive death notifications for remote binders, as local binders by definition can't die without you dying as well.
Throws
RemoteException
if the target IBinder's process has already died.
See Also
unlinkToDeath(IBinder.DeathRecipient, int)
DeathRecipient is an interface for receiving a callback when the process hosting an IBinder has gone away.
DeathRecipientについては、公式サイトのドキュメントを参照してください.
http://developer.android.com/reference/android/os/IBinder.DeathRecipient.html
-------------------------------------------
テスト手順、appを起動し、startをクリックし、adb shell psでcomを表示します.example.testserviceプロセスID、adb shell kill pidでclient killを落とし、logをチェック
Log.d(TAG, "client has died");printが出てくるかどうか
Sample code:
//Client TestActivity.java
public class TestActivity extends Activity { private String TAG = "TestService"; private Button mStartBtn; private Button mStopBtn; private Button mBindBtn; private Button mUnbindBtn; ClickListener mClickListener = new ClickListener(); private Intent mIntent = new Intent("com.example.action.TEST"); private IBinder mBinder = new Binder(); private ITest mTest = null; private ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { //TODO Auto-generated method stub Log.d(TAG, "onServiceDisconnected"); } @Override public void onServiceConnected(ComponentName name, IBinder service) { //TODO Auto-generated method stub Log.d(TAG, "onServiceConnected:"+ name); mTest = ITest.Stub.asInterface(service); try { mTest.setBinder(mBinder); } catch (RemoteException e) { //TODO Auto-generated catch block e.printStackTrace(); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test_service); mStartBtn = (Button)findViewById(R.id.start); mStopBtn = (Button)findViewById(R.id.stop); mBindBtn = (Button)findViewById(R.id.bind); mUnbindBtn = (Button)findViewById(R.id.unbind); mStartBtn.setOnClickListener(mClickListener); mStopBtn.setOnClickListener(mClickListener); mBindBtn.setOnClickListener(mClickListener); mUnbindBtn.setOnClickListener(mClickListener); } @Override public boolean onCreateOptionsMenu(Menu menu) { //Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.activity_test_service, menu); return true; } private class ClickListener implements OnClickListener{ @Override public void onClick(View v) { int id = v.getId(); if(id == R.id.start){ startService(mIntent); }else if(id == R.id.stop){ stopService(mIntent); }else if(id == R.id.bind){ bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE); }else if(id == R.id.unbind){ unbindService(mServiceConnection); } } } }
//ITest .aidl package com.example.testservice;/** Example service interface */interface ITest {
int getPid(); void setBinder(IBinder client); }
//TestService.java
public class TestService extends Service{ private String TAG = "TestService"; private TestApi mTestApi = new TestApi(); private IBinder mClient = null; @Override public IBinder onBind(Intent intent) { Log.d(TAG, "Onbind() action="+ intent.getAction()); return mTestApi; } private class TestDeathRecipient implements DeathRecipient{ @Override public void binderDied() { Log.d(TAG, "client has died"); } } private class TestApi extends ITest.Stub{ @Override public int getPid() throws RemoteException { return (int)Thread.currentThread().getId(); } @Override public void setBinder(IBinder client) throws RemoteException { mClient = client; mClient.linkToDeath(new TestDeathRecipient(), 0); } } }
//AndroidManifest.xml
package="com.example.testservice" android:versionCode="1" android:versionName="1.0"> android:minSdkVersion="8" android:targetSdkVersion="17"/> android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme"> android:name="com.example.testservice.TestActivity" android:label="@string/app_name"> android:process=":service">
//activity_test_service.xml
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".TestActivity"> android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:text="@string/hello_world"/> android:id="@+id/start" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_toLeftOf="@+id/stop" android:text="start"/> android:id="@+id/bind" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/start" android:layout_below="@+id/start" android:layout_marginTop="23dp" android:text="Bind"/> android:id="@+id/stop" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_alignRight="@+id/textView1" android:text="stop"/> android:id="@+id/unbind" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBottom="@+id/button1" android:layout_toRightOf="@+id/button1" android:text="Unbind"/>