Android中Service的通信机制

本文详细介绍了Android中Service的通信机制,包括通过startService启动服务时的数据传递,以及通过bindService绑定服务实现更高效的数据交互。同时,讨论了如何在Service中将状态变化通知给外界,如使用接口回调和广播机制更新UI线程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在上一篇博客中http://blog.youkuaiyun.com/redoq/article/details/52142868,我们对Service进行了粗略的讲解,这一篇博客我将介绍Service的通信机制,不足之处望指正。


由于Service的启动分为两种,所以我把Service的通信分为两种介绍

一:对于通过startService启动的服务

我们可以通过下面的代码将数据发送到Service中

启动服务的Activity中的代码

Intent i = new Intent(this,MyService.class);
i.putExtra("data","send data");
...
startService(i);

MyService中的代码,由于使用的是startService启动服务,所以这里用onStartCommand来接收数据

private String data = "";
 @Override
    public int onStartCommand(final Intent intent, int flags, int startId) {

        data = intent.getStringExtra("data");  //通过onStartCommand中的intent参数获取数据
        System.out.println("接收到的数据为:" + data);
        return super.onStartCommand(intent, flags, startId);
    }


输出结果  接收到的数据为:send data

通过startService传递数据虽然简单方便,但是不能将MyService中的数据返回到调用它的Activity,除非使用广播,我将在后面对广播进行讲解。

=============================================================================

二、通过bindService绑定服务传递数据

1、首先,我们重写MyService中的onBind()并新建一个类继承Binder

public class MyService extends Service {
    private String data = "";

    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();   //将MyBinder对象返回给启动MyService的Activity
    }

    public class MyBinder extends Binder {    //Binder类实现了IBinder接口
        public void setData(String data) {
            MyService.this.data = data;   //修改data的值
        }
    }
}

2、然后我们使用bindService绑定服务并重写onServiceConnected()和onServiceDisconnected()

MainActivity代码

    private MyService.MyBinder binder = null; //新建一个MyBinder对象,用于接收MyService返回的MyBinder对象

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                binder.setData("修改MyService中data的值 ");
            }
        });

        bindService(new Intent(this,MyService.class),this,Context.BIND_AUTO_CREATE);
    }

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
            binder = (MyService.MyBinder)service;  //接收MyService返回的MyBinder对象
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
    }

通过上面的绑定服务来直接调用方法就可以将数据传递给Service,这种方法比startService更加方便同时也更加高效。

===========================================================================================

三、如何将服务中状态的改变通知给外界,比如Service执行某些操作之后想要更新主UI线程

我们知道,在辅线程中是不能进行主UI线程更新操作的,有些人可能听过这样的口诀“主线程不做耗时操作,子线程不更新UI”

1、使用接口回调的方式更新UI线程

我们在MyService中写一个接口

public static interface Callback{
    void onDataChange(String data);
}

为了大家能直观的理解,我把MyService的代码全列出

public class MyService extends Service {
    private boolean running = false;   
    private CallBack mCallBack = null;

    public MyService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        running = true;

        new Thread() {
            @Override
            public void run() {
                super.run();
                int i = 0;
                while (running) {
                    i++;
                    if (mCallBack != null) {
                        mCallBack.onDataChange(i + "");  //把更新的内容传出去
                    }

                    try {
                        sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        running = false;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }

    public class MyBinder extends Binder{
        public MyService getMyService(){
            return MyService.this;
        }
    }

    public CallBack getCallBack() {
        return mCallBack;
    }

    public void setCallBack(CallBack callBack) {
        mCallBack = callBack;
    }

    public static interface CallBack {
         void onDataChange(String data);
    }

}

下面的内容是Activity中的部分代码,控件的初始化代码没给


    private MyService.MyBinder binder = null;
    private TextView tv;

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        binder = (MyService.MyBinder) service;  //获取MyService中onBind返回的 MyBinder对象
        binder.getMyService().setCallBack(new MyService.CallBack() {  
            @Override
            public void onDataChange(String data) { //这里不能直接更新UI,因为辅线程不能更新UI主线程
                Message message = new Message();
                Bundle b = new Bundle();
                b.putString("data", data);
                message.setData(b);
                mHandler.sendMessage(message);  //把数据通过Message发送到Handler中
            }
        });
    }

    private Handler mHandler = new Handler() {  //定义一个Handler对象,用于更新UI线程
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            tv.setText(msg.getData().getString("data"));  //更新UI
        }
    };

    @Override
    public void onServiceDisconnected(ComponentName name) {

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.bindService:
                bindService(new Intent(MainActivity.this, MyService.class), this, Context.BIND_AUTO_CREATE);
                break;
        }
    }

2、使用广播(broadcast)将MyService中的数据传到外界,更新UI

当MyService中的数据变化时就发送一条广播,然后在Activity中已经注册的广播接收器就能接收到广播并获取内容进行UI更新。
(1)首先在Activity中注册广播

public class MainActivity extends Activity implements View.OnClickListener {
    private TextView tv;
    private MsgReceiver msgReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.tv);
        findViewById(R.id.startService).setOnClickListener(this);
        findViewById(R.id.stopService).setOnClickListener(this);
    }

    //广播接收器
    public class MsgReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            tv.setText(intent.getIntExtra("data", 0)+"");  //接收到广播数据后更新UI
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.startService:
                msgReceiver = new MsgReceiver();  //定义一个广播接收器

                // IntentFilter intentFilter = new IntentFilter(MyService.ACTION);  //也可像下面那样写

                 IntentFilter intentFilter = new IntentFilter();
                intentFilter.addAction(MyService.ACTION);  //添加action,要和发送广播的Intent中的action一致
                registerReceiver(msgReceiver,intentFilter);  //注册广播

                startService(new Intent(this, MyService.class));  //启动服务
                break;
            case R.id.stopService:
                stopService(new Intent(this, MyService.class));  //停止服务
                unregisterReceiver(msgReceiver);  //注销广播
        }
    }
}

(2)、在MyService中将需要传出的数据通过广播发送出去

public class MyService extends Service {
    private boolean running = false;
    public static final String ACTION = "包名.intent.action.MyService";
    @Override
    public void onCreate() {
        super.onCreate();
        running = true;

        new Thread() {
            @Override
            public void run() {
                super.run();
                int i = 0;
                while (running) {
                    i++;
                    Intent intent = new Intent( ACTION );  //添加action,要和Activity中接收广播的action一致
                    intent.putExtra("data", i);
                    sendBroadcast(intent);  //每次内容更改都发送一条广播

                    try {
                        sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        running = false;
    }

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AidenWU

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值