文章目录
第一章 四大组件
第二组件 Service
(一)基础知识
1.定义
服务,是Android四大组件之一, 属于 计算型组件
2.作用
提供 需在后台长期运行的服务,如:复杂计算、音乐播放、下载等
3.特点
无用户界面、在后台运行、生命周期长
一个运行在后台执行长时间运行的操作组件,它不提供任何用户界面,作为与Activity同级的组件,它依旧是运行在主线程中(由于是在主线程,所以需开一个线程来执行耗时操作)。
一个组件还可以与一个Service进行绑定来实现组件之间的交互,甚至可以执行IPC(Inter-Process Communication)进程间通信。
Service可以在后台执行很多任务,比如处理网络事务,播放音乐,文件读写或者与一个内容提供者交互,等等。
(二)生命周期
1.生命周期常用方法
1、4个手动调用方法
startService() 启动服务
stopService() 关闭服务
bindService() 绑定服务
unbindService() 解绑服务
2、5个内部自动调用方法
onCreat() 创建服务
onStartCommand() 开始服务
onDestroy() 销毁服务
onBind() 绑定服务
onUnbind() 解绑服务
2.生命周期方法具体介绍
1、startService()
(1)作用:启动Service服务
(2)自动调用方法:onCreate()、onStartCommand()
a)一个Service被sartService多次启用,onCreate()只会调用一次,onStartCommand()可以多次调用(=startService()调用次数)
b)onStartCommand()必须返回一个整数=描述系统因异常(1.内存不足2.进程关闭等)在杀死onStartCommand()后的服务后应该如何继续运行
Service中onStartCommand回调四种返回值的区别
- START_NOT_STICKY:系统在onStartCommand()返回后终止服务,不会重新启动服务。除非有挂起 Intent 要传递,否则系统不会重建服务。这是最安全的选项,可以避免在不必要时服务自动重启以及应用能够轻松重启所有未完成的作业时运行服务。
- START_STICKY:系统在onStartCommand()返回后终止服务,会重新启动服务&调用onStartCommand(),但不保留已传入的intent。用null intent调用onStartCommand()。除非有挂起的未发送完的启动服务的intent,会依此继续传入intent。适用于媒体播放器类似服务,不执行命令,但要一直执行并随时待命。
- START_REDELIVER_INTENT:系统在onStartCommand()返回后终止服务,会重新启动service&通过传递给服务最后一个intent调用onstartCommand()。任何挂起的未发送完的intent,会依此传入。适用于主动执行应该立即恢复工作的活跃服务,比如下载文件。
实例:
服务
public class MyService extends Service {
private static final String TAG = MyService.class.getSimpleName();
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "onCreate");
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Log.e(TAG, "postDelayed");
// 制造异常,kill 掉该 Service
int a = 1 / 0;
}
}, 3000L);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand, intent: " + intent + ", startId: " + startId);
return Service.START_STICKY_COMPATIBILITY;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
Log.e(TAG, "onDestroy");
super.onDestroy();
}
}
测试
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService(new Intent(MainActivity.this, MyService.class));
}
}
测试结果:
1、使用 START_STICKY 作为返回值
// 服务重新创建并重启,但是 intent 对象被置空了
03-22 20:43:42.199 11233-11233/com.example.test E/MyService: onCreate
03-22 20:43:42.209 11233-11233/com.example.test E/MyService: onStartCommand, intent: null, startId: 2
03-22 20:43:45.209 11233-11233/com.example.test E/MyService: postDelayed
2、使用 START_NOT_STICKY 作为返回值
// 服务没有重新创建
3、使用 START_REDELIVER_INTENT 作为返回值
// 服务重新创建并启动,intent 对象没有被置空
03-22 20:46:00.879 14792-14792/com.example.test E/MyService: onCreate
03-22 20:46:00.879 14792-14792/com.example.test E/MyService: onStartCommand, intent: Intent { cmp=com.example.test/.MyService }, startId: 1
03-22 20:46:03.889 14792-14792/com.example.test E/MyService: postDelayed
(3)示意图:
2、stopService()
(1)作用:关闭Service服务
(a)未启动的服务(本身关闭)(b)启动&绑定&未解绑的服务无法调用onDestroy()——>无法关闭服务
(2)自动调用的方法:onDestroy()
(3)示意图:
3、bindService()
(1)作用:绑定Service服务
(2)自动调用的方法:onCreate()、onBind()
(3)示意图:
4、unbindService()
(1)作用:解绑Service服务
(2)自动调用的方法:onUnbind()、onDestroy()
(3)示意图:
3.应用场景
1、启动服务——只使用startService
(1)流程图:
(2)备注:
1、一个Service的onCreate()只调用一次(只有一个Service实例),onStartCommand()调用次数=startService调用次数
2、startService与stopService配对(必须通过stopService关闭Service)
3、只使用startService(),无法与Activity交互,绑定者无法操作Service
2、绑定服务——只使用BindService
(1)流程图:
(2)备注:
1、一个Service的onCreate()只调用一次(只有一个Service实例),onBind()调用次数=BindService调用次数,多个绑定者可以绑定到同一个服务上
2、bindService与unbindService配对,当该Service所有绑定者解绑后,系统会自动销毁服务(不需手动stop)
3、bindService能让Activity与Service交互,绑定者通过一个iBinder接口与服务通信
3、启动服务后绑定——startService()+bindService
(1)流程图:
(2)备注:
1、关于操作Service:
(1)startService()、stopService()只能开启&关闭Service,但无法操作Service
(2)bindService()、unbindService()除了绑定Service还能操作Service
2、关于Service销毁:
(1)startService()开启的Service,绑定者退出后Service仍存在
(2)bindService()开启的Service,绑定者退出后,Service随着调用者退出销毁
(三)Service分类
1.类型
1、按运行地点分(1)本地服务(2)远程服务
2、按运行类型分(1)前台服务(2)后台服务
3、按功能分(1)可通信服务(2)不可通信服务
2.详细介绍
1、按运行地点分
(1)本地服务
1、特点:(1)运行在主线程(2)主线程被终止后,服务也会终止(3)节约资源,且不需要AIDL/IPC,简便
2、场景:(最常用)需要依附某个进程,不需要常驻的服务,如音乐播放
3、使用:
步骤1:新建子类继承Service类——需重写父类的onCreate()、onStartCommand()、onDestroy()和onBind()方法
public class MyService extends Service {
@Override
public void onCreate() {
super.onCreate();
System.out.println("执行了onCreat()");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("执行了onStartCommand()");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
System.out.println("执行了onDestory()");
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
步骤2:构建用于启动Service的Intent对象
步骤3:调用startService()启动Service、调用stopService()停止服务
//构建启动服务的Intent对象
Intent startIntent = new Intent(this, MyService.class);
//调用startService()方法-传入Intent对象,以此启动服务
startService(startIntent);
//构建停止服务的Intent对象
Intent stopIntent = new Intent(this, MyService.class);
//调用stopService()方法-传入Intent对象,以此停止服务
stopService(stopIntent);
步骤4:在AndroidManifest.xml里注册Service
<application
//注册Service服务
<service android:name=".MyService">
</service>
</application>
(2)远程服务
2.1)特点:
- 运行在独立进程(占用一定资源)
- 服务常驻后台,不受其他Activity影响(Activity所在进程被kill时,服务仍在进行)
- 使用AIDL进行IPC
2.2)应用场景:系统级别服务(常驻),多个应用程序共享同一个后台服务(跨进程通信)
2.3)远程服务Service(含AIDL&IPC讲解)
2.4)IntentService用法&源码(客户端远程调用服务器端的远程Service)
1.AIDL与IPC(使用AIDL进行IPC)
IPC:Inter-Process Communication,即跨进程通信
AIDL:Android Interface Definition Language,即Android接口定义语言;用于让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能。
2.多进程通信中2个角色:
服务端:
步骤1:新建定义AIDL文件,并声明该服务需要向客户端提供的接口
// 在新建的AIDL_Service1.aidl里声明需要与Activity进行通信的方法
package scut.carson_ho.demo_service;
interface AIDL_Service1 {
void AIDL_Service();
}
步骤2:在Service子类中实现AIDL中定义的接口方法,并定义生命周期的方法(onCreat、onBind()、blabla)
public class MyService extends Service {
// 实例化AIDL的Stub类(Binder的子类)
AIDL_Service1.Stub mBinder = new AIDL_Service1.Stub() {
//重写接口里定义的方法,用于客户端调用
@Override
public void AIDL_Service() throws RemoteException {
System.out.println("客户端通过AIDL与远程后台成功通信");
}
};
//重写与Service生命周期的相关方法
@Override
public void onCreate() {
super.onCreate();
System.out.println("执行了onCreat()");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("执行了onStartCommand()");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
System.out.println("执行了onDestory()");
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
System.out.println("执行了onBind()");
//在onBind()返回继承自Binder的Stub类型的Binder,非常重要
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
System.out.println("执行了onUnbind()");
return super.onUnbind(intent);
}
}
步骤3:在AndroidMainfest.xml中注册服务 & 声明为远程服务
<service
android:name=".MyService"
android:process=":remote" //将本地服务设置成远程服务
android:exported="true" //设置可被其他进程调用
>
//该Service可以响应带有scut.carson_ho.service_server.AIDL_Service1这个action的Intent。
//此处Intent的action必须写成“服务器端包名.aidl文件名”
<intent-filter>
<action android:name="scut.carson_ho.service_server.AIDL_Service1"/>
</intent-filter>
</service>
客户端:
步骤1:拷贝服务端的AIDL文件到客户端目录下,并进行编译
步骤2:使用Stub.asInterface接口获取服务器的Binder,根据需要调用服务提供的接口方法
//定义aidl接口变量
private AIDL_Service1 mAIDL_Service;
//创建ServiceConnection的匿名类
private ServiceConnection connection = new ServiceConnection() {
//重写onServiceConnected()方法和onServiceDisconnected()方法
//在Activity与Service建立关联和解除关联的时候调用
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//使用AIDLService1.Stub.asInterface()方法获取服务器端返回的IBinder对象
//将IBinder对象传换成了mAIDL_Service接口对象
mAIDL_Service = AIDL_Service1.Stub.asInterface(service);
try {
//通过该对象调用在MyAIDLService.aidl文件中定义的接口方法,从而实现跨进程通信(客户端调用服务端方法)
mAIDL_Service.AIDL_Service();
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
步骤3:通过Intent指定服务端的服务名称和所在包,绑定远程Service
//通过Intent指定服务端的服务名称和所在包,与远程Service进行绑定
//参数与服务器端的action要一致,即"服务器包名.aidl接口文件名"
Intent intent = new Intent("scut.carson_ho.service_server.AIDL_Service1");
//Android5.0后无法只通过隐式Intent绑定远程Service
//需要通过setPackage()方法指定包名
intent.setPackage("scut.carson_ho.service_server");
//绑定服务,传入intent和ServiceConnection对象
bindService(intent, connection, Context.BIND_AUTO_CREATE);
2、按运行类型分
(1)前台服务
1.1)特点:在通知栏显示通知(用户可以看到)
1.2)应用场景:服务使用时需要让用户知道并进行相关操作,如音乐播放服务(服务被终止时,通知栏的通知也会消失)
1.3)使用方法:
Service类onCreate()增加通知栏显示功能
//添加下列代码将后台Service变成前台Service
//构建"点击通知后打开MainActivity"的Intent对象
Intent notificationIntent = new Intent(this,MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,0,notificationIntent,0);
//新建Builer对象
Notification.Builder builer = new Notification.Builder(this);
builer.setContentTitle("前台服务通知的标题");//设置通知的标题
builer.setContentText("前台服务通知的内容");//设置通知的内容
builer.setSmallIcon(R.mipmap.ic_launcher);//设置通知的图标
builer.setContentIntent(pendingIntent);//设置点击通知后的操作
Notification notification = builer.getNotification();//将Builder对象转变成普通的notification
startForeground(1, notification);//让Service变成前台Service,并在系统的状态栏显示出来
(2)后台服务
后台:后台任务运行完全不依赖UI,即时Activity被销毁/程序被关闭,只要进程还在,后台任务就可继续运行
2.1)特点:处于后台的服务(用户无法看到)
2.2)应用场景:服务使用时不需要让用户知道并进行相关操作,如天气更新,日期同步(服务被终止时,用户是无法知道的)
3、按功能分
(1)可通信服务
1.1)特点:a)用bindServiceb)调用者退出后,随调用者销毁c)只有绑定Service服务(Binder类、bindService()、onBind()、unbindService()、onUnbind())才能与Activity通信
1.2)应用场景:后台服务需要与Activity进行通信
1.3)使用方法:
步骤1:在新建子类继承Service类,并新建一个子类继承自Binder类、写入与Activity关联需要的方法、创建实例
public class MyService extends Service {
private MyBinder mBinder = new MyBinder();
@Override
public void onCreate() {
super.onCreate();
System.out.println("执行了onCreat()");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("执行了onStartCommand()");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
System.out.println("执行了onDestory()");
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
System.out.println("执行了onBind()");
//返回实例
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
System.out.println("执行了onUnbind()");
return super.onUnbind(intent);
}
//新建一个子类继承自Binder类
class MyBinder extends Binder {
public void service_connect_Activity() {
System.out.println("Service关联了Activity,并在Activity执行了Service的方法");
}
}
}
步骤2:在Activity通过调用MyBinder类中的public方法来实现Activity与Service的联系(Activity指挥Service执行的功能)
1、构建绑定服务的Intent对象
//构建绑定服务的Intent对象
Intent bindIntent = new Intent(this, MyService.class);
//调用bindService()方法,以此停止服务
bindService(bindIntent,connection,BIND_AUTO_CREATE);
//参数说明
//第一个参数:Intent对象
//第二个参数:上面创建的Serviceconnection实例
//第三个参数:标志位
//这里传入BIND_AUTO_CREATE表示在Activity和Service建立关联后自动创建Service
//这会使得MyService中的onCreate()方法得到执行,但onStartCommand()方法不会执行
//调用unbindService()解绑服务
//参数是上面创建的Serviceconnection实例
unbindService(connection);
2、创建ServiceConnection匿名类,,在Activity和Service建立和解除关联时调用
//创建ServiceConnection的匿名类
private ServiceConnection connection = new ServiceConnection() {
//重写onServiceConnected()方法和onServiceDisconnected()方法
//在Activity与Service建立关联和解除关联的时候调用
@Override
public void onServiceDisconnected(ComponentName name) {
}
//在Activity与Service解除关联的时候调用
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//实例化Service的内部类myBinder
//通过向下转型得到了MyBinder的实例
myBinder = (MyService.MyBinder) service;
//在Activity调用Service类的方法
myBinder.service_connect_Activity();
}
};
(2)不可通信服务
2.1)特点:a)用startService启动b)调用者退出后,随调用者销毁
2.2)应用场景:该后台服务不进行任何通信
(四)Service使用解析【见Service分类】
1.本地服务(普通服务、不可通信服务)
2.可通信服务
3.前台服务
4.远程服务
(五)AndroidManifest.xml中Service元素常见属性
1、android:name: 服务类名。可以是完整的包名+类名。也可使用. 代替包名。
2、android:exported: 其他应用能否访问该服务,如果不能,则只有本应用或有相同用户ID的应用能访问。默认为false。
3、android:process: 服务所运行的进程名。默认是在当前进程下运行,与包名一致。
4、android:permission: 申请使用该服务的权限,如果没有配置下相关权限,服务将不执行
(六)对比
1.Service和Thread区别
(1)运行线程
Service运行在主线程(不能处理耗时操作,否则会出现ANR),Thread运行在工作线程
(2)运行范围
Service在进程运行
- 完全不依赖UI/Activity,只要进程还在,Service就可继续运行
- 所有的Activity都可与Service关联,获得Service实例&操作其中方法
- 若要处理耗时操作,则在Service里创建Thread子线程执行
Thread在Activity运行
- 依赖于某个Activity
- 在一个Activity中创建子线程,另一个Activity无法对其操作
- Activity很难控制Thread,且Activity被销毁后,无法再获取之前创建的子线程实例
2.Service和IntentService区别
(1)什么是IntentService?为什么要使用IntentService?
Service是用于后台服务的,保证程序挂到后台时某些组件仍能正常工作。然而Service不是独立的进程,是默认运行在主线程中的。所以如果直接在服务里去处理一些耗时的逻辑,就很容易出现ANR(Application Not Responding)的情况。
所以这个时候就需要用到Android多线程编程的技术了,我们可以在服务内开启线程,采用thread+handler方式处理耗时操作。但服务一旦启动,就会一直处于运行状态,必须调用stopSelf()/stopService()才能让服务停止。编写逻辑较复杂。
我们可以引用IntentService。
IntentService是继承Service的,那么它包含了Service的全部特性,当然也包含service的生命周期,那么与service不同的是,IntentService在执行onCreate操作的时候,内部开了一个线程,去执行耗时操作。
IntentService是一个通过Context.startService(Intent)启动可以处理异步请求的Service,使用时你只需要继承IntentService和重写其中的onHandleIntent(Intent)方法接收一个Intent对象,工作完成后会自动停止服务。所有的请求的处理都在一个工作线程中完成,它们会交替执行(但不会阻塞主线程的执行),一次只能执行一个请求。
这是一个基于消息的服务,每次启动该服务并不是马上处理你的工作,而是首先会创建对应的Looper,Handler并且在MessageQueue中添加的附带客户Intent的Message对象,当Looper发现有Message的时候接着得到Intent对象通过在onHandleIntent((Intent)msg.obj)中调用你的处理程序,处理完后即会停止自己的服务,意思是Intent的生命周期跟你的处理的任务是一致的,所以这个类用下载任务中非常好,下载任务结束后服务自身就会结束退出。
(2)特点
- 会创建独立的worker线程来处理所有的Intent请求;
- 会创建独立的worker线程来处理onHandleIntent()方法实现的代码,无需处理多线程问题;
- 所有请求处理完成后,IntentService会自动停止,无需调用stopSelf()方法停止Service;
(3)实例
(3.1)新建一个MyIntentService类继承自IntentService
1、提供一个无参的构造函数,并且必须在其内部调用父类的有参构造函数。
2、在其子类中去实现onHandlerIntent()这个抽象方法,在这个方法中可以去处理一些具体的逻辑。(用于处理耗时操作,该方法在子线程中执行)
public class MyIntentService extends IntentService{
public MyIntentService(){
super("MyIntentService"); //调用父类的有参构造函数
}
@Override
protected void onHandlerIntent(Intent intent){
//打印当前线程的id
Log.d("MyIntentService","Thread id is"+ Thread.currentThread().getId());
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("MyIntentService","onDestroy executed");//运行结束后服务自动停止
}
}
(3.2)在Activity启动服务
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.id.activity_main);
Button startIntentService=(Button)findViewById(R.id.start_intent_service);
startIntentService.setOnClickListener(this);
}
@Override
public void onClick(View v){
switch(v.getId()) {
...
case R.id.start_intent_service:
//打印主线程的id
Log.d("MainActivity","Thread id is"+Thread.currentThread().getId());
Intent intentService=new Intent(this,MyIntentService.class);
startService(intentService);//启动服务
break;
default:
break;
}
}
}
(3.3)在AndroidManifest注册服务
<application
<service android:name=".MyIntentService" />
</application>
(4)IntentService与service的区别
IntentService是继承并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统的Service一样,同时,当任务执行完后,IntentService会自动停止,而不需要我们手动去控制或stopSelf()。
另外,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。它本质上就是一个封装了HandlerThread+Handler的异步框架
(七)Activity与Service通信方式总结
*方法1:binder+回调(listener)
当Activity通过调用bindService(Intent service, ServiceConnection conn,int flags),我们可以得到一个Service的一个对象实例,然后我们就可以访问Service中的方法,同时利用回调接口实现Service中进度变化主动通知Activity更新UI
(1)新建一个回调接口,通过回调接口实现当Service中进度发生变化主动通知Activity更新UI
(回调接口的理解见:一个经典例子让你彻彻底底理解java回调机制)
public interface OnProgressListener {
void onProgress(int progress);
}
(2)新建一个Service类
public class MsgService extends Service {
public static final int MAX_PROGRESS = 100;//进度条最大值
private int progress = 0;//进度条进度值
private OnProgressListener onProgressListener;//更新进度的回调接口
public void setOnProgressListener(OnProgressListener onProgressListener) {
//注册回调接口的方法,供外部调用
this.onProgressListener = onProgressListener;
}
public int getProgress() {
//增加get()方法,供Activity调用,返回progress
return progress;
}
/**
* 模拟下载任务,每秒钟更新一次
*/
public void startDownLoad(){
new Thread(new Runnable() {
@Override
public void run() {
while(progress < MAX_PROGRESS){
progress += 5;
//进度发生变化通知调用方
if(onProgressListener != null){
onProgressListener.onProgress(progress);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
@Override
public IBinder onBind(Intent intent) {
return new MsgBinder();//返回Binder对象
}
public class MsgBinder extends Binder{
public MsgService getService(){
return MsgService.this;//返回当前service对象
}
}
}
(3)新建一个ServiceConnection对象,它是一个接口,Activity与Service绑定后,在onServiceConnected回调方法中返回服务对象。
onServiceConnected用于执行Activity与Service绑定后执行相关操作。
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//返回一个MsgService对象
msgService = ((MsgService.MsgBinder)service).getService();
}
};
(4)Activity代码
public class MainActivity extends Activity {
private MsgService msgService;
private ProgressBar mProgressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//绑定Service
Intent intent = new Intent("com.example.communication.MSG_ACTION");
bindService(intent, conn, Context.BIND_AUTO_CREATE);
mProgressBar = (ProgressBar) findViewById(R.id.progressBar1);
Button mButton = (Button) findViewById(R.id.button1);
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//开始下载
msgService.startDownLoad();
}
});
}
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//返回一个MsgService对象
msgService = ((MsgService.MsgBinder)service).getService();
//注册回调接口来接收下载进度的变化
msgService.setOnProgressListener(new OnProgressListener() {
@Override
public void onProgress(int progress) {
mProgressBar.setProgress(progress);
}
});
}
};
@Override
protected void onDestroy() {
unbindService(conn);
super.onDestroy();
}
}
*方法2:广播(推荐LocalBroadcaseManager)
利用系统的LocalBroadcastManager,Service send message, Activity receive message;Service向Activity发送消息,可以使用广播,当然Activity要注册相应的接收器。适用于Service要向多个Activity发送同样的消息。
当进度变化时发送一条广播,然后在Activity的注册广播接收器,接受广播后更新progressbar
public class MainActivity extends Activity {
private ProgressBar mProgressBar;
private Intent mIntent;
private MsgReceiver msgReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//动态注册广播接收器
msgReceiver = new MsgReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.example.communication.RECEIVER");
registerReceiver(msgReceiver, intentFilter);
mProgressBar = (ProgressBar) findViewById(R.id.progressBar1);
Button mButton = (Button) findViewById(R.id.button1);
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//启动服务
mIntent = new Intent("com.example.communication.MSG_ACTION");
startService(mIntent);
}
});
}
@Override
protected void onDestroy() {
//停止服务
stopService(mIntent);
//注销广播
unregisterReceiver(msgReceiver);
super.onDestroy();
}
/**
* 广播接收器
* @author len
*
*/
public class MsgReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
//拿到进度,更新UI
int progress = intent.getIntExtra("progress", 0);
mProgressBar.setProgress(progress);
}
}
}
public class MsgService extends Service {
/**
* 进度条的最大值
*/
public static final int MAX_PROGRESS = 100;
/**
* 进度条的进度值
*/
private int progress = 0;
private Intent intent = new Intent("com.example.communication.RECEIVER");
/**
* 模拟下载任务,每秒钟更新一次
*/
public void startDownLoad(){
new Thread(new Runnable() {
@Override
public void run() {
while(progress < MAX_PROGRESS){
progress += 5;
//发送Action为com.example.communication.RECEIVER的广播
intent.putExtra("progress", progress);
sendBroadcast(intent);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
startDownLoad();
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
方法3:binder+Handler
Service 持有 Activity的Handler 对象,Service 通过往该Handler send message 的方式,达到通信的目的。
方法4:开源组件(EventBus,otto)
利用反射或者注释的方式实现对注册类的注册,然后遍历当前的注册表,通过key进行查询,然后dispatch,调用相应的事件处理方法。(不同的开源框架实现有所区别)