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

来源:互联网 发布:学校封游戏端口怎么办 编辑:程序博客网 时间:2024/05/17 07:00
原文  http://blog.csdn.net/yuzhiboyi/article/details/7558176

应用组件 ( 客户端 )可以调用 bindService() 绑定到一个 serviceAndroid 系统之后调用 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_UNBINDBIND_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>

0 0