Android Communication between service and activity

Scenario(方案) 1:    Broadcast receiver另有:android.support.v4.content.LocalBroadcastManager

https://androidexperinz.wordpress.com/2012/02/14/communication-between-service-and-activity-part-1/   

To communicate between activity ad services there two major ways
1. Broadcast receiver
2. Aidl – Android Interface Definition Language
3. Messenger

In this post, we will just go through Broadcast receivers,
1. Create a service and activity.
2. Create a broadcast receiver for both service and activity.
3. Register the receiver in the activity and service.

Scenario:
1. Service starts on launching the application.
2. Onclick of a button, activity sends broadcast to service
3. service in turn sends broadcast to the activity.

SERVICE
public class MyService extends Service {
//Strings to register to create intent filter for registering the recivers
    private static final String ACTION_STRING_SERVICE = "ToService";
    private static final String ACTION_STRING_ACTIVITY = "ToActivity";

//STEP1: Create a broadcast receiver
    private BroadcastReceiver serviceReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(getApplicationContext(), "received message in service..!", Toast.LENGTH_SHORT).show();
            Log.d("Service", "Sending broadcast to activity");
            sendBroadcast();
        }
    };

    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("Service", "onCreate");
//STEP2: register the receiver
        if (serviceReceiver != null) {
//Create an intent filter to listen to the broadcast sent with the action "ACTION_STRING_SERVICE"
            IntentFilter intentFilter = new IntentFilter(ACTION_STRING_SERVICE);
//Map the intent filter to the receiver
            registerReceiver(serviceReceiver, intentFilter);
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("Service", "onDestroy");
//STEP3: Unregister the receiver
        unregisterReceiver(serviceReceiver);
    }

//send broadcast from activity to all receivers listening to the action "ACTION_STRING_ACTIVITY"
    private void sendBroadcast() {
        Intent new_intent = new Intent();
        new_intent.setAction(ACTION_STRING_ACTIVITY);
        sendBroadcast(new_intent);
    }
}

ACTIVITY
public class sample extends Activity {
//Strings to register to create intent filter for registering the recivers
    private static final String ACTION_STRING_SERVICE = "ToService";
    private static final String ACTION_STRING_ACTIVITY = "ToActivity";

//STEP1: Create a broadcast receiver
    private BroadcastReceiver activityReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(getApplicationContext(), "received message in activity..!", Toast.LENGTH_SHORT).show();
        }
    };

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

//STEP2: register the receiver
        if (activityReceiver != null) {
//Create an intent filter to listen to the broadcast sent with the action "ACTION_STRING_ACTIVITY"
            IntentFilter intentFilter = new IntentFilter(ACTION_STRING_ACTIVITY);
//Map the intent filter to the receiver
            registerReceiver(activityReceiver, intentFilter);
        }

//Start the service on launching the application
        startService(new Intent(this,MyService.class));

        findViewById(R.id.button).setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Log.d("SampleActivity", "Sending broadcast to service");
                sendBroadcast();
            }
        });
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("Service", "onDestroy");
//STEP3: Unregister the receiver
        unregisterReceiver(activityReceiver);
    }

//send broadcast from activity to all receivers listening to the action "ACTION_STRING_SERVICE"
    private void sendBroadcast() {
        Intent new_intent = new Intent();
        new_intent.setAction(ACTION_STRING_SERVICE);
        sendBroadcast(new_intent);
    }
}

Conclusion:
This seemed a simple solution but this was a chaotic one. So had to move into second approach.

        

Scenario(方案) 2:   AIDL

https://androidexperinz.wordpress.com/2012/02/21/communication-between-service-and-activity-part-2/

Aidl though simple seems to be tough in the beginning, not sure why but hope this post will help to make it simple.

Scenario:(we will have 2 aidl, 2 activity, 1 sevice)

IService.aidl – to bind the activity and service (to process messages from activity)
IServiceCallback.aidl – to return messages to the activity from service
sample2.java – to start the service (not required for time-being let the flow be like this)
sample.java – activity bounded to the service
MsgService.java – service
IService.aidl:

package com.sample.aidl;
import com.sample.aidl.IServiceCallBack;
interface IService {
    void fromActivity(); // function called from activity
    void registerCallBack(IServiceCallBack cb);
}

IServiceCallBack.aidl:

package com.sample.aidl;
interface IServiceCallBack {
    void fromService();
}

Sample2.java:

Create a button and on click of it start the service as below:
startService(new Intent(sample2.this,MsgService.class));

MsgService.java:

Step1: Create a callback list, which gets populated when registerCallback is called from the activity
final RemoteCallbackList<IServiceCallBack> mCallbacks = new RemoteCallbackList<IServiceCallBack>();
Step2: Implement the IService.aidl
private final IService.Stub mBinder = new IService.Stub() {
    @Override
    public void fromActivity() throws RemoteException {
        Log.d("AIDL service", "fromActivity method called from Activity");
        fromActivityProcess();
    }
    @Override
    public void registerCallBack(IServiceCallBack cb) throws RemoteException {
        if(cb!=null){
            Log.d("AIDL service", "registerCallBack registering");
            mCallbacks.register(cb);
        }
    }
};
Step3:Return the binder(IService type) in onBind function
@Override
public IBinder onBind(Intent arg0) {
    return mBinder; // null;
}
Step4:startActivity(sample.java) in onCreate function
@Override
public void onCreate() {
    super.onCreate();
    Log.d("AIDL service", "Oncreate");
    startActivity();
}
public void startActivity(){
    Log.d("AIDL service", "startActivity");
    Intent intent = new Intent();
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    intent.setClassName("com.sample.aidl", "com.sample.aidl.sample");
    startActivity(intent);
}
Step5:Implement fromActivityProcess function – to send callback to the activity
public void fromActivityProcess(){
    Log.d("AIDL service", "fromActivity1");
    Log.d("AIDL service", "Now to call someMethodInActivity");
    try {
        // this is very important - if u miss it u ll end in exception
        int N = mCallbacks.beginBroadcast();
        Log.d("AIDL service", "mCallBacks N value = " + N);
        // now for time being we will consider only one activity is bound to the service, so hardcode 0
        mCallbacks.getBroadcastItem(0).fromService();
        mCallbacks.finishBroadcast();
    } catch (RemoteException e) {
        e.printStackTrace();
    }
}

