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

        

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

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

       

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

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

       

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

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

  • 相关阅读:
    Entity Framework Tips: IN关键字的支持
    (转载)用IT网络和安全专业人士视角来裁剪云的定义
    解决数据库查询中的锁冲突
    2010年计划
    MergeOption 枚举实测
    习惯的力量
    Entity Framewok中获取实体对象的部分属性
    JQuery下拉框联动本地数据
    Json学习整理
    Hadoop:mapreduce的splitsize和blocksize
  • 原文地址:https://www.cnblogs.com/codingblock/p/4850299.html
Copyright © 2020-2023  润新知