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