簡單跨程式使用EventBus

夕陽下的奔跑發表於2020-03-05

一、結構

簡單跨程式使用EventBus

說明:

  1. 主程式有一個Service,負責維護監聽器列表,以及監聽相關事件,併傳送給子程式
  2. 子程式需要繫結主程式的Service,並註冊監聽
  3. 主程式和子程式內的事件通過EventBus傳送,需要跨程式的通過Binder轉發

二、AIDL介面

工程結構:

簡單跨程式使用EventBus

定義AIDL介面:
IEventInterface.aidl:
// IEventInterface.aidl
package com.example.autolog.aidl;
import com.example.autolog.aidl.IRemoteCallback;
// Declare any non-default types here with import statements
import com.example.autolog.aidl.Msg;
interface IEventInterface {
    //子程式向主程式註冊事件回撥
    void registerCallback(IRemoteCallback callback);
	//子程式解註冊
    void unregisterCallback(IRemoteCallback callback);
	//子程式向主程式通知事件
    void notify(in Msg msg);
}
複製程式碼
IRemoteCallback.aidl:
// IRemoteCallback.aidl
package com.example.autolog.aidl;

// Declare any non-default types here with import statements
import com.example.autolog.aidl.Msg;

interface IRemoteCallback {
    //子程式實現的事件回撥
    void notifyEvent(in Msg msg);
}
複製程式碼
Msg.aidl:
// Msg.aidl
package com.example.autolog.aidl;
//訊息型別
parcelable Msg;
複製程式碼

三、本地客戶端

Msg.java:
package com.example.autolog.aidl;

import android.os.Parcel;
import android.os.Parcelable;
//訊息實體類,需要實現Parcelable介面,跨程式時需要進行序列化
public class Msg implements Parcelable {
    public int code;
    public String message;

    public Msg(int code, String msg) {
        this.code = code;
        this.message = msg;
    }

    public Msg(Parcel in) {
        this.code = in.readInt();
        this.message = in.readString();
    }

    public final static Creator<Msg> CREATOR = new Creator<Msg>() {
        @Override
        public Msg createFromParcel(Parcel in) {
            return new Msg(in);
        }

        @Override
        public Msg[] newArray(int size) {
            return new Msg[size];
        }
    };

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(code);
        dest.writeString(message);
    }

    @Override
    public int describeContents() {
        return 0;
    }
}
複製程式碼
LocalService.java:主程式的Service,其他程式需要繫結該Service
package com.example.autolog.aidl;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;

import androidx.annotation.Nullable;

import java.util.ArrayList;
import java.util.List;

import de.greenrobot.event.EventBus;
import de.greenrobot.event.Subscribe;

public class LocalService extends Service {
    //監聽列表,使用RemoteCallbackList可以進行監聽物件的移除
    final RemoteCallbackList<IRemoteCallback> lis = new RemoteCallbackList<>();
    Binder mBinder = new IEventInterface.Stub() {
        @Override
        public void registerCallback(IRemoteCallback callback) throws RemoteException {
            Log.v("aidl-service", "localservice registercallback:" + callback + callback.asBinder());
            lis.register(callback);
        }

        @Override
        public void unregisterCallback(IRemoteCallback callback) throws RemoteException {
            Log.v("aidl-service", "localservice unregistercallback " + callback + callback.asBinder());
            lis.unregister(callback);
        }

        @Override
        public void notify(Msg msg) throws RemoteException {
            Log.v("aidl-service", "localservice notify code:" + msg.code + " message:" + msg.message);
            //子程式傳送事件後,用EventBus分發
            EventBus.getDefault().post(msg);
        }
    };