Sample.java:

Step1: Implement IServiceCallback stub
private IServiceCallBack mCallback = new IServiceCallBack.Stub() {
    @Override
    public void fromService() throws RemoteException {
        Log.d("Sample Activity", "Callback from Service");
        someMethodInActivity();
    }
};
public void someMethodInActivity(){
    Log.d("Sample Activity", "someMethodInActivity");
}
Step2: Create a class which implements serviceConnection
class MyConnection implements ServiceConnection {
    @Override
    public void onServiceDisconnected(ComponentName name) {
    }
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        Log.d("Sample Activity", "Inside OnServiceConnected callback");
        remoteService = IService.Stub.asInterface(service);
        try {
            remoteService.registerCallBack(mCallback);
        } catch (RemoteException e1) {
            e1.printStackTrace();
        }
        try {
            Log.d("Sample Activity", "Before calling fromActivity in Activity");
            remoteService.fromActivity();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}
Step3: Bind the service and activity on click of a button or on onCreate function
boolean ret = getApplicationContext().bindService(new Intent(sample.this,MsgService.class),
mConnection, Context.BIND_AUTO_CREATE);
Log.d("Sample Activity", "After bind call " + ret);
Step4: unbind the service onDestroy function
unbindFromService();

Scenario(方案) 3:  Messenger

https://androidexperinz.wordpress.com/2012/12/14/communication-between-service-and-activity-part-3/

After a long time, I found out that Messenger can also be used to communicate between Activity and Services.

What does this Messenger mean?
    It is a Parcelable type, which carries messages from service to activity and vise vera.
    It is similar to aidl, which can work between two different processes.

Quick example how to implement them.
Create a service on launching the activity. On clicking the button in the

Activity:
1. It will have an handler which is responsible for handling all the messages from the service
private class IncomingHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        String str = (String)msg.obj;
        Toast.makeText(getApplicationContext(),
            "From Service -> " + str, Toast.LENGTH_LONG).show();
    }
}

2. Create a class implementing ServiceConnection Interface
class MyServiceConnection implements ServiceConnection {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        mServiceMessenger = new Messenger(service);
        // where mServiceMessenger is used to send messages to Service
        // service is the binder returned from onBind method in the Service
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        mServiceMessenger = null;
        unbindService(mCon);
    }
}

3. Create a Messenger Object in OnCreate method with the object of IncomingHandler class
Messenger mActivityMessenger;
mActivityMessenger = new Messenger(new IncomingHandler());

4. Start the service in the onCreate method
Intent lIntent = new Intent(MainActivity.this, MainService.class);
lIntent.putExtra("Messenger", mActivityMessenger);
startService(lIntent);

5. Bind to a service in OnResume method
@Override
protected void onResume() {
    super.onResume();
    Intent lIntent = new Intent(MainActivity.this, MainService.class);
    bindService(lIntent, mCon, 0); // mCon is an object of MyServiceConnection Class
}

6. Unbind the service in OnPause method to avoid Service leakage
@Override
protected void onPause() {
    super.onPause();
    unbindService(mCon);
}

7. Add a onClickListener to the button and send message to service on onClick event.
((Button)findViewById(R.id.button1)).setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        Log.d(TAG, "onClick");
        Message msg = new Message();
        msg.obj = "Hi service..";
        try {
            mServiceMessenger.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
});
NOTE:
1. Currently string is sent in the message as obj but when the activity and the service are in different process we need to send the string as bundle.
2. If there are more than one activity bound to the service then the service should have a arraylist of client registered and replyTo variable in Message should be set to that activity’s messenger.

Service:
1. It will have an handler which is responsible for handling all the messages from the Activity
private class IncomingHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        String str = (String)msg.obj;
        Toast.makeText(getApplicationContext(),
    "From Activity -> " + str, Toast.LENGTH_LONG).show();
        Message lMsg = new Message();
        lMsg.obj="Hello Activity";
        try {
            mActivityMessenger.send(lMsg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}

3. Create a Messenger Object in OnCreate method with the object of IncomingHandler class
Messenger mServiceMessenger;
mServiceMessenger = new Messenger(new IncomingHandler());

4. Get the extras from the messenger and save it in the local variable
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.d(TAG, "onStartCommand");
    mActivityMessenger = intent.getParcelableExtra("Messenger");
    return super.onStartCommand(intent, flags, startId);
}

5. OnBind return the service messenger’s binder to the activity.
@Override
public IBinder onBind(Intent intent) {
    Log.d(TAG, "onBind");
    return mServiceMessenger.getBinder();
}

以上三种方案思路太清晰了!震撼!

Scenario(方案) 4:第三方之EventBus

转载于:https://my.oschina.net/u/1389206/blog/866096

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值