利用Andriod死亡通知机制告诉service,client被kill了


Android提供了一种叫做死亡通知的机制,用于满足某些应用的特定需求:

    某个process需要知道另外一个process是否存活;或者当某个进程被kill的时候,另外一个进程期望知道这件事情;


   一般来讲是某个bound service关心其client是否被kill

  可能有人会问,为什么service会关系client是否被kill呢


应用场景:

 比如:一个bound service可能会为bind过来的client分配一些资源,当client调用release或者unbind的时候则会释放资源,但是

           在某个时候client确被kill了,此时如果service不知道,则为其分配的资源则不会被释放。


Android提供了一个名为DeathRecipient 的接口,

1.在client中new 一个Binder,然后传给另外一个进程,通常是一个Bound service

2.你只需在关心另外一个进程死亡信息的进程中(通常是一个service)实现DeathRecipient

3.调用client传过来的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" />



你可能感兴趣的:(Android开发)