package com.chiclaim.ipc.service; import android.app.Service; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Messenger; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.util.Log; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.chiclaim.ipc.IConnectionService; import com.chiclaim.ipc.IMessageReceiverListener; import com.chiclaim.ipc.IMessageService; import com.chiclaim.ipc.IServiceManager; import com.chiclaim.ipc.bean.Message; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class RemoteService extends Service { private boolean isConnected = false; //private List<IMessageReceiverListener> listeners = new ArrayList<>(); // 如果使用ArrayList ,在unRegister后,其实并没有真正的移除成功,因为传递进来的对象,RemoteService 收到的对象不还一样 // RemoteCallbackList 是通过 IBinder 作为 key 来定位之前的监听对象,虽然监听对象发生变化,但是 IBinder 是唯一的 private RemoteCallbackList<IMessageReceiverListener> listeners = new RemoteCallbackList<>(); private Handler handler = new Handler(Looper.getMainLooper()); private ScheduledThreadPoolExecutor scheduledExecutorService; private IConnectionService connectionService = new IConnectionService.Stub() { /* 会在 Binder 所在进程中的子线程中执行(28320 表示进程的id): D/RemoteService: connect in Binder:28320_3 D/RemoteService: disconnect in Binder:28320_3 D/RemoteService: isConnected in Binder:28320_3 */ private ScheduledFuture scheduledFuture; @Override public void connect() throws RemoteException { if (scheduledExecutorService == null) { scheduledExecutorService = new ScheduledThreadPoolExecutor(1); } try { Thread.sleep(4000); isConnected = true; Log.d("RemoteService", "connect in " + Thread.currentThread().getName()); handler.post(new Runnable() { @Override public void run() { Toast.makeText(RemoteService.this, "connect", Toast.LENGTH_SHORT).show(); } }); scheduledFuture = scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { try { int size = listeners.beginBroadcast(); for (int i = 0; i < size; i++) { IMessageReceiverListener listener = listeners.getBroadcastItem(i); Message message = new Message(); message.setContent("message send from remote service"); listener.onReceiveMessage(message); } listeners.finishBroadcast(); } catch (RemoteException e) { e.printStackTrace(); } } }, 5000, 5000, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public void disconnect() throws RemoteException { isConnected = false; Log.d("RemoteService", "disconnect in " + Thread.currentThread().getName()); handler.post(new Runnable() { @Override public void run() { Toast.makeText(RemoteService.this, "disconnect", Toast.LENGTH_SHORT).show(); } }); if (scheduledFuture != null) { scheduledFuture.cancel(true); } } @Override public boolean isConnected() throws RemoteException { Log.d("RemoteService", "isConnected in " + Thread.currentThread().getName()); return isConnected; } }; private IMessageService messageService = new IMessageService.Stub() { @Override public void sendMessage(final Message message) throws RemoteException { Log.d("RemoteService", "sendMessage in " + Thread.currentThread().getName()); handler.post(new Runnable() { @Override public void run() { Toast.makeText(RemoteService.this, String.valueOf(message.getContent()), Toast.LENGTH_SHORT).show(); } }); message.setSendSuccess(isConnected); } @Override public void registerReceiveListener(IMessageReceiverListener listener) throws RemoteException { Log.d("RemoteService", "RemoteService registerReceiveListener : " + listener.toString()); Log.d("RemoteService", "registerReceiveListener in " + Thread.currentThread().getName()); listeners.register(listener); } @Override public void unRegisterReceiveListener(IMessageReceiverListener listener) throws RemoteException { Log.d("RemoteService", "unRegisterReceiveListener in " + Thread.currentThread().getName()); Log.d("RemoteService", "RemoteService unRegisterListener : " + listener.toString()); listeners.unregister(listener); } }; private Handler messengerHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(@NonNull android.os.Message msg) { super.handleMessage(msg); Bundle bundle = msg.getData(); // Class not found when unmarshalling: com.chiclaim.ipc.bean.Message bundle.setClassLoader(Message.class.getClassLoader()); Message data = bundle.getParcelable("message"); Toast.makeText(getApplicationContext(), data.getContent(), Toast.LENGTH_SHORT).show(); Messenger replyTo = msg.replyTo; Message raw = new Message(); raw.setContent("I receive your message: " + data.getContent()); android.os.Message message = new android.os.Message(); Bundle replyBundle = new Bundle(); replyBundle.putParcelable("message", raw); message.setData(replyBundle); try { replyTo.send(message); } catch (RemoteException e) { e.printStackTrace(); } } }; private Messenger messenger = new Messenger(messengerHandler); private IServiceManager serviceManager = new IServiceManager.Stub() { @Override public IBinder getService(String name) throws RemoteException { if (IConnectionService.class.getSimpleName().equals(name)) { return connectionService.asBinder(); } else if (IMessageService.class.getSimpleName().equals(name)) { return messageService.asBinder(); } else if (Messenger.class.getSimpleName().equals(name)) { return messenger.getBinder(); } return null; } }; @Nullable @Override public IBinder onBind(Intent intent) { //connectionService.asBinder(); return serviceManager.asBinder(); } }