	//監聽EventBus傳送的字串事件,並呼叫子程式的監聽器
    @Subscribe
    public void handle(String message) {
        Log.v("aidl-service", "localservice handle:" + message);
        synchronized (lis) {
            int n = lis.beginBroadcast();
            try {
                for (int i = 0; i < n; i++) {
                    lis.getBroadcastItem(i).notifyEvent(new Msg(0, message));
                }
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            lis.finishBroadcast();
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        EventBus.getDefault().register(this);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
}
複製程式碼
MainActivity.java:主頁面,此處用來啟動LocalService和RemoteService
package com.example.autolog;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.example.autolog.aidl.Msg;
import com.example.autolog.aidl.RemoteService;
import com.example.autolog.aidl.LocalService;

import de.greenrobot.event.EventBus;
import de.greenrobot.event.Subscribe;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        startService(new Intent(this, LocalService.class));

        startService(new Intent(this, RemoteService.class));

        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(3000);
                        //傳送事件,由LocalService處理,並通知給子程式
                        EventBus.getDefault().post("wahaha, i'am mainactivity:" + System.currentTimeMillis());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
        EventBus.getDefault().register(this);
    }

    @Subscribe
    public void process(Msg msg){
        //子程式事件傳送到LocalService後,處理EventBus傳送的事件
        Log.v("aidl-service", "main activity preocess code:"+msg.code+" msg:"+msg.message);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }
}
複製程式碼

四、子程式

RemoteService:子程式,用來繫結主程式,並註冊監聽

package com.example.autolog.aidl;

import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

import androidx.annotation.Nullable;

import com.example.autolog.LocalService;
import com.example.autolog.aidl.IEventInterface;
import com.example.autolog.aidl.IRemoteCallback;
import com.example.autolog.aidl.Msg;

import de.greenrobot.event.EventBus;

public class RemoteService extends Service {
    IEventInterface iEventInterface;

    @Override
    public void onCreate() {
        super.onCreate();
        Log.v("aidl-service", "remoteservice oncreate " + getPackageName());
        Intent it = new Intent(this, LocalService.class);
        //繫結主程式的服務
        boolean r = bindService(it, new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Log.v("aidl-service", "remoteservice onserviceconnected");
                iEventInterface = IEventInterface.Stub.asInterface(service);
                try {
                    //註冊監聽
                    iEventInterface.registerCallback(new IRemoteCallback.Stub() {
                        @Override
                        public void notifyEvent(Msg msg) throws RemoteException {
                            Log.v("aidl-service", "remoteservice notifyevent code:" + msg.code + " message:" + msg.message);
                            EventBus.getDefault().post(msg);
                        }
                    });
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            while (true) {
                                try {
                                    Thread.sleep(2000);
                                    //向主程式傳送事件
                                    iEventInterface.notify(new Msg(1, "hello i'am remoteservice:" + System.currentTimeMillis()));
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }).start();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {

            }
        }, BIND_AUTO_CREATE);
        Log.e("aidl-service", "remoteservice bind localservice " + r);
    }


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}
複製程式碼

在AndroidManifest.xml中配置service

<service android:name=".LocalService" >
   <intent-filter>
         <action android:name="localservice"/>
   </intent-filter>
</service>

<service
    android:name=".aidl.RemoteService"
    android:process=":remote" />
複製程式碼

通過以上的程式碼,可以實現使用EventBus在主程式和子程式之間通訊。

五、多module

將主程式的service和子程式的service放到不同的module中:

base:基礎module,包含了aidl檔案和Msg實體類,以及LocalService

簡單跨程式使用EventBus

child:子程式,包含RemoteService,並在AndroidManifest.xml配置service的程式,需要在build.gradle中配置對base的依賴

簡單跨程式使用EventBus

app:主module,包含MainActivity,需要在build.gradle中配置對base和child的依賴

簡單跨程式使用EventBus

六、多APP通訊

將AIDL檔案和實體類拷貝到main目錄下,保證包名和路徑正確,即可實現app之間的通訊。

簡單跨程式使用EventBus

在第二個APP中,使用顯式的intent來繫結第一個APP中的LocalService,使用LocalService設定的action。

簡單跨程式使用EventBus