Interaction mode between Activity and Service

Activity communicates with Service

The first method: call the Service method through MyBinder
step
  • Inherit Binder definition middleman object

BanZhengService

public class BanZhengService extends Service {

    //Return the intermediary object I defined 
    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }
    //Method of certificate handling
    public void banZheng(int money){
        if (money>1000) {
            Toast.makeText(getApplicationContext(), "I'm the leader. I gave you the certificate", 1).show();
        }else {
            Toast.makeText(getApplicationContext(), "I want to work with this money....", 1).show();
        }
    }
    //[1] Define an intermediary object (IBinder)
    
    public class MyBinder extends Binder{
        
        public void callBanZheng(int money){
            //Call the method of certificate processing
            banZheng(money);
        }}}
  • When overriding ServiceConnection and onServiceConnected, the intermediary object binding service is called
    MainActivity
public class MainActivity extends Activity {

    private MyConn conn;
    private MyBinder myBinder;//The intermediary object I defined
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        Intent intent = new Intent(this,BanZhengService.class);
        //Connection service 
        conn = new MyConn();
        bindService(intent, conn, BIND_AUTO_CREATE);
        }
    //Click the button to call the certificate processing method in the service
    public void click(View v) {
        
        myBinder.callBanZheng(10000000);
    }
    
    //Monitor the status of the service
    private class MyConn implements ServiceConnection{

        //When the service connection is successful
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //Get middleman object
            myBinder = (MyBinder) service;
        }
        //Lost connection
        @Override
        public void onServiceDisconnected(ComponentName name) {
            
        }}
    @Override
    protected void onDestroy() {
        //Unbind the service when the activity is destroyed 
        unbindService(conn);
        super.onDestroy();
    }}

The second method: call the Service method through the interface Iservice

Calling a service with an excuse is essentially the same as calling it directly, except for one more step,

Implementation steps

  • 1. Inherit Binder definition middleman object
  • 2. Define the interface
public interface Iservice {

    //Define the methods that the leader wants to expose in the interface
    public void callBanZheng(int money);
//  public void callPlayMaJiang();
  • 3. Rewrite ServiceConnection. When onServiceConnected, call the middleman object and force it to interface (myBinder = (Iservice) service;) Binding service

Here's the difference. Everything else is the same as the first one above
MainActivity

    //Monitor the status of the service
    private class MyConn implements ServiceConnection{
        //When the service connection is successful
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //Get middleman object
            myBinder = (Iservice) service;
        }
        //Lost connection
        @Override
        public void onServiceDisconnected(ComponentName name) {
            
        }
    }
    @Override
    protected void onDestroy() {
        //Unbind the service when the activity is destroyed 
        unbindService(conn);
        super.onDestroy();
    }
}

During the development process, we often encounter the need for Activity and Service to communicate with each other and exchange data. The most common ones are music players, which use Service to play music in the background, and the foreground uses the Activity display interface. After clicking the foreground control, we need to inform the Service to control the playback, pause and switch to the next song, The background Service then transmits the data to the Activity to change the interface display

Activities and services interact in the following ways:

  • Interact via broadcast

  • By sharing files

  • Messenger

  • AIDL

The following uses several interactive methods to realize the program of a timer. The program interface has only one Button, and a number is displayed on the Button. Click the Button to start timing. Add 1 to the data on the Button every 1 second, and use Service to realize the function of timing

The layout file is simple

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>

1. Interact via broadcast

Click Button in Activity to start the Service

public void onClick(View v) {
        Intent intent = new Intent(this, CounterService.class);
        intent.putExtra("counter", counter); //counter is used to count
        startService(intent);
    }

CounterService.java

public class CounterService extends Service {

    int counter;

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // TODO Auto-generated method stub
        counter = intent.getIntExtra("counter", 0);
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                Intent counterIntent = new Intent();
                counterIntent.putExtra("counter", counter);
                counterIntent.setAction("com.example.counter.COUNTER_ACTION");
                sendBroadcast(counterIntent);
                counter++;
            }
        }, 0, 1000);
        return START_STICKY;
    }
}

Start a timer in onStartCommand() of the Service, add 1 to the counter count every 1 second, send the counter through broadcast, take out the counter after receiving the broadcast in the Activity, and set the counter to the Button

Broadcast receiver, defined in Activity

class CounterReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            // TODO Auto-generated method stub
            counter = intent.getIntExtra("counter", 0);
            start.setText(counter + "");
        }
    }

Run the program and click the button to start timing

There is a problem in the process of running the program. Here, the broadcast class is defined in the Activity. It is the internal class of the Activity. When this internal class uses static registration, the program will crash. The reason is that if the internal broadcast class uses static registration, it must be a static internal class, but if it is a static internal class, Only static member variables of external classes can be accessed, so dynamic registration is recommended for internal broadcast classes, and this kind of broadcast is generally only used inside the program, and there is no need to continue receiving broadcast after the process ends

The interaction between Activity and Service through broadcast is simple and easy to implement. The disadvantage is that the sending of broadcast is not restricted by the system. The system will give priority to sending system level broadcast. The customized broadcast receiver may have delay, and there can be no time-consuming operation in the broadcast, otherwise the program will not respond

2. By sharing files

Shared files communicate by reading and writing the same file. When communicating in this way, only one party can write and one party can read at the same time, not both parties can write at the same time. Here, SharedPreferences is used to realize the interaction between Activity and Service

The client clicks the Button to start the Service

public void onClick(View v) {
        Intent intent = new Intent(this, CounterService.class);
        intent.putExtra("counter", counter); //counter is used to count
        startService(intent);
    }

CounterService.java

public class CounterService extends Service {

