Service与Activity通信 回调方式***

  要实现service与activity的高强度通信用什么方法?

  service与activity之前的通信方式有很多,回调接口方式、观察者模式、广播、还有handler等,方法有很多,但要高强度地通信,个人觉得还是用回调接口的方式比较妥当(虽然本人开始也是用的传入的handler。。。哈哈,用handler的话,如果涉及到service要向多个activity传送数据就变得麻烦了)。所以在这里记录下回调接口的方式进行通信:

1、怎样在启动一个Service时向它传递数据

  关键点:Intent传值,onStartCommand()接收。

  2、怎样向运行的Service中同步数据

  关键点:通过onBind()获取Service实例,然后再调用Binder中的相关方法。

  3、怎样侦听Service中数据变化

  关键点:通过回调函数达到目的。

一、准备Service

  先贴出Service的详细代码,然后再慢慢分析


import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.Binder;

public
class MyService extends Service { private String data = "默认消息"; private boolean serviceRunning = false; // 必须实现的方法,用于返回Binder对象 @Override public IBinder onBind(Intent intent) { System.out.println("--onBind()--"); return new MyBinder(); } public class MyBinder extends Binder { MyService getService() { return MyService.this; } public void setData(String data) { MyService.this.data = data; } } // 创建Service时调用该方法,只调用一次 @Override public void onCreate() { super.onCreate(); System.out.println("--onCreate()--"); serviceRunning = true; new Thread() { @Override public void run() { int n = 0; while (serviceRunning) { n++; String str = n + data; System.out.println(str); if (dataCallback != null) { dataCallback.dataChanged(str); } try { sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }; }.start(); } // 每次启动Servcie时都会调用该方法 @Override public int onStartCommand(Intent intent, int flags, int startId) { System.out.println("--onStartCommand()--"); data = intent.getStringExtra("data"); return super.onStartCommand(intent, flags, startId); } // 解绑Servcie调用该方法 @Override public boolean onUnbind(Intent intent) { System.out.println("--onUnbind()--"); return super.onUnbind(intent); } // 退出或者销毁时调用该方法 @Override public void onDestroy() { serviceRunning = false; System.out.println("--onDestroy()--"); super.onDestroy(); } DataCallback dataCallback = null; public DataCallback getDataCallback() { return dataCallback; } public void setDataCallback(DataCallback dataCallback) {//注意这里以单个回调为例  如果是向多个activity传送数据 可以定义一个回调集合 在此处进行集合的添加 this.dataCallback = dataCallback; } // 通过回调机制,将Service内部的变化传递到外部 public interface DataCallback { void dataChanged(String str); } }

 代码分析:我们都知道,通过startService启动一个Service时,Service会调用生命周期函数onStartCommand(),在代码中创建一个Service,在onStartCommand()方法中获取从Activity传递过来的数据,并在Service的onCreate()方法中开启一个新的线程,使其循环调用回调函数,以达到通知外界信息改变的目的。并在Service中通过Binder类,将Service与Activity链接起来,以实现信息同步。

二、准备布局文件

  布局文件比较简单,直接贴出,就不分析了,activity_main.xml如下:

<LinearLayout 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"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv_out"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="显示区域" />
    
    <EditText
        android:id="@+id/et_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10" >

        <requestFocus />
    </EditText>
    
    <Button
        android:id="@+id/btn_start_service"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="startService" />
    
    <Button
        android:id="@+id/btn_stop_service"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="stopService" />
    
    <Button
        android:id="@+id/btn_bind_service"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="bindService" />
    
    <Button
        android:id="@+id/btn_unbind_service"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="unbindService" />
    
    <Button
        android:id="@+id/btn_sync_data"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="同步数据" />

</LinearLayout>

三、准备Activity

   MainActivity代码如下:


public
class MainActivity extends Activity implements OnClickListener { private Intent intent = null; private Button btn_start_service; private Button btn_stop_service; private Button btn_bind_service; private Button btn_unbind_service; private Button btn_sync_data; private EditText et_data; private TextView tv_out; MyServiceConn myServiceConn; MyService.MyBinder binder = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); intent = new Intent(this, MyService.class); myServiceConn = new MyServiceConn(); setOnClick(); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_start_service: //用intent启动Service并传值 intent.putExtra("data", et_data.getText().toString()); startService(intent); break; case R.id.btn_stop_service: //停止Service stopService(intent); break; case R.id.btn_bind_service: //绑定Service bindService(intent, myServiceConn, Context.BIND_AUTO_CREATE); break; case R.id.btn_unbind_service: //解绑Service if (binder != null) { unbindService(myServiceConn); } break; case R.id.btn_sync_data: //注意:需要先绑定,才能同步数据 if (binder != null) { binder.setData(et_data.getText().toString()); } break; default: break; } } class MyServiceConn implements ServiceConnection { // 服务被绑定成功之后执行 @Override public void onServiceConnected(ComponentName name, IBinder service) { // IBinder service为onBind方法返回的Service实例 binder = (MyService.MyBinder) service; binder.getService().setDataCallback(new MyService.DataCallback() { //执行回调函数 @Override public void dataChanged(String str) { Message msg = new Message(); Bundle bundle = new Bundle(); bundle.putString("str", str); msg.setData(bundle); //发送通知 handler.sendMessage(msg); } }); } @SuppressLint("HandlerLeak") Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { //在handler中更新UI tv_out.setText(msg.getData().getString("str")); }; }; // 服务奔溃或者被杀掉执行 @Override public void onServiceDisconnected(ComponentName name) { binder = null; } } private void loadUI() { btn_start_service = (Button) findViewById(R.id.btn_start_service); btn_stop_service = (Button) findViewById(R.id.btn_stop_service); btn_bind_service = (Button) findViewById(R.id.btn_bind_service); btn_unbind_service = (Button) findViewById(R.id.btn_unbind_service); btn_sync_data = (Button) findViewById(R.id.btn_sync_data); et_data = (EditText) findViewById(R.id.et_data); tv_out = (TextView) findViewById(R.id.tv_out); } private void setOnClick() { loadUI(); btn_start_service.setOnClickListener(this); btn_stop_service.setOnClickListener(this); btn_bind_service.setOnClickListener(this); btn_unbind_service.setOnClickListener(this); btn_sync_data.setOnClickListener(this); } }

代码分析:

  1、加载UI,初始化变量啥的跳过了,主要说一下关键代码,在第28代码中,与启动一个Activity类似,通过Intent想要启动的Service传递参数。

  2、在37行通过bindService绑定Service,然后在ServiceConnection中获取Service类中onBind方法返回的实例,获取实例Service实例后,我们就可以通过调用Service中MyBinder的setData()方法对Service进行同步数据,如48行所示。

  3、整个过程,在Service的onCreate方法中都会循环调用回调函数,同时我们在MainActivity中重写回调方法以实现更新UI。

四、测试

  1、启动示例后,在输入框输入你好,然后点击startService,界面和对应的日志如下:

    

  看了下面的代码后就会知道,此时因为没有绑定service,所以办法执行回调函数更新UI,所以显示区域没有更新。

  2、点击bindService后,界面如下:

   

  当执行bindService后,在ServiceConnection方法中就会执行执行回调函数更新UI,此时显示区域开始更新。

  3、改变输入框内容,点击同步数据,界面和对应的日志如下:

   

原文地址:https://www.cnblogs.com/jiangzhaowei/p/11341890.html