四大组件2–Service
后台执行服务,不直接显示
常时间耗时操作且不需要和用户交互,如后台播放音乐、下载
如果要交互,创建一个Thread线程,与Activity同周期
started
Activity中启动startService(),调用者和服务之间没有联系,调用者退出,服务仍然进行,只有一个服务
[onCreate()->onStartCommand()->startService()->onDestory()]
1、编写类继承Service或者其子类
复写 onStartCommand(),onBind(),onCreate(),onDestory()
int onStartCommand(Intent intent,Int flags ,int startId)执行操作
1、flags 表示服务请求 0,START_REDELIVERY,START_FLAG_REIRY
2、返回值
START_STICKY当服务进行在运行时被杀死,系统将会把它值为started状态,但是并不保存其传递的Intent对象
START_NOT_STICKY 当服务进行在运行时被杀死,并且没有新的Intent对象传递过来,系统会将它值为started状态,但是并不会再次创建进程,直到startService(Intent)方法被调用。
START_REDELIVER_INTENT:当服务在运行时被杀死,它将会隔一段时间后重新被创建,并且最后一个传递的Intent对象将会再次传递过来。
2、manifest文件中声明服务
3、启动服务
Intent intent = new Intent(Main.this,Service.class);
startService(intent);//intent可以传参
stopService(intent);
4、关闭服务
Bound
Activity中启动bindService():调用者和服务绑在一起,调用者一旦退出服务,就终止
[onCreated()->onBind()->onUnbind()->onDestory()]
允许其它的组件绑定到这个Service上,也可以发送请求,接受请求,甚至进程间的通话。仅仅服务于其他组件时存在,不能独立无限期的在后台运行。
创建Bound Services
当创建一个提供绑定功能的服务时,必须提供一个IBinder对象,客户端能使用这个对象与服务进行交互。
定义方式:
1、扩展Binder类
继承Service 复写Ibinder方法,返回一个Ibinder接口实现类对象
返回对象可以继承于Ibinder接口实现类Binder,
返回对象对象中定义 返回本Service类对象的方法。
BindService(intent,conn,Context.BIND_AUTO_CREATE);
public class BinderService extends Service{
private MyBinder binder = new MyBinder();
public MyBinder extends Binder(){
public BinderService getService(){
return BinderService.this;
}
}
@Override
public IBinder onBind(Intent intent){
return binder;
}
public void MyMethod(){
Log.i("TAG","--->")
}
}
boolean isConn =false;
//开启绑定
private void bindService(){
Intent intent = new Intent(BinderActivity.this,BinderService.class);
bindService(intent,conn,Context.BIND_AUTO_CREATE);
}
//解除绑定
private void unBind(){
if(isConn){
unbindService(conn);
}
}
private ServiceConnection conn = new ServiceConnection(){
@Override
public void onServiceDisconnected(ComponentName name){
isConn=false
}
@Override
public void onServiceConnected(ComponentName name,IBinder binder){
MyBinder myBinder = (MyBinder)binder;
BinderService service = myBinder.getService();
service.MyMethod();
isConn=true;
}
}
2、使用Messenger
3、使用AIDL(Android Interface Definition Language)
Thread.currentThread().getId();
处理异步请求
以started方式启动时,默认无处理,执行耗时操作会终止与用户的操作,可以使用两种方法解决
1、使用JAVA多线程技术
2、使用IntentService(Service子类),处理异步请求,一次单个
客户端通过startService(Intent intent)方法传递请求给IntentService,IntentService通过worker thread处理每个Intent对象,执行完所有工作后自动停止Service.
写构造方法
复写onHandleIntent方法
执行过程
创建一个与应用程序主线程分开worker thread用来处理所有通过传递过来的Intent请求
创建一个work queue,一次只传递一个intent到onHandleIntent()方法中,从而不用担心多线程带来的问题
处理完所有请求后自动停止服务,而不需要自己调用stopSelf()方法
默认实现了OnBind()方法,返回值为null
默认实现了OnStartCommand()方法,这个方法会把我们的intent放到work queue中,然后在onHandleIntent()中执行
3、一次处理多个,在onStartCommand中自行处理
消息处理详解
MessageQueue 消息队列,存放消息的地方,按照FIFI规则执行,每一个线程只可以拥有一个MessageQueue。在创建Looper对象会创建一个MessageQueue对象
Message消息对象,MessageQueue中存放的对象。一个MessageQueue中可以包含多个Message对象,可以通过Message.obtain()或者Handle.obtainMessage()获取对象。但是这并不一定是直接创建一个新的实例,而是先从消息池中看有没有可用的Message实例,存在则直接取出这个实例,没有的话,使用给定的参数创建一个Message对象。调用removeMessages()时,将Message从MessageQueue中删除,同时放入到消息池中。
Looper 操作MessageQueue.一个Looper对应一个MessageQueue。通过调用Looper.myLooper()可以获得当前线程的Looper对象。Looper从MessageQueue中取出Message然后,交由Handler的handleMessage()进行处理。处理完后,调用Message.recycle()将其放入消息池中。
Handler消息的处理者,handler负责将需要传递的信息封装成Message对象,然后调用sendMessage()方法将消息放入MessageQueue中。当MessageQueue循环到该Message,调用相应的handler对象的handleMessage()方法对其进行处理,Handler都可以共享同一个Looper和MessageQueue.
步骤Service中
1、onCreate()执行
Looper looper=Looper.getMainLooper();
handler=new ServiceHandler(looper);
ServiceHandler继承于Handler
处理消息在handleMessage中
2、onStartCommand执行
获得消息 Message msg = handler.obtainMessage();
设置消息属性 msg.what msg.arg1,msg.obj
发送消息 handle.sendMessage(msg)
Status Bar Notifications
状态栏与通知栏
添加了一个icon到系统的状态栏中(文本信息可选),添加一段信息到“Notifications”窗口中。当在后台运行的服务需要与用户进行交互时我们可以使用status bar notification
Notification
基本
a icon for status bar 图标
a title and expanded message 标题 和拓展信息
a PendingIntent 可触发的意图
可选
设定消息
播放声音
震动
灯
IntentService 中执行
Notification notification = new Notification(icon,“开始下载”,System.currentTimeMillis());
Intent intent = new Intent(this,MainActivity);
PendingIntent contentIntent=PendingIntent.getActivity(this,0,intent,flags);
flags :FLAG_CANCEL_CURRENT 如果最近的触发意图存在,取消最近的一个产生一个新的
FLAG_NO_CREATE 如果触发意图不存在,返回为null
FLAG_ONE_SHOT 触发意图仅仅使用一次
FLAG_UPDATE_CURRENT如果最近的触发意图存在,会进行保持但如果新的不同则更新
notification.setLatesEventIndo(this,“下载”,"正在下载”,contentIntent);
NotificationManager manager=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);
manager.notify(ID,notification);
ID常量标记触发意图,定义为全局变量
取消状态栏与通知栏
OnStart()中获得
NotificationManager manager=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);
manager.cancel(ID)
可以设定其它通知,更新。
设定默认拓展 notification.sound
DEFAULT_LIGHTS 闪光
DEFAULT_SOUND声音
DEFAULT_VIBRATE震动
DEFAULT_ALL全部开启
自定义 声音URi.parse(“file:///sdcard/xxx.mp3”);
自定义震动 long[] vibrate ={0,100,200}震动时长
notification.vibrate=vibrate;
自定义闪光 闪光颜色,闪光时间
notification.ledARGB
notification.ledonMS
notification.ledOffMS
notification.flags |=Notification.FLAG_SHOW_LIGHTS;
广播事件的处理
广播向外发送消息,可一对多,被多个其他服务接受。
Broadcast Receiver
广播接收器,它和事件处理机制类似,只不过事件处理机制是程序组件级别,而广播事件处理机制是系统级别。
标准广播Action,广播事件使用步骤
1、类继承BroadcaseReceiver,复写onReceiver()方法,里面不要执行耗时操作
public class MyBroadcaseReceiver extends BroadcaseReceiver{
@Override
public void onReceiver(){
}
}
2、在AndroidManifest.xml文件中注册BroadcaseReceiver
<receiver android:name="com.zwl.MyBroadcaseReceiver">
<intent-filter>
<action android:name="com.zwl.broadcast.ACTION">
</intent-filter>
</receiver>
3、构建Intent对象
Intent intent = new Intent();
intent.setAction("com.zwl.broadcast.ACTION");
sendBroadcast(intent);
4、调用sendBroadcase()方法发送广播
程序运行时先注册广播,触发事件发送广播,检查广播类型,类型匹配执行BroadcasetReceiver中的onReceiver的方法,调用时生效,执行结束后销毁。
信息发送广播添加权限
注册Broadcast Receiver的方法
1、在AndroidManifest.xml文件中进行注册
不会因为Activity销毁而销毁广播。
2、在应用程序的代码中进行注册
Recevier定为全局变量
注册 registerReceiver;
MyReceiver receiver;//新建
IntentFilter filter;//新建
filter.addAction(“Action”);
registerReceiver(receiver,filter);
取消注册unregisterReceiver
unregisterReceiver(receiver);
如果在onResume中注册,则应在onPause()中取消注册。
参见官方开发者文档https://developer.android.google.cn/reference/kotlin/android/os/package-summary