目录
一.服务(Service)
1.使用服务
- 服务(Service): 后台长时间运行,没有用户界面,是四大应用组件之一
- 服务在主线程中执行,也可以在主线程外线程中执行,可以从应用组件(例如活动)进行管理
- 若服务操作耗时,那么最好在服务里单独启动一个线程执行该操作,如下载或更新
- 服务用于更新数据源,向可见活动提供更新,还可以用于触发通知(SMS或电子邮件的接收的通知)
- 服务可以从其他组件启动/停止/控制(如活动、其他服务或广播接收器),很多时候从 活动 启动服务
2.服务的形式
- 服务的形式有很多种,常见的:启动、绑定、IntentService(了解即可)
- 启动:应用组件(如活动)通过调用 startService() 方法 启动服务
- 特点:一旦被启动,可以在后台无限期运行,即使启动它的组件已被销毁
- 绑定:应用组件(如活动)通过调用 bindService() 方法 绑定到服务上
- 已绑定的服务提供 客户机-服务器接口,允许应用组件与服务交互、发送请求、获取结果,进行进程间通信(IPC)
- 特点:多个组件可以同时绑定一个服务,当所有组件解除绑定后,服务被销毁
- 启动和绑定的区别:启动只能调用服务,绑定可以调用服务,并进行交互
3.startService() 的生命周期
- 启动服务的生命周期:
- 当组件(如活动)调用 startService() 方法,将创建服务,该方法用 Intent对象 作为参数
- 服务正在运行,就调用 onStartCommand() 方法:将其传递给 Intent对象(绑定则是 PendingIntent对象)
- 服务没在运行,则先调用 onCreate() 方法,再调用 onStartCommand() 方法
- 一旦服务被调用,它将无限期运行,直至:
- 服务通过调用 stopSelf() 方法 自行停止
- 其他组件通过调用 stopService(Intent iSrvce) 方法停止服务
- 服务被停止后,系统销毁服务,onDestroy()
- onStartCommand() 方法 调用多次,onCreate() 方法、onDestroy() 方法 调用一次
- 注册服务:在 AndroidManifest.xml文件中声明,将 <service>添加为 <application> 的子元素
4.bindService() 的生命周期
- 绑定服务的生命周期:
- 当组件(如活动)调用 bindService() 方法,将创建绑定服务
- 一旦组件与服务绑定,将通过 IBinder接口 与服务通信,就是说可以进行交互
- 组件可通过调用 unbindService() 方法 来解除绑定
- 当绑定到服务上的所有组件解除绑定后,该服务将自动停止并销毁
- 以下哪个方法 不是 创建绑定服务时 实现的?
- onStartCommand() onCreate() onDestroy() onBind()
- 当需要将服务和组件绑定时,或者进行跨进程通信时,使用绑定服务
5.启动服务Example
- MainActivity.java:调用服务
public class MainActivity extends Activity { // ... // 启动服务 直接把自定义服务写成.class intent = new Intent(MainActivity.this,PlayService.class); } class ButtonListener implements OnClickListener{ @Override public void onClick(View v) { switch(v.getId()){ case R.id.start: startService(intent); // 调用服务 break; case R.id.stop: stopService(intent); // 停止服务 break; }}}}
- PlayService.java:重写服务的各种方法,到系统配置文件中注册服务,到主活动中调用服务
public class PlayService extends Service { MediaPlayer player; // 声明音乐播放器类 static boolean isPlay; // 定义播放器状态 @Override // I:必须实现的绑定方法,当其他组件通过 BindService()请求与服务绑定时调用 public IBinder onBind(Intent arg0) { return null; } @Override // II:当其他组件调用 unbindService()解除被绑定到服务的所有组件的绑定后调用 public boolean onUnbind(Intent intent) { return super.onUnbind(intent); } @Override public void onCreate() { // 首次创建服务时调用,仅调用一次 super.onCreate(); player = MediaPlayer.create(this, R.raw.music2); // 获取音乐播放器组件 res/raw } @Override // 其他组件请求调用服务时 调用,可执行多次 public int onStartCommand(Intent intent, int flags, int startId) { if (!player.isPlaying()) { // 如果不是播放状态 player.start(); // 播放音乐 isPlay=player.isPlaying(); // 修改播放器状态 } return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { // 销毁服务时调用,仅调用一次 player.stop(); // 关闭播放器 if (isPlay) { // 如果正在播放 player.release(); // 就先释放资源(类似流中的.close手动释放),也可以等垃圾回收机制 } super.onDestroy(); }}
- 音乐播放服务界面展示:
6.绑定服务Example
- MainActivity.java:调用服务
public class MainActivity extends Activity { // ... // 获取 Intent和 MyserviceConnection对象 intent=new Intent(MainActivity.this,MyService.class); con=new MyServiceConnection(); } class ButtonListener implements OnClickListener{ @Override public void onClick(View v) { switch(v.getId()){ case R.id.bind: //三个参数:意图、ServiceConnection对象监视服务连接状态、Flag标记值 // Flag标记值:用于指定绑定该服务时是否自动创建服务 bindService(intent, con, BIND_AUTO_CREATE); break; case R.id.unbind: unbindService(con); Log.i("bindService","--MainActivity unbindService(con)--"); break; case R.id.getNumber: StringBuffer buffer =new StringBuffer(); buffer.append("号码是:"); List number = myService.getRandomNumber(); // 获取随机数组 for (int i = 0; i < number.size(); i++) { //遍历数组并显示 buffer.append(number.get(i)); buffer.append(","); } Toast.makeText(MainActivity.this, buffer, Toast.LENGTH_LONG).show(); Log.i("bindService","--MainActivity number--"); break; }}} private ServiceConnection con = new ServiceConnection() { // 与 后台Service进行通讯 @Override public void onServiceConnected(ComponentName name, IBinder service) { // 获取后台Service信息 myService = ((MyService.MyBinder) service).getService(); } @Override public void onServiceDisconnected(ComponentName name) { // 解除绑定调用 }};
- MyService.java:重写服务的各种方法,到系统配置文件中注册服务,到主活动中调用服务
public class MyService extends Service { public MyService() { super();} @Override public void onCreate() { // 1:首次创建服务时调用,调用一次 super.onCreate();} public class MyBinder extends Binder{ // 2:创建MyBinder内部类 并获取 服务对象 与 Service状态 public MyService getService(){ // 创建 获取Service的方法 return MyService.this; // 返回 当前Service类 }} @Override public IBinder onBind(Intent intent) { // 3:当服务绑定的时候调用该方法 return new MyBinder(); // 返回 MyBinder服务对象 实现绑定组件和服务间的交互 } public List getRandomNumber() { // 创建获取 7个33以内随机号码的方法 List resArr = new ArrayList(); // 创建 ArrayList数组 String strNumber=""; for (int i = 0; i < 7; i++) { int number = new Random().nextInt(33) + 1; if (number<10) { // 在数字1~9前加0 数字格式化 strNumber = "0" + String.valueOf(number); } else { strNumber=String.valueOf(number);} resArr.add(strNumber);} return resArr; } @Override // 5:当服务 解除完所有绑定的时候 调用该方法 public boolean onUnbind(Intent intent) { return super.onUnbind(intent); } @Override // 6:当销毁服务时调用 仅调用一次 public void onDestroy() { super.onDestroy(); }}
- 获取随机数字服务界面展示:
- 日志界面:
- 解除绑定之后仍可获取随机数字,除非关闭通道ServiceConnection
- 解除绑定按钮仅能点击一次,否则报错
二.广播接收器(Broadcast Receiver)
1.广播接收器简介
- 广播接收器:四大组件之一,负责接受和响应广播消息,不提供 UI,可以创建状态栏通知
- 广播以 intent 的形式 传达
- 广播可由 系统 / 应用 生成:系统比如电量过低,应用比如求取权限
- 可以接收的广播类型主要有两种:普通广播、有序广播
- 普通广播:广播被 同时发送 到所有相关接收器,接收器以未定义顺序(无序)运行
- void sendBroadcast(Intent intent,String receiverPermission);
- intent:要被广播的 intent
- receiverPermission:可选参数,通常省略,指定广播接收器必须有的权限
- 有序广播:按顺序 将广播发送给接收器,这意味着一次向一个接收器发送广播
void sendOrderBroadcast(Intent intent,String receiverPermission);
- android:priority属性:设置接收器接收的先后顺序
2.创建广播接收器
- 创建广播接收器步骤:
- 集成 BroadcastReceiver类,创建其子类,并重写其中的 onReceive() 方法
- 注册广播接收器
- onReceive(Context context, Intent intent) :
- 广播接收器接收 广播intent 时调用,必须包括在接收广播时需要执行的代码
- Context是接收器运行所在的上下文
- Intent:是正被接受的intent
- abortBroadcast() 方法:终止继续传播,若不需要向下个广播接收器传送广播
3.注册广播接收器
- 注册广播接收器有两种形式:静态注册、动态注册
- 静态注册:在 AndroidManifest.xml清单文件 中注册
- 动态注册:在 java代码中 注册,该情况下,程序执行到注册的代码后才会注册
- unregisterReceiver(BroadcastReceiver) 方法:动态注册中,取消注册广播接收器
IntentFilter filter = new IntentFilter(); filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); registerReceiver(myBroadcastReceiver,filter);
- 常见广播事件:
ACTION_BATTERY_LOW
电量不足
ACTION_HEADSET_PLUG
耳机插入拔出
ACTION_SCREEN_OFF 和 ACTION_SCREEN_ON
屏幕打开关闭,是系统生成的 intent
ACTION_TIMEZONE_CHANGED
时区设置更改
ACTION_BOOT_COMPLETED
设备完成启动
ACTION_CAMERA_BUTTON
启动相机
4.静态注册广播接收器-无序广播
// MainActivity.java:调用广播接收器 public class MainActivity extends Activity { // ... send.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent=new Intent(MainActivity.this,MyMessageReceiver.class); // intent意图启动组件的同时,可以传送数据 // 可以打包成一个Bundle传递,也可以直接 以键-值对的形式 放入数据 intent.putExtra("message",etMsg.getText().toString()); sendBroadcast(intent); // 发送无序广播 }});}} // MyMessageReceiver.java :定义广播 public class MyMessageReceiver extends BroadcastReceiver{ // 定义广播接收器 @Override public void onReceive(Context context, Intent intent) { // 重写方法,收到广播自动调用 // 字符串,用getStringExtra()获取,如果是int,则用getIntExtr()获取 String msg=intent.getStringExtra("message"); Toast.makeText(context,"收到信息:"+msg, Toast.LENGTH_LONG).show(); }} // AndroidMainfest.xml:静态注册广播接收器 <receiver android:name="com.Lyrelion.messagereceiver.MessageReceiver1"> // intent-filter:设置广播接收器可以接受的Intent // priority:接受广播的优先级别,值从-1000到1000,越高,越优先 --> <intent-filter android:priority="999"> <action android:name="andyreceiver"/> </intent-filter> </receiver>
5.静态注册广播接收器-有序广播
// MainActivity.java:调用广播接收器 public class MainActivity extends Activity { // ... @Override public void onClick(View v) { Intent intent=new Intent(); // 隐式Intent:不明确指定目标组件的名称,通过action等信息过滤要使用的目标组件 intent.setAction("andyreceiver"); // 与系统清单文件中保持一致 sendOrderedBroadcast(intent,null); // 发送有序广播 }});}} // MessageReceive1.java:定义广播接收器1 public class MessageReceiver1 extends BroadcastReceiver{ public void onReceive(Context context, Intent intent) { Toast.makeText(context,"Receiver1收到消息!",Toast.LENGTH_SHORT).show(); }} // MessageReceive2.java:定义广播接收器2 public class MessageReceiver2 extends BroadcastReceiver{ public void onReceive(Context context, Intent intent) { Toast.makeText(context,"Receiver2收到消息!",Toast.LENGTH_SHORT).show(); abortBroadcast(); // 终止继续传播 }} // 系统文件清单.xml:设置广播接收顺序 <receiver android:name="com.aa.messagereceiver.MessageReceiver1"> <intent-filter android:priority="999"> <action android:name="andyreceiver"/> // 与下面保持一致 </intent-filter> </receiver> <receiver android:name="com.aa.messagereceiver.MessageReceiver2"> <intent-filter android:priority="1000"> // 所以先接受广播,1000>999 <action android:name="andyreceiver"/> // 与上面保持一致 </intent-filter> </receiver>
- 先收到2的消息(优先级高),再接收1的消息:
6.动态注册广播接收器
// MainActivity.java public class MainActivity extends Activity { // ... mr=new MessageReceiver(); // 实现广播接收器的动态注册 IntentFilter filter=new IntentFilter(); // 动态注册广播 filter.addAction("msgReceiver"); registerReceiver(mr,filter); send.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent=new Intent(); intent.setAction("msgReceiver"); sendBroadcast(intent); // 发送广播 }}); unregister.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { unregisterReceiver(mr); // 取消注册广播接收器 }});}} // MessageReceiver.java public class MessageReceiver extends BroadcastReceiver{ public void onReceive(Context context, Intent intent) { Toast.makeText(context,"收到消息,over!",Toast.LENGTH_LONG).show(); }} // TimeZoneReceiver.java public class TimeZoneReceiver extends BroadcastReceiver{ public void onReceive(Context context, Intent intent) { Toast.makeText(context,"时区改变了!",Toast.LENGTH_LONG).show(); }}