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

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

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

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

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

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

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

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

一、准备Service

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

 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) {
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、改变输入框内容,点击同步数据,界面和对应的日志如下:

   

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

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

Android学习笔记(九)一个例子弄清Service与Activity通信的更多相关文章

  1. Android学习笔记九:Service

    一:Service是什么 Service,服务.一般用于提供需要在后台长期运行的服务(如复杂计算.下载等等耗时任务),其特点是长生命周期的.没有用户界面.在后台运行的. 二:Service的生命周期方 ...

  2. android学习笔记五。1、Service深入学习

    一.Service,服务是没有界面而在后台长期运行的程序,可以看做是后台的Activity. 1.在Android中按返回键退出一个应用并不会(内存充足时)直接销毁一个进程,所以其中的子线程也可以在后 ...

  3. Android学习笔记_70_一个应用程序启动另一个应用程序的Activity

    第一种(我自己写的) :之前在网上看来一些,很多不是我要的可以启动另外一个应用程序的主Activity. //这些代码是启动另外的一个应用程序的主Activity,当然也可以启动任意一个Activit ...

  4. Android学习笔记(八)深入分析Service启动、绑定过程

    Service是Android中一个重要的组件,它没有用户界面,可以运行在后太做一些耗时操作.Service可以被其他组件启动,甚至当用户切换到其他应用时,它仍然可以在后台保存运行.Service 是 ...

  5. android学习笔记九——RatingBar

    RatingBar==>星级评分条 RatingBar和SeekBar十分相似,它们甚至有相同的父类:AbsSeekBar.两者都允许用户通过拖动来改变进度: 两者最大的区别在于RatingBa ...

  6. Android学习笔记-构建一个可复用的自定义BaseAdapter

    转载自http://www.runoob.com/w3cnote/android-tutorial-customer-baseadapter.html   作者:coder-pig 本节引言: 如题, ...

  7. Android学习笔记(5)----启动 Theme.Dialog 主题的Activity时程序崩溃的解决办法

    新建了一个Android Studio工程,在MainActivity的主界面中添加了两个按钮,点击其中一个按钮用来启动 NormalActivity,点击另一按钮用来启动DialogActivity ...

  8. 【转】Pro Android学习笔记(十四):用户界面和控制(2):Text类控制

    目录(?)[-] TextView 例子1在XML中设置autoLink属性 例子2在代码中设置autoLink属性 EditText AutoCompleteTextView MultiAutoCo ...

  9. 【转】 Pro Android学习笔记(九三):AsyncTask(2):小例子

    目录(?)[-] 继承AsyncTask UI操作接口 使用AsyncTask 文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://blog.csdn. ...

随机推荐

  1. 静态库的pdb

    静态库也会有pdb,只不过,默认是以vc编译器作为名字,比如vs2003的lib的pdb是vc70.pdb,vs2008则是vc90.pdb

  2. NODE JS拼命吹,我就不喜欢. 别问为什么,直觉.

    NODE JS拼命吹,我就不喜欢. 别问为什么,直觉. 来看看node js 在paypal的捣鼓文章吧.https://www.paypal-engineering.com/2013/11/22/n ...

  3. ASP.NET服务端基本控件介绍

    ASP.NET服务端基本控件介绍 大概分为三种控件: HTML控件,ASP.NET把HTML控件当成普通字符串渲染到浏览器端,不去检查正确性,无法在服务端进行处理ASP.NET服务端控件,经过ASP. ...

  4. 用Session实现验证码

    新建一个 ashx 一般处理程序 如: YZM.ashx继承接口 IRequiresSessionState //在一般处理程序里面继承 HttpContext context 为请求上下文,包含此次 ...

  5. php安装过程中遇到的需要安装的问题

    http://www.cnblogs.com/kristain/articles/3809243.html     借鉴php安装错误 2013-01-04 19:16:49 分类: 系统运维 环境: ...

  6. apache config directive – order, allow, deny

    在对apache进行配置的时候,常看到oerder, allow, deny.现在就简单回顾一下其用法. 对于每个对于资源的请求,服务器可以配置是否允许这个请求通过.在配置当中,使用的是允许与不允许的 ...

  7. DIV+CSS 网页布局之:两列布局

    1.宽度自适应两列布局 两列布局可以使用浮动来完成,左列设置左浮动,右列设置右浮动,这样就省的再设置外边距了. 当元素使用了浮动之后,会对周围的元素造成影响,那么就需要清除浮动,通常使用两种方法.可以 ...

  8. input多选图片与显示

    input标签 在使用input选择文件时遇到了 在遍历input file.files 只显示最后一个,修改如下: CSS: <style type="text/css"& ...

  9. [转]Vim 复制粘贴探秘

    Vim作为最好用的文本编辑器之一,使用vim来编文档,写代码实在是很惬意的事情.每当学会了vim的一个新功能,就会很大地提高工作效率.有人使用vim几十年,还没有完全掌握vim的功能,这也说明了vim ...

  10. Python 学习笔记(1) - 开始

    找一个能看的教程(不用太过于纠结以至于耗费大量时间,很可能还没开始就放弃了. -- 这条要作为新的做事准则放入我的日常了,警惕一开始就追求完美常常会什么也得不到.) 我喜欢看书不爱视频,所以找了这个: ...