Android中Service的通信机制

来源:互联网 发布:电脑网卡mac地址怎么查 编辑:程序博客网 时间:2024/06/07 09:30

在上一篇博客中http://blog.csdn.net/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);    }}
0 0
原创粉丝点击