Android里Service的bindService()和startService()混合使用深入分析

原文  http://blog.csdn.net/yuzhiboyi/article/details/7558176

应用组件 ( 客户端 ) 可以调用 bindService() 绑定到一个 service Android 系统之后调用 service onBind() 方法,它返回一个用来与 service 交互的 IBinder .\

绑定是异步的. bindService() 会立即返回,它不会返回 IBinder 给客户端.要接收 IBinder ,客户端必须创建一个 ServiceConnection 的实例并传给 bindService() ServiceConnection 包含一个回调方法,系统调用这个方法来传递要返回的 IBinder


注:只有 activities,services, contentproviders 可以绑定到一个 service— 你不能从一个 broadcastreceiver 绑定到 service


所以,从你的客户端绑定到一个 service ,你必须:

  • 1实现 ServiceConnection.

    你的实现必须重写两个回调方法:

    • onServiceConnected()

      系统调用这个来传送在 service onBind() 中返回的 IBinder

    • OnServiceDisconnected()

      Android 系统在同 service 的连接意外丢失时调用这个.比如当 service 崩溃了或被强杀了.当客户端解除绑定时,这个方法不会被调用.

  • 2调用 bindService() ,传给它 ServiceConnection 的实现.

  • 3当系统调用你的 onServiceConnected() 方法时,你就可以使用接口定义的方法们开始调用 service 了.

  • 4要与 service 断开连接,调用 unbindService()

    当你的客户端被销毁,它将从 service 解除绑定,但是你必须总是在你完成与 service 的交互时或当你的 activity 暂停于是 service 在不被使用时可以关闭此两种情况下解除绑定. ( 下面会讨论更多在适当的时候绑定和解除绑定的问题. )

  1. LocalService mService;  
  2. private  ServiceConnection mConnection =  new  ServiceConnection() {  
  3.      // 当与service的连接建立后被调用   
  4.      public   void  onServiceConnected(ComponentName className, IBinder service) {  
  5.          // Because we have bound to an explicit   
  6.          // service that is running in our own process, we can   
  7.          // cast its IBinder to a concrete class and directly access it.   
  8.         LocalBinder binder = (LocalBinder) service;  
  9.         mService = binder.getService();  
  10.         mBound =  true ;  
  11.     }  
  12.   
  13.      // 当与service的连接意外断开时被调用   
  14.      public   void  onServiceDisconnected(ComponentName className) {  
  15.         Log.e(TAG,  "onServiceDisconnected" );  
  16.         mBound =  false ;  
  17.     }  
  18. };  

使用这个 ServiceConnection ,客户端可以绑定到一个 service ,通过把它传给 bindService() .例如:

Intentintent = new Intent(this, LocalService.class);

bindService(intent,mConnection, Context.BIND_AUTO_CREATE);

  • 第一个 bindService() 的参数是一个明确指定了要绑定的 service Intent

  • 第二个参数是 ServiceConnection 对象.

  • 第三个参数是一个标志,它表明绑定中的操作.它一般应是 BIND_AUTO_CREATE ,这样就会在 service 不存在时创建一个.其它可选的值是 BIND_DEBUG_UNBIND BIND_NOT_FOREGROUND, 不想指定时设为 0 即可.


补充事项

下面是一些关于绑定到 service 的重要事项:

  • 你总是需要捕获 DeadObjectException 异常.它会在连接被打断时抛出.这是被远程方法抛出的唯一异常.

  • 对象引用计数是跨进程的作用的.

  • 你应该在客户端的生命期内使绑定和解除绑定配对进行,例如:

    • 如果你需要在你的 activity 可见时与 service 交互,你应该在 onStart() 绑定并在 onStop() 中解除绑定.

    • 如果你想让你的 activity 即使在它停止时也能接收回应,那么你可以在 onCreate() 中绑定并在 onDestroy() 中解除绑定.注意这意味着你的 activity 需要使用在自己整个运行期间使用 service( 即使位于后台 ) ,所以如果 service 在另一个进程中,那么你增加了这个进程的负担而使它变得更容易被系统杀掉.


