Android 实现同进程下Activity与Service的通信

一、基本用法(使用bind的方式注册Service)

(1)新建一个继承自Service的类MyService,然后在AndroidManifest.xml里注册这个Service.

(2)Activity里面使用bindService方式启动MyService,也就是绑定了MyService.

(3)新建一个继承自Binder的类MyBinder

(4)在MyService里实例化一个MyBinder对象mBinder,并在onBind回调方法里边返回mBinder对象

(5)第2步bindService方法需要一个ServiceConnection类型的参数,在ServiceConnection里可以取到一个IBinder对象,就是第4步onBinder返回的mBinder对象(也就是在Activity里面拿到了Service里面的mBinder对象)

(6)在Activity里面拿到mBinder之后就可以调用这个binder里面的方法了(也就是可以给Service发消息了),需要什么方法在MyBinder类里面定义实现就行了。如果需要Service给Activity发消息的话,通过这个binder注册一个自定义回调即可。

二、代码实现

  Service

public class MyService extends Service {
    private static final String TAG="wcy";
    //实例化一个MyBinder对象
    private MyBinder myBinder=new MyBinder(this);

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return myBinder;
    }
    public void serviceMothod(String str){
        Log.i(TAG,"receive msg from activity:"+str);
    }
}

Service也是四大组件之一,所以创建一个Service类也需要在功能清单文件中注册。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.wcystart.wcystart">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".FirstActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
       
        <service
            android:name=".MyService"
            android:enabled="true"
            android:exported="true">
        </service>
    </application>

</manifest>

android:enabled="true"  代表是否能被其他应用隐式调用,其默认值是由service中有无intent-filter决定的,如果有intent-filter,默认值为true,否则为false。为false的情况下,即使有intent-filter匹配,也无法打开,即无法被其他应用隐式调用。能被跨进程使用。

android:exported="true"  代表是否能被其他的应用隐式调用

Binder

public class MyBinder extends Binder {
    private static final String TAG = "wcy";
    private MyService mService;
    onTestListener mOnTestListener;
    public  MyBinder(MyService service){
        this.mService=service;
    }
    public void testMothod(String str){
        //Activity 通过Binder来调用Service的方法将消息传给Activity
        mService.serviceMothod(str);
        mOnTestListener.onTest("hi,activity");
    }
    //MyBinder里边提供一个注册回调的方法
    public void setOnTestListener(onTestListener onTestListener) {
        this.mOnTestListener = onTestListener;
    }

    //自定义一个回调接口
    public interface onTestListener {
        void onTest(String str);
    }
}

Activity

public class FirstActivity extends Activity implements View.OnClickListener {
    private static String TAG = "FirstActivity";
    private Button mBtnMain;
    private MyBinder myBinder;
    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            myBinder = (MyBinder) service;
            myBinder.setOnTestListener(new MyBinder.onTestListener() {
                @Override
                public void onTest(String str) {
                    Log.i(TAG, "receive msg from service:" + str);
                }
            });
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mBtnMain = findViewById(R.id.btn_main);
        //跳转到Service
        Intent intent=new Intent(this,MyService.class);
        bindService(intent,mConnection,BIND_AUTO_CREATE);
        mBtnMain.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        myBinder.testMothod("hi,service.");
    }
}
bindService(intent,mConnection,BIND_AUTO_CREATE);
第一个bindService()的参数是一个明确指定了要绑定的service的Intent.
第二个参数是ServiceConnection对象.
第三个参数是一个标志,它表明绑定中的操作.它一般应是BIND_AUTO_CREATE,这样就会在service不存在时创建一个.其它可选的值是BIND_DEBUG_UNBIND和BIND_NOT_FOREGROUND,不想指定时设为0即可.。//当bindService最后一个参数为Context.BIND_AUTO_CREATE时会和service建立连接,会在连接建立之后调用onServiceConnected方法,当bindService最后一个参数为Context.BIND_DEBUG_UNBIND时会断开和service的链接,会在断开连接后调用onServiceDisconnected()方法。

三、为了防止内存泄漏,需要在Activity销毁的时候解绑Service

   @Override
    protected void onDestroy() {
        super.onDestroy();
        //当Activity销毁的时候解服务
        if(mConnection!=null){
            unbindService(mConnection);
            mConnection=null;
        }
    }

总结

代码很简单,首先Activity绑定Service得到一个MyBinder实例并注册MyBinder里面的OnTestListener回调监听,然后点击按钮的时候调用MyBinder里面的testMethod(String)方法将消息发出去,MyBinder持有一个MyService的实例,testMethod(String)里面调用MyService里面的方法就可以把Activity的消息传给Service了,然后testMethod(String)里面回调mListener.onTest(String)将Service的消息发给Activity。

MyBinder定义在MyService里面作为内部类也是很常见的写法,这里为了方便后面的讲解写成了普通类的形式。

至此就实现了同进程下Activity与Service的双向通信,运行代码,点击按钮后log如下:

wcy: receive msg from activity:hi,service.
FirstActivity: receive msg from service:hi,activity

通过打印日志可以看到,Activity与Service之间是通过一个Binder对象来通信的。

参考文章:关于Android Service的全面解析

猜你喜欢

转载自blog.csdn.net/qq_37982823/article/details/86232895