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 {
// 当电话设置状态发生改变的时候调用
@Override
public 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() step
recorder.release(); // Now the object cannot be reused
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK:// 接听状态
System.out.println("开始录音");
recorder.start(); // Recording is now started
break;
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 block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.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 {
@Override
public 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"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android: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 {
@Override
public 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;
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
//[1]创建ScreenReceiver实例
receiver = new ScreenReceiver();
//[2]获取IntentFilter 实例 目的是添加action
IntentFilter filter = new IntentFilter();
//[3]动态添加action
filter.addAction("android.intent.action.SCREEN_OFF");
filter.addAction("android.intent.action.SCREEN_ON");
//[4]注册服务
registerReceiver(receiver, filter);
super.onCreate();
}
@Override
public 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 {
@Override
protected 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 {
//把定义的中间人对象返回
@Override
public 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;//定义的中间人对象
@Override
protected 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{
//当服务连接成功调用
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder = (MyBinder) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
@Override
protected 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;
@Override
protected 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);
}
@Override
protected 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{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iService = (IService) service;
}
@Override
public 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 {
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public 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{
@Override
public void callPlayMusic() {
playMusic();
}
@Override
public void callPauseMusic() {
pauseMusic();
}
@Override
public 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的应用场景
比如 支付宝
只言片语任我说,提笔句句无需忖。落笔不知寄何人,唯有邀友共斟酌。