注:你一般不应该在你的 activity onResume() onPause() 中绑定和解除绑定到 service ,因为这些回调方法 , 出现在每个生命期变化中,并且你需要使发生在这些变化中的处理最小化.还有,如果你应用中的多个 activity 绑定到同一个 service ,并且有一个变化发生在其中两个 activity 之间, service 可能在当前 activity 解除绑定 (pause ) 和下一个绑定前 (rusume ) 被销毁又重建.


管理 BoundService 的生命期

当一个 service 的所有客户端都解除绑定, Android 系统就销毁它 ( 除非它是从 onStartCommand() 启动 ) .如果你的 service 是一个纯 boundservice ,你不需管理它的生命期Android 系统会为你管理它.


然而,如果你选择了实现 onStartCommand() 回调方法,那么你必须明确地停止 service ,因为 service 现在被认为是"开始的".在此情况下, service 会一直运行,直到 service 使用 stopSelf() 停止它自己或另外的组件调用了 stopService() 停止了它,不管是否有客户端绑定了它.


另外,如果你的 service 已经启动并且接受绑定,那么当系统调用你的 onUnbind() 方法,你可以选择返回 true 表示 你想在客户端下一次绑定到 service 时接受一个对 onRebind() 的调用 ( 而不是一个对 onBind() 的调用 ) onRebind() 返回 void ,但是客户端依然会在它的 onServiceConnected() 回调中接收到 IBinder .下图演示了这种生命其的逻辑:


1.如果先bindService,再startService:

在bind的Activity退出的时候,Service会执行unBind方法而不执行onDestory方法,因为有startService方法调用过,所以Activity与Service解除绑定后会有一个与 调用者没有关连的Service存在

 

2.如果先bindService,再startService,再调用Context.stopService

Service的onDestory方法不会立刻执行,因为有一个与Service绑定的Activity,但是在Activity退出的时候,会执行onDestory,如果要立刻执行stopService,就得先解除绑定

 

---------------------------

把上面的"如果先bindService,再startService"换成"如果先startService,再bindService",结果是一样的

问题:

如果在一个Activity的onCreate方法中,

bindService(serviceIntent, conn, Context.BIND_AUTO_CREATE);

再startService(serviceIntent);

退出这个Activity时,会执行onUnBind

但是再次进入这个Activity的时候,为什么不执行onBind方法了?只有在这个Service销毁后(执行onDestory),再进这个Activity才会执行onBind


package yy.android.service;


import org.apache.http.conn.ClientConnectionManager;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences.Editor;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class ServiceActivity extends Activity {
//    private final String TAG = "ServiceActivity";
    private Button unbind;
    public static IService iService=null;
    private Button mSkiptoClient;
    private Button mStart;
    public static EditText medit;
    private Button mBind;
    private Button mStop;
    public static ServiceConnection connection=new ServiceConnection() {
        public void onServiceDisconnected(ComponentName name) {
            Log.d("LOG","Activity ->Disconnected the LocalService");
        }
        public void onServiceConnected(ComponentName name, IBinder service) {
            // TODO Auto-generated method stub
            //获取连接的服务对象
              //System.out.println("Connection!!!");
              iService=(IService)service;
              medit.setText(iService.getName());
              Log.d("LOG","Activity ->Connected the Service");
        }
    };  
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Log.d("LOG","Activity ->OnCreate");
        unbind = (Button)findViewById(R.id.unbind);
        mSkiptoClient = (Button)findViewById(R.id.skip);
        mStart = (Button)findViewById(R.id.start);
        mStop = (Button )findViewById(R.id.stop);
        medit = (EditText)findViewById(R.id.edit);
        mBind = (Button)findViewById(R.id.connection);
        mBind.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                // TODO Auto-generated method stub
                 Intent intent=new Intent(ServiceActivity.this,LocalService.class);
                 bindService(intent,connection, BIND_AUTO_CREATE);    
            }
        });
        mStart.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                // TODO Auto-generated method stub
                Intent intent=new Intent(ServiceActivity.this,LocalService.class);    
                startService(intent);
            }
        });
        mStop.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                // TODO Auto-generated method stub
                Intent intent=new Intent(ServiceActivity.this,LocalService.class);
                stopService(intent);
            }
        });
        mSkiptoClient.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                Intent intent = new Intent("android.intent.action.YClient");
                startActivity(intent);
            }
        });
        unbind.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                // TODO Auto-generated method stub
                unbindService(connection);
            }
        });
    }
    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        Log.d("LOG","Activity ->OnDestory");
    }
    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
