Android bind service explanation and cross-process communication

**

Android bind service explanation and Messenger cross-process communication

**
Android service is a program that runs in the background. To put it bluntly, there is no interface. Here I want to emphasize that running in the background does not mean running in a non-main thread. Except for IntentService, if you don’t start a new service, normal service Thread, then the default is to run in the main thread.
There are two ways to start a service, one is bind and the other is start. There are quite a few differences between the two startup methods. It should be noted that when bind binds service, until the last program from bind to service calls unbind, otherwise the service will continue to run. As for the start method of startservice, once it is started, you need to stopService yourself or call the stopSelf inside the service, otherwise the service will not be closed.
Also need to pay attention to the service life cycle, this attached picture will fully understand.
Write picture description here
It should be noted that the onCreate method is only called once when you start the service, and then when you start the service, it will go directly to onStartCommand() or onBind().

Okay, let’s stop talking nonsense, let’s take a demo:

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    
    

    private boolean hasBound;
    private Button intent_Service;
    private Button start_Service;
    private Button bind_Service;
    private Button messenger_Service;
    //下面的handler和Messenger使用来进行跨进程通信的
    private Handler handler=new Handler()
    {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if(msg.what==322)
            {
                Toast.makeText(getApplicationContext(),"receive message from server",Toast.LENGTH_SHORT).show();
            }
        }
    };

    private Messenger clientMessenger=new Messenger(handler);
    private Messenger serverMessenger;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView()
    {
        intent_Service= (Button) findViewById(R.id.intent_service);
        intent_Service.setOnClickListener(this);
        start_Service= (Button) findViewById(R.id.start_service);
        start_Service.setOnClickListener(this);
        bind_Service=(Button)findViewById(R.id.bind_service);
        bind_Service.setOnClickListener(this);
        messenger_Service=(Button)findViewById(R.id.messenger_service);
        messenger_Service.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch(v.getId())
        {
            case R.id.intent_service:
            //启动IntentService
                Intent intentService=new Intent(this,IntentTestService.class);
                startService(intentService);
                break;
            case R.id.start_service:
            //start调用普通Sservice
                Intent startService=new Intent(this,NormalService.class);
                startService(startService);
                break;
            case R.id.bind_service:
            //bind调用service
                Intent bindService=new Intent(this,NormalService.class);
                if(bindService.resolveActivity(getPackageManager())!=null)
                bindService(bindService,connection,BIND_AUTO_CREATE);
                break;
//利用Messenger进行跨进程通信
            case R.id.messenger_service:
                if(!hasBound) {
                    Intent intent = new Intent("com.skateboard.serverservice.service.BIND");
                    intent.setPackage("com.skateboard.serverservice");
                    bindService(intent, messengerConnection, Context.BIND_AUTO_CREATE);
                }
                else
                {
                    sendMessageToServier();
                }
                break;
        }
    }



    private ServiceConnection messengerConnection=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            hasBound=true;
            serverMessenger=new Messenger(service);
            Message message=new Message();
            message.what=233;
            message.replyTo=clientMessenger;
            try {
                serverMessenger.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
          hasBound=false;
        }
    };

    private ServiceConnection connection=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            NormalService.NormalBinder binder= (NormalService.NormalBinder) service;
            binder.bindMethod();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    private void sendMessageToServier()
    {
        Message message=new Message();
        message.what=233;
        message.replyTo=clientMessenger;
        try {
            serverMessenger.send(message);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }
}

IntentTestService inherits the child IntentService, its function is very simple, it is to print a line of "intent service start". What is more special is that, as mentioned above, this service runs on a non-main thread.

public class IntentTestService extends IntentService {
    
    


    public IntentTestService()
    {
       super("IntentTestService");
    }

    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public IntentTestService(String name) {
        super(name);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        System.out.println("intent service start");
    }
}

NormalService can be started by startService() and can also be started by bindService. Here we mainly talk about the start method of bindService. When we bind to a service, we call back the onBind method, which will return an IBinder class. This class personally feels like the proxy mode, through which to call the method in the service, when we bindservice, we need to pass in a parameter, ServiceConnection, there are two callback methods in this object, one is ublic void onServiceConnected(ComponentName name , IBinder service) One is public void onServiceDisconnected(ComponentName name), the parameter service in onServiceConnected is the IBinder we return in the onBind method, and by transforming it, we can call the method in the corresponding service. So here I wrote an internal class NormalBinder, use it to print ""bind method" and return it in the onBind method, so that I can get this NormalBinder in MainActivity and call its internal methods.

public class NormalService extends Service {
    
    
    public NormalService() {
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        System.out.println("service start");
        stopSelf();
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        NormalBinder normalBinder=new NormalBinder();
        return normalBinder;

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        System.out.println("stop service");
    }

    public class NormalBinder extends Binder
    {
    
    
        public void bindMethod()
        {
            System.out.println("bind method");
        }
    }


}

For this process, I wanted to draw a schematic diagram, but I was too lazy, so I decided to keep it in text.
There are two ways of cross-process communication, one is AIDL, and the other is to use Messenger. The difference between these two methods is that AIDL is multi-threaded, while Messenger is single-threaded, which means that it uses Messenger to cross-thread. Process communication has only one request at a time in the message queue. Note that if you need the server to send data back to the client, you need to get the client’s Messenger in the handler’s public void handleMessage(Message msg) method. This messenger is Messenger clientMessenger=msg.replyTo; this is on the client The parameters passed to the message when sending a message to the server.

public class ServerService extends Service {
    
    

    private Handler handler=new Handler()
    {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if(msg.what==233)
            {
                Messenger clientMessenger=msg.replyTo;
                Message message=new Message();
                message.what=322;
                try {
                    clientMessenger.send(message);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }
    };

    private Messenger messenger=new Messenger(handler);

    public ServerService()
    {

    }

    @Override
    public void onCreate() {
        super.onCreate();
        System.out.println("service create");
    }

    @Override
    public IBinder onBind(Intent intent) {
        System.out.println("bind service");
       return messenger.getBinder();
    }
}

Then MainAcitivyt initiates a bindService request. (It should be noted here that after 5.0, the Intent that opens the service must be the displayed Intent, so your Intent must contain the information of the package name of another program.) onServiceConnected in ServiceConnection In the method, get the corresponding Messenger through the returned IBinder

 private ServiceConnection messengerConnection=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            hasBound=true;
            serverMessenger=new Messenger(service);
            Message message=new Message();
            message.what=233;
            message.replyTo=clientMessenger;
            try {
                serverMessenger.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
          hasBound=false;
        }
    };

Guess you like

Origin blog.csdn.net/skateboard1/article/details/51253116