转载

Android高级编程笔记(九)一个例子弄清Service与Activity通信

上一篇博文主要整理了Service的创建、绑定过程,本篇主要整理一下Service与Activity的通信方式。包括在启动一个Service时向它传递数据、怎样改变运行中的Service中得数据和侦听Service内数据的改变。

本篇将写一个demo来说明以下三个问题:

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

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

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

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

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

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

一、准备Service

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

 1 public class MyService extends Service {  2     private String data = "默认消息";  3     private boolean serviceRunning = false;  4       5     // 必须实现的方法,用于返回Binder对象  6     @Override  7     public IBinder onBind(Intent intent) {  8         System.out.println("--onBind()--");  9         return new MyBinder(); 10     } 11  12     public class MyBinder extends Binder { 13         MyService getService() { 14             return MyService.this; 15         } 16  17         public void setData(String data) { 18             MyService.this.data = data; 19         } 20     } 21  22     // 创建Service时调用该方法,只调用一次 23     @Override 24     public void onCreate() { 25         super.onCreate(); 26         System.out.println("--onCreate()--"); 27         serviceRunning = true; 28         new Thread() { 29             @Override 30             public void run() { 31                 int n = 0; 32                 while (serviceRunning) { 33                     n++; 34                     String str = n + data; 35                     System.out.println(str); 36                     if (dataCallback != null) { 37                         dataCallback.dataChanged(str); 38                     } 39                     try { 40                         sleep(1000); 41                     } catch (InterruptedException e) { 42                         e.printStackTrace(); 43                     } 44                 } 45             }; 46         }.start(); 47     } 48  49     // 每次启动Servcie时都会调用该方法 50     @Override 51     public int onStartCommand(Intent intent, int flags, int startId) { 52         System.out.println("--onStartCommand()--"); 53         data = intent.getStringExtra("data"); 54         return super.onStartCommand(intent, flags, startId); 55     } 56  57     // 解绑Servcie调用该方法 58     @Override 59     public boolean onUnbind(Intent intent) { 60         System.out.println("--onUnbind()--"); 61         return super.onUnbind(intent); 62     } 63  64     // 退出或者销毁时调用该方法 65     @Override 66     public void onDestroy() { 67         serviceRunning = false; 68         System.out.println("--onDestroy()--"); 69         super.onDestroy(); 70     } 71  72     DataCallback dataCallback = null; 73  74     public DataCallback getDataCallback() { 75         return dataCallback; 76     } 77  78     public void setDataCallback(DataCallback dataCallback) { 79         this.dataCallback = dataCallback; 80     } 81  82     // 通过回调机制,将Service内部的变化传递到外部 83     public interface DataCallback { 84         void dataChanged(String str); 85     } 86  87 }

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

二、准备布局文件

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

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  2     xmlns:tools="http://schemas.android.com/tools"  3     android:layout_width="match_parent"  4     android:layout_height="match_parent"  5     android:orientation="vertical">  6   7     <TextView  8         android:id="@+id/tv_out"  9         android:layout_width="fill_parent" 10         android:layout_height="wrap_content" 11         android:text="显示区域" /> 12      13     <EditText 14         android:id="@+id/et_data" 15         android:layout_width="match_parent" 16         android:layout_height="wrap_content" 17         android:ems="10" > 18  19         <requestFocus /> 20     </EditText> 21      22     <Button 23         android:id="@+id/btn_start_service" 24         android:layout_width="fill_parent" 25         android:layout_height="wrap_content" 26         android:text="startService" /> 27      28     <Button 29         android:id="@+id/btn_stop_service" 30         android:layout_width="fill_parent" 31         android:layout_height="wrap_content" 32         android:text="stopService" /> 33      34     <Button 35         android:id="@+id/btn_bind_service" 36         android:layout_width="fill_parent" 37         android:layout_height="wrap_content" 38         android:text="bindService" /> 39      40     <Button 41         android:id="@+id/btn_unbind_service" 42         android:layout_width="fill_parent" 43         android:layout_height="wrap_content" 44         android:text="unbindService" /> 45      46     <Button 47         android:id="@+id/btn_sync_data" 48         android:layout_width="fill_parent" 49         android:layout_height="wrap_content" 50         android:text="同步数据" /> 51  52 </LinearLayout>

三、准备Activity

MainActivity代码如下:

  1 public class MainActivity extends Activity implements OnClickListener {   2    3     private Intent intent = null;   4     private Button btn_start_service;   5     private Button btn_stop_service;   6     private Button btn_bind_service;   7     private Button btn_unbind_service;   8     private Button btn_sync_data;   9     private EditText et_data;  10     private TextView tv_out;  11     MyServiceConn myServiceConn;  12     MyService.MyBinder binder = null;  13   14     @Override  15     protected void onCreate(Bundle savedInstanceState) {  16         super.onCreate(savedInstanceState);  17         setContentView(R.layout.activity_main);  18         intent = new Intent(this, MyService.class);  19         myServiceConn = new MyServiceConn();  20         setOnClick();  21     }  22       23     @Override  24     public void onClick(View v) {  25         switch (v.getId()) {  26         case R.id.btn_start_service:  27             //用intent启动Service并传值  28             intent.putExtra("data", et_data.getText().toString());  29             startService(intent);  30             break;  31         case R.id.btn_stop_service:  32             //停止Service  33             stopService(intent);  34             break;  35         case R.id.btn_bind_service:  36             //绑定Service  37             bindService(intent, myServiceConn, Context.BIND_AUTO_CREATE);  38             break;  39         case R.id.btn_unbind_service:  40             //解绑Service  41             if (binder != null) {  42                 unbindService(myServiceConn);  43             }  44             break;  45         case R.id.btn_sync_data:  46             //注意:需要先绑定,才能同步数据  47             if (binder != null) {  48                 binder.setData(et_data.getText().toString());  49             }  50             break;  51         default:  52             break;  53         }  54     }  55   56     class MyServiceConn implements ServiceConnection {  57         // 服务被绑定成功之后执行  58         @Override  59         public void onServiceConnected(ComponentName name, IBinder service) {  60             // IBinder service为onBind方法返回的Service实例  61             binder = (MyService.MyBinder) service;  62             binder.getService().setDataCallback(new MyService.DataCallback() {  63                 //执行回调函数  64                 @Override  65                 public void dataChanged(String str) {  66                     Message msg = new Message();  67                     Bundle bundle = new Bundle();  68                     bundle.putString("str", str);  69                     msg.setData(bundle);  70                     //发送通知  71                     handler.sendMessage(msg);  72                 }  73             });  74         }  75   76         @SuppressLint("HandlerLeak")   77         Handler handler = new Handler() {  78             public void handleMessage(android.os.Message msg) {  79                 //在handler中更新UI  80                 tv_out.setText(msg.getData().getString("str"));  81             };  82         };  83   84         // 服务奔溃或者被杀掉执行  85         @Override  86         public void onServiceDisconnected(ComponentName name) {  87             binder = null;  88         }  89     }  90       91     private void loadUI() {  92         btn_start_service = (Button) findViewById(R.id.btn_start_service);  93         btn_stop_service = (Button) findViewById(R.id.btn_stop_service);  94         btn_bind_service = (Button) findViewById(R.id.btn_bind_service);  95         btn_unbind_service = (Button) findViewById(R.id.btn_unbind_service);  96         btn_sync_data = (Button) findViewById(R.id.btn_sync_data);  97         et_data = (EditText) findViewById(R.id.et_data);  98         tv_out = (TextView) findViewById(R.id.tv_out);  99     } 100  101     private void setOnClick() { 102         loadUI(); 103         btn_start_service.setOnClickListener(this); 104         btn_stop_service.setOnClickListener(this); 105         btn_bind_service.setOnClickListener(this); 106         btn_unbind_service.setOnClickListener(this); 107         btn_sync_data.setOnClickListener(this); 108     } 109  110 }

代码分析:

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,界面和对应的日志如下:

Android高级编程笔记(九)一个例子弄清Service与Activity通信 Android高级编程笔记(九)一个例子弄清Service与Activity通信

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

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

Android高级编程笔记(九)一个例子弄清Service与Activity通信

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

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

Android高级编程笔记(九)一个例子弄清Service与Activity通信 Android高级编程笔记(九)一个例子弄清Service与Activity通信

因本人水平有限,如在文中发现错误或者描述不当的地方,敬请指正,感激不尽!

声明:欢迎转载,转载是请注明本文链接,谢谢!

正文到此结束
Loading...