//        unbindService(connection);
        Log.d("LOG","Activity ->OnPause");
        super.onPause();
        
    }
    @Override
    protected void onRestart() {
        // TODO Auto-generated method stub
        super.onRestart();
        Log.d("LOG","Activity ->OnRestart");
    }
    @Override
    protected void onResume() {
        // TODO Auto-generated method stub
        Log.d("LOG","Activity ->OnResume");
//         Intent intent=new Intent(ServiceActivity.this,LocalService.class);
//         bindService(intent,connection, BIND_AUTO_CREATE);    
        super.onResume();
        
    }
    protected void onStart() {
        // TODO Auto-generated method stub
        super.onStart();
        Log.d("LOG","Activity ->OnSatrt");
    }
    @Override
    protected void onStop() {
        // TODO Auto-generated method stub
        super.onStop();
        Log.d("LOG","Activity ->OnStop");
    }
    

}

////////////////////////////////////////////////////////////////////////////

package yy.android.service;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

public class CLient extends Activity{
    private IService iService2=null;
    private Button unbind2;
    private Button mStart2;
    private EditText medit2;
    private Button mBind2;
    private Button mStop2;
    ServiceConnection connection2=new ServiceConnection() {
         public void onServiceDisconnected(ComponentName name) {
            Log.d("LOG","Client ->Disconnected the LocalService");
        }
        public void onServiceConnected(ComponentName name, IBinder service) {
            // TODO Auto-generated method stub
             //获取连接的服务对象
              //System.out.println("Connection!!!");
              iService2=(IService)service;
               medit2.setText(iService2.getName());
               Log.d("LOG","Client ->Connected the Service");
        }
     };  
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.client);
        Log.d("LOG","Client ->OnCreate");
        unbind2 = (Button)findViewById(R.id.unbind2);
        mStart2 = (Button)findViewById(R.id.start2);
        mStop2 = (Button )findViewById(R.id.stop2);
        medit2 = (EditText)findViewById(R.id.edit2);
        mBind2 = (Button)findViewById(R.id.connection2);
        mBind2.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                // TODO Auto-generated method stub
                 Intent intent=new Intent(CLient.this,LocalService.class);
                 bindService(intent,connection2, BIND_AUTO_CREATE);    
            }    
        });    
        mStart2.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {  
                // TODO Auto-generated method stub
                Intent intent=new Intent(CLient.this,LocalService.class);    
                startService(intent);
            }
        });
        mStop2.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                // TODO Auto-generated method stub
                Intent intent=new Intent(CLient.this,LocalService.class);
                stopService(intent);
            }
        });
        unbind2.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                // TODO Auto-generated method stub
                Log.e("LOG", "Unbind");
                unbindService(connection2);
                Log.e("LOG", "Unbind");
            }  
        });
    }     
    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        //unbindService(connection2);
        Log.d("LOG","Client ->OnDestory");
        super.onDestroy();
        
    }
    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
        Log.d("LOG","Client ->OnPause");
    }
    @Override
    protected void onRestart() {
        // TODO Auto-generated method stub
        super.onRestart();
        Log.d("LOG","Client ->OnRestart");
    }
    @Override
    protected void onResume() {
        // TODO Auto-generated method stub
        super.onResume();
        Log.d("LOG","Client ->OnResume");
    }
    @Override
    protected void onStart() {
        // TODO Auto-generated method stub
        super.onStart();
        Log.d("LOG","Client ->OnSatrt");
    }
    @Override
    protected void onStop() {
        // TODO Auto-generated method stub
        super.onStop();
        Log.d("LOG","Client ->OnStop");
    }
    
}
///////////////////////////////////////////////////////////////////

