day08 服务
pasting
1 进程的概念 [1]Android下四大组件都运行在主线程下
[2]服务是在后台下运行 没有界面的activity
service 是 activity的大爷
进程的优先级
[1]Foreground process 前台进程 优先级最高 相当于activity执行了onResume方法 用户正在交互
[2]Visible process 可视进程 一直影响用户看得见相当于activity执行了onPause方法
[3]service process 服务进程 通过startService方法开启一个服务
[4]Background process 后台进程 相当于activity执行了onStop方法 界面不可见 但是activity并没有销毁
[5]Empty process 空进程 不会维持任何组件运行
2 start方式开启服务的特点
[1]定义四大组件的方式是一样的
[2]定义一个类继承Service
[3]第一次点击按钮开启服务 服务执行onCreate方法和onStartCommand方法
[4]第二次点击按钮 再次开启服务 服务执行onStartCommand方法
[5]服务一旦被开启 服务就会后台长期运行 直到用户手工停止
补充:股票应用
3 电话qie听器案例
TelephoneManager
实现步骤
[1]定义一个服务 开启服务 记得在清单文件配置服务
[2]在服务的onCreate方法里面 获取TelephoneManager
// [1]获取teltphonemanager的实例TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
[3]注册电话的监听
/ [2]注册电话的监听tm.listen(new MyPhoneStateListener(),PhoneStateListener.LISTEN_CALL_STATE);
[4]定义一个类用来监听电话的状态
// 定义一个类用来监听电话的状态private class MyPhoneStateListener extends PhoneStateListener {// 当电话设置状态发生改变的时候调用@Overridepublic void onCallStateChanged(int state, String incomingNumber) {// [3]具体判断一下电话的状态switch (state) {case TelephonyManager.CALL_STATE_IDLE:// 空闲状态if(recorder!=null){recorder.stop();recorder.reset(); // You can reuse the object by going back to// setAudioSource() steprecorder.release(); // Now the object cannot be reused}break;case TelephonyManager.CALL_STATE_OFFHOOK:// 接听状态System.out.println("开始录音");recorder.start(); // Recording is now startedbreak;case TelephonyManager.CALL_STATE_RINGING:// 响铃状态System.out.println("准备录音机");try {//[1]创建MediaRecorder实例recorder = new MediaRecorder();//[2]设置音频的来源recorder.setAudioSource(MediaRecorder.AudioSource.MIC);//[3]设置输出的格式recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);//[4]设置音频的编码方式recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);//[5]设置存放的路径recorder.setOutputFile("/mnt/sdcard/luyin.3gp");//[6]准备录recorder.prepare();} catch (IllegalStateException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}break;}super.onCallStateChanged(state, incomingNumber);}}
[5]加权限
<uses-permission android:name="android.permission.READ_PHONE_STATE"/><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.RECORD_AUDIO"/>
[6]把开启服务的逻辑放到手机重启的广播中
package com.phone.phonelistener;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;public class BootReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {//服务开启Intent intent1 = new Intent(context,PhoneService.class);context.startService(intent1);}}
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<applicationandroid:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme" ><activityandroid:name=".MainActivity"android:label="@string/app_name" ><!-- <intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter> --></activity><service android:name="com.phone.phonelistener.PhoneService"></service><receiver android:name="com.phone.phonelistener.BootReceiver"><intent-filter ><action android:name="android.intent.action.BOOT_COMPLETED"/></intent-filter></receiver></application>
4 使用服务注册特殊的广播接收者
操作特别频繁的广播事件 比如屏幕的解锁和锁屏
实现步骤
[1]定义广播接收者 接收屏幕解锁屏幕的事件
package com.phone.registerbroadcast;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;public class ScreenReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {//获取当前事件类型String action = intent.getAction();if("android.intent.action.SCREEN_OFF".equals(action)){System.out.println("说明屏幕锁屏了");}else if("android.intent.action.SCREEN_ON".equals(action)){System.out.println("说明屏幕解屏了");}}}
[2]写一个服务 用来注册广播接收者
package com.phone.registerbroadcast;import android.app.Service;import android.content.Intent;import android.content.IntentFilter;import android.os.IBinder;public class ScreenService extends Service {private ScreenReceiver receiver;@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubreturn null;}@Overridepublic void onCreate() {//[1]创建ScreenReceiver实例receiver = new ScreenReceiver();//[2]获取IntentFilter 实例 目的是添加actionIntentFilter filter = new IntentFilter();//[3]动态添加actionfilter.addAction("android.intent.action.SCREEN_OFF");filter.addAction("android.intent.action.SCREEN_ON");//[4]注册服务registerReceiver(receiver, filter);super.onCreate();}@Overridepublic void onDestroy() {unregisterReceiver(receiver);super.onDestroy();}}
[3]在MainActivity的onCreate方法中开启服务
package com.phone.registerbroadcast;import android.app.Activity;import android.content.Intent;import android.os.Bundle;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Intent intent = new Intent(this,ScreenReceiver.class);startService(intent);}}
[4]配置服务
<service android:name="com.phone.registerbroadcast.ScreenService"></service>
5 bindService开启服务
[1]第一次点击按钮 会执行服务的onCreate方法和onBind方法
[2]当onBind方法返回null的时候onServiceConnected方法是不执行的
[3]第二次点击按钮 服务没有响应
[4]不求同时生 但求同时死 指的是调用者和服务之间
[5]服务不可以多次解绑 多次解绑会报异常
[6]通过bind方式开启服务 服务不能在设置页面找到 相当于是一个隐形的服务
6 为什么要引入bindService
目的是为了调用服务里的方法
7 通过bindservice方式调用 服务方法里面的过程
[1]在服务的内部定义一个方法 让activity调用
[2]在服务的内容定义一个中间人对象(IBinder)
[3]把定义的中间人对象在onBind方法里面返回
[4]在mainactivity的oncreate方法里面调用bindservice的目的是为了获取我们定义的中间人对象
[5]获取中间人对象
[6]拿到中间人对象就可以间接调用到服务里面的方法
[7]当Activity销毁的时候解绑服务
package com.phone.ban;import android.app.Service;import android.content.Intent;import android.os.Binder;import android.os.IBinder;import android.widget.Toast;public class BanZhangService extends Service {//把定义的中间人对象返回@Overridepublic IBinder onBind(Intent intent) {return new MyBinder();}public void banZhang(int money) {if(money > 1000){Toast.makeText(getApplicationContext(), "我是领导 把证给你办了", 1).show();}else{Toast.makeText(getApplicationContext(), "这点钱还想办事....", 1).show();}}//[1]定义中间人对象public class MyBinder extends Binder{public void callBanZheng(int money){//调用办证方法banZhang(money);}}}
package com.phone.ban;import android.app.Activity;import android.content.ComponentName;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.view.View;import com.phone.ban.BanZhangService.MyBinder;public class MainActivity extends Activity {private MyConn conn;private MyBinder myBinder;//定义的中间人对象@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Intent intent = new Intent(this,BanZhangService.class);//绑定服务conn = new MyConn();bindService(intent, conn, BIND_AUTO_CREATE);}//点击按钮调用服务里办证的方法public void click(View v){myBinder.callBanZheng(1001);}//监视服务的状态private class MyConn implements ServiceConnection{//当服务连接成功调用@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {myBinder = (MyBinder) service;}@Overridepublic void onServiceDisconnected(ComponentName name) {}}@Overrideprotected void onDestroy() {//当activity销毁的时候解绑服务unbindService(conn);super.onDestroy();}}
8 通过接口方式调用服务里面的方法
接口可以隐藏代码内部的细节 让程序员暴露自己只想暴露的方法
[1]定义一个接口 把想暴露的方法都定义在接口里面
[2]我们定义的中间人对象事项我们自己定义的接口
[3]在获取中间人对象的时候
myBinder = (Iservice) service;
补充:混合方式开启服务
需求:既想让服务在后台长期运行 又想调用服务里面的方法
[1]先调用startService方法开启服务 能够保证服务在后台长期运行
[2]调用bindService方法 去获取中间人对象
[3]调用unbindSerivce 解绑服务
[4]调用stopSerivce
9 百度音乐盒框架
package com.phone.baidumusic;import android.content.ComponentName;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.app.Activity;import android.view.View;public class MainActivity extends Activity {//中间人对象private IService iService;private MyConn conn;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//混合方式开启服务//[1]先调用startservice 目的是可以保证服务在后台长期运行Intent intent = new Intent(this, MusicService.class);startService(intent);//[2]调用bindservice 目的为了获取我们定义的中间人对象 就可以间接的调用服务里面的方法了conn = new MyConn();bindService(intent, conn, BIND_AUTO_CREATE);}@Overrideprotected void onDestroy() {//当Activity销毁的时候 解绑服务unbindService(conn);super.onDestroy();}//点击按钮 播放音乐public void click1(View v){iService.callPlayMusic();}//点击按钮 暂停音乐public void click2(View v){iService.callPauseMusic();}//点击按钮 继续播放音乐public void click3(View v){iService.callRePlayMusic();}//监听服务的状态private class MyConn implements ServiceConnection{@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {iService = (IService) service;}@Overridepublic void onServiceDisconnected(ComponentName name) {}}}
package com.phone.baidumusic;import android.app.Service;import android.content.Intent;import android.os.Binder;import android.os.IBinder;import android.view.View;public class MusicService extends Service {@Overridepublic IBinder onBind(Intent intent) {return new MyBinder();}@Overridepublic void onCreate() {super.onCreate();}@Overridepublic void onDestroy() {super.onDestroy();}// 播放音乐public void playMusic() {// TODO 等讲完多媒体 再完善该案例System.out.println("音乐播放了");}// 暂停音乐public void pauseMusic() {// TODO 等讲完多媒体 再完善该案例System.out.println("音乐暂停了");}// 继续播放音乐public void rePlayMusic() {// TODO 等讲完多媒体 再完善该案例System.out.println("音乐继续播放了");}// [1]在服务的内部定义一个中间对象(IBinder)private class MyBinder extends Binder implements IService{@Overridepublic void callPlayMusic() {playMusic();}@Overridepublic void callPauseMusic() {pauseMusic();}@Overridepublic void callRePlayMusic() {rePlayMusic();}}}
package com.phone.baidumusic;public interface IService {public void callPlayMusic();public void callPauseMusic();public void callRePlayMusic();}
<service android:name="com.phone.baidumusic.MusicService"></service>
10 aidl介绍
本地服务:运行自己应用里面的服务
远程服务:运行在其他应用里面的服务
实现进程间通信 IPC
aidl:Android Interface defined Language 安卓接口定义语言
专门是用来解决进程间通信的
总结:使用aidl的步骤
[1]把IService.java文件变成一个aidl文件
[2]adil这个语言不认识public 把public去掉
[3]自动生成一个IService.java文件 系统自动帮助我们生成一个类Stub(在gen目录下)
[4]我们自己定义的中间人对象直接继承Stub
[5]保证2应用的aidl文件是同一个 保证aidl文件所在的包名相同
[6]获取中间人对象的方式不一样了
IService = Stub.asInterface(service);
11 aidl的应用场景
比如 支付宝
只言片语任我说,提笔句句无需忖。落笔不知寄何人,唯有邀友共斟酌。
浙公网安备 33010602011771号