    int counter;
    SharedPreferences sharedPreferences;


    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // TODO Auto-generated method stub
        counter = intent.getIntExtra("counter", 0);
        sharedPreferences = getSharedPreferences("counter_preferences", Context.MODE_PRIVATE);
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                sharedPreferences.edit().putInt("counter", counter).commit();
                counter++;
            }
        }, 0, 1000);
        return START_STICKY;
    }

}

Start a timer in the Service, increase the count by 1 per second, and then write it to shared preferences

In the Activity, you also need to start a scheduled task to read the count from SharedPreferences

sharedPreferences = getSharedPreferences("counter", Context.MODE_PRIVATE);
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                counter = sharedPreferences.getInt("counter", 0);
                handler.sendEmptyMessage(0x123);
            }
        }, 0, 1000);

Start the timer in onCreate() of Activity and read the data every 1 second. Since the UI cannot be updated in the child thread, send a message to the main thread through the handler to update

Handler handler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            if(msg.what == 0x123) {
                start.setText(counter + "");
            }
        };
    };

The running result of the program is the same as the above figure

Using SharedPreferences for data sharing has no requirements on file format, as long as the data format is agreed between the reading and writing parties. However, it also has limitations. In the face of highly concurrent reading and writing, this method becomes unreliable, which may lead to inconsistent reading and writing data. Therefore, this method is not recommended for communication

3,Messenger

The meaning of messenger can be translated into messenger, through which meepage objects can be passed between different processes. Messenger is a lightweight IPC scheme, and the bottom layer is implemented with AIDL

The steps of data transmission between Activity and Service using Messenger are as follows;

1. Create a messenger object on the Service side

A Handler object needs to be passed in to create Messenger, so first create a new Handler and use Handler to create messenger

@Override
    public void onCreate() {
        // TODO Auto-generated method stub
        super.onCreate();
        mMessenger = new Messenger(handler);
    }

2. Usage method of messenger. Bind() Getbinder() returns a binder object

@Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return mMessenger.getBinder();
    }

3. The client is bound to the Service. In the onServiceConnected() method, use the IBinder object returned by the Service to create a Messenger object. Through this Messenger object, you can send messages to the Service.

ServiceConnection connection = new ServiceConnection() {
        public void onServiceConnected(ComponentName name, android.os.IBinder service) {
            rMessenger = new Messenger(service);
        };
        public void onServiceDisconnected(ComponentName name) {

        };
    };

This only enables the client to send a Message to the Service. If necessary, the Service can send the corresponding client. Similarly, it needs to use the Handler to create the Messenger object on the client, and send the Messenger to the Service through Message. After the Service obtains the Messenger object of the client, it can also send a Message to the client.

Realize the above functions through Messenger

Service side code: counterservice java

public class CounterService extends Service {

    int counter;
    Messenger mMessenger, cMessenger; //Messenger object of Service and messenger object of client

    Handler handler = new Handler() {
        public void handleMessage(Message msg) {
            cMessenger = msg.replyTo; //Gets the client messenger object in the Message
            counter = msg.arg1; //Gets the count in the Message
            new Timer().schedule(new TimerTask() {
                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    Message message = Message.obtain();
                    message.arg1 = counter;
                    try {
                        cMessenger.send(message); //Send a message to the client through the messenger object of the client, and the counter is saved in the message
                    } catch (RemoteException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    counter++;
                }
            }, 0, 1000);
        };
    };

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return mMessenger.getBinder();
    }

    @Override
    public void onCreate() {
        // TODO Auto-generated method stub
        super.onCreate();
        mMessenger = new Messenger(handler); //Initialize Service messenger
    }

}

Client code mainactivity java

public class MainActivity extends Activity {

    Button start;
    int counter = 0;
    Messenger rMessenger, mMessenger; //Messenger object on remote Service side and messenger object on local client side

    Handler handler = new Handler() {
        public void handleMessage(Message msg) {
            counter = msg.arg1; //Gets the count in the Service message
            start.setText(counter + "");
        };
    };

    ServiceConnection connection = new ServiceConnection() {
        public void onServiceConnected(ComponentName name, IBinder service) {
            rMessenger = new Messenger(service); //Initialize the messenger object on the Service side with the IBinder object returned by the Service
            mMessenger = new Messenger(handler); //Initialize local client messenger object
            Message message = Message.obtain();
            message.replyTo = mMessenger; //Save the messenger object of the client in message and send it to the Service through the messenger object of the Service side
            message.arg1 = counter;
            try {
                rMessenger.send(message);
            } catch (RemoteException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        };
        public void onServiceDisconnected(ComponentName name) {
            rMessenger = null;
        };
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        start = (Button)findViewById(R.id.start);
        start.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                Intent intent = new Intent(MainActivity.this, CounterService.class);
                bindService(intent, connection, BIND_AUTO_CREATE);
            }
        });
    }

}

The comments in the code are very detailed. After clicking the button, the client binds to the Service, creates the messenger object on the Service side through the IBinder object returned in the Service, and then sends the local messenger object and count variable of the client to the Service through Message.

After getting the message sent by the client in the Service, take out the Messenger in the information, so that the Service has the Messenger object of the client and can send messages to the client, so as to realize two-way communication.

The running effect of the program is the same as that of the previous two programs

4. Communication using AIDL

AIDL belongs to the IPC mechanism of Android and is often used for cross process communication. The main implementation principle is based on the underlying Binder mechanism. AIDL Service is used to realize inter process communication in another blog http://blog.csdn.net/zh175578809/article/details/71915238 There is a detailed introduction in, so I won't elaborate here

Keywords: Android

Added by todayme on Thu, 10 Feb 2022 14:39:44 +0200