package yy.android.service;
 
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

public class LocalService extends Service{
    private MyBind myBind=new MyBind();
    
    public IBinder onBind(Intent intent) {
            //System.out.println("Service onBind!!!");
            Log.d("LOG","LocalService ->onBind");
            return myBind;
        }
    @Override
    public void onCreate() {
        // TODO Auto-generated method stub
        Log.d("LOG","LocalService ->onCreate");
        super.onCreate();
        
    }
     @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
         Log.d("LOG","LocalService ->onDestory");
        super.onDestroy();
        
    }
    @Override
    public void onStart(Intent intent, int startId) {
        // TODO Auto-generated method stub
        Log.d("LOG","LocalService ->onSatrt");
        super.onStart(intent, startId);
        
    }
    @Override  
    public boolean onUnbind(Intent intent) {
        // TODO Auto-generated method stub
        Log.d("LOG","LocalService ->onUnbind");
        return super.onUnbind(intent);
        //return true;
    }
    
    @Override
    public void onRebind(Intent intent) {
        // TODO Auto-generated method stub
        Log.d("LOG","LocalService ->onRebind");
        super.onRebind(intent);
        
    }
    
    

    public class MyBind extends Binder implements IService{

         public String getName() {
             // TODO Auto-generated method stub
             return "YUZHIBOYI";
         }
     }
}
/////////////////////////////////////////////////////////////////////////

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="yy.android.service"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="10" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".ServiceActivity"
            
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".CLient"
            
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.YClient" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
        <service android:name=".LocalService">
           <intent-filter>  
               <action android:name="com.yy.yy"/>
               <category android:name="android.intent.category.DEFAULT" />
           </intent-filter>  
        </service>   
    </application>
</manifest>

/////////////////////////////////////////////////////////

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <EditText
        android:id="@+id/edit2"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
    ></EditText>     
    <Button  
        android:id = "@+id/connection2"  
        android:layout_width = "wrap_content"  
        android:layout_height = "wrap_content"  
        android:text = "@string/Bind"  
        />  
        <Button  
        android:id = "@+id/start2"  
        android:layout_width = "wrap_content"  
        android:layout_height = "wrap_content"  
        android:text = "@string/Start"  
        />  
        <Button  
        android:id = "@+id/stop2"  
        android:layout_width = "wrap_content"  
        android:layout_height = "wrap_content"  
        android:text = "@string/StopService"  
        />  
          <Button  
        android:id = "@+id/unbind2"  
        android:layout_width = "wrap_content"  
        android:layout_height = "wrap_content"  
        android:text = "@string/UnbindService"  
        />
</LinearLayout>

//////////////////////////////////////////////////////

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
   <EditText
        android:id="@+id/edit"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
    ></EditText>     
    <Button  
        android:id = "@+id/connection"  
        android:layout_width = "wrap_content"  
        android:layout_height = "wrap_content"  
        android:text = "@string/Bind"  
        />  
        <Button  
        android:id = "@+id/start"  
        android:layout_width = "wrap_content"  
        android:layout_height = "wrap_content"  
        android:text = "@string/Start"  
        />  
        <Button  
        android:id = "@+id/stop"  
        android:layout_width = "wrap_content"  
        android:layout_height = "wrap_content"  
        android:text = "@string/StopService"  
        />  
        <Button  
        android:id = "@+id/skip"  
        android:layout_width = "wrap_content"  
        android:layout_height = "wrap_content"  
        android:text = "@string/Skip"  
        />  
        <Button  
        android:id = "@+id/unbind"  
        android:layout_width = "wrap_content"  
        android:layout_height = "wrap_content"  
        android:text = "@string/UnbindService"  
        /> 
</LinearLayout>

你可能感兴趣的:(Android里Service的bindService()和startService()混合使用深入分析)