服务
长期后台运行,没有界面的组件,服务是运行在当前应用程序进程里面
如何创建一个服务
1,创建一个类继承Service
public class DemoService extends Service { }
2,在清单文件的application节点中进行配置,
<service android:name="com.servicedemo.DemoService" > </service>
如何开启和关闭服务
开启服务
Intent intent = new Intent(this,DemoService.class); startService(intent);
关闭服务
Intent intent = new Intent(this,DemoService.class); stopService(intent);
服务创建和销毁的生命周期方法
服务创建:onCreate
服务销毁:onDestroy
服务运行在那个线程
运行在主线程,不能执行耗时操作
进程的优先级
Foreground process
前台进程:用户正在操作的应用程序所在的进程就是前台进程
Visible process
可视进程:用户已经不能操作这个应用程序了,但是界面用户仍然可以看到
Service process
服务进程:应用程序有一个服务代码正在运行
Background process
后台进程:应用程序有界面,但是界面被用户最小化(点击home键),或者开启了另一个界面,当前界面不可见了
Empty process
空进程:应用程序没有任何运行的Activity、Service
前台进程 > 可视进程 > 服务进程 > 后台进程 > 空进程
为什么需要服务
当应用程序退出后,如果里面只有一个子线程,那么这个进程就会被当作一个空进程,优先级很低。当内存不足的时候,会被很快的被回收了
而如果开了一个服务的话,就算把程序退出了,那么这个进程也是一个服务进程,优先级中等,轻易不会被回收!即使被回收了,在内存充足的时候也会被重新开启
服务的生命周期
多次调用startService()的方式开启服务,服务只会被创建一次,在创建的时候执行onCreate()方法,一旦服务创建完毕,再去开启service就不会重复执行onCreate()方法了,只会执行onStart()和onStartCommand(); 调用stopService()停止服务,执行ondestroy()方法,服务只会被停止一次
通过什么方式来调用服务里的方法
Android中提供了调用服务里的方法的解决方案,就是要获取到服务的代理
1,服务通过onBind()方法返回代理,其返回值是一个IBinder的实现类
2,创建一个IBinder的实现类,IBinder是一个接口,实现该接口我们需要实现里面所有的方法,非常不方便,系统为我们提供了一个方便的实现类Binder,让该类继承Binder,我们就可以提供代理方法了
public class TestService extends Service {
@Override
//在服务成功绑定的时候,返回中间代理人
public IBinder onBind(Intent intent) {
return new MyBind();
}
//服务内部的代理人
class MyBind extends Binder {
//代理人帮忙调用服务内的方法
public void callrequestForService(String name, int money) {
if (money > 150) {
requestForService(name, money);
}else {
Toast.makeText(TestService.this, "对不起,请走合法程序", 0).show();
}
}
}
@Override
public void onCreate() {
System.out.println("服务创建了");
super.onCreate();
}
@Override
public void onDestroy() {
System.out.println("服务销毁了");
super.onDestroy();
}
public void requestForService(String name, int money) {
Toast.makeText(TestService.this, "证已办好,不用谢!!", 0).show();
}
}
3,绑定服务获得其代理,调用服务里的方法
public class MainActivity extends Activity {
private MyBind mybind;//代理人
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//布局里面设置的点击的方法
public void bind(View view){//绑定服务获取代理人
Intent service = new Intent(MainActivity.this,TestService.class);
//BIND_AUTO_CREATE,如果服务不存在,直接创建一个服务对象
bindService(service,new Myconn(), BIND_AUTO_CREATE);
}
public class Myconn implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mybind = (MyBind) service;//要获取的代理人
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
//布局里面设置的点击的方法
//通过中间人调用服务器的方法
public void call(View view){
mybind.callrequestForService("小明", 100);
}
}
绑定服务调用服务方法的步骤
1,编写服务代码
public IBinder onBind(Intent intent) {}
2,在服务内部定义一个代理人对象 MyBinder
代理人对象有一个方法可以间接的调用服务内部的方法
3,在onbind方法里面返回代理人对象
4,在Activity代码采用绑定的方式连接到服务
bindService(intent, new MyConn(), BIND_AUTO_CREATE);
5,在serviceConnection的实现类里面有一个方法,获取到服务返回的代理人对象
public void onServiceConnected(ComponentName name, IBinder service)
6,强制类型转换IBinder转化成 MyBinder类型
myBinder = (MyBinder) service;
7,调用代理人对象的方法–间接调用了服务里面的方法.
绑定方式开启服务的生命周期
1,绑定的方式开启服务:如果服务不存在,执行onCreate()—>onBind(),不会执行onStart()和onStartCommand()方法
2,解除绑定服务:会执行onUnbind()—>onDetroy()
3,多次绑定服务:服务只会被创建一次,onCreate()方法只会被执行一次,onBind()方法也只会执行一次
4,在实际开发的时候,如果需要调用服务的方法,就绑定服务,只能绑定一次。多次绑定会导致解绑时onUnbind()方法不会调用,并且第二次解绑会导致程序异常。
两种开启服务方式的比较
- start的方式开启服务
服务一旦开启,长期后台运行,服务和开启者(Activity)没有任何的关系,开启者退出了,服务还是继续在后台长期运行
开启者(Activity)不可以调用服务里面的方法
在系统设置界面里面可以观察到 - bind的方式开启服务
如果开启者(Activity)退出了,服务也会跟着挂掉
开启者(Activity)可以间接的利用中间人调用服务里面的方法
在系统设置界面看不到的.
服务如果被开启同时被绑定,服务就停不掉了,必须解除绑定服务才可以停止服务.
混合的方式开启服务.
为了保证服务又能长期后台运行,又能调用到服务里面的方法,采用混合的方式开启服务.
请严格按照以下步骤编写代码:
start的方式开启服务 (保证服务长期后台运行)
bind的方式绑定服务 (可调用服务的方法)
unbind的方式解除绑定服务
stop的方式停止服务
通过接口隐藏代码内部实现的细节
1,定义接口
public interface IService {
public void callrequestForService(String name, int money);
}
2,修改服务中内部类
//服务内部的代理人
private class MyBind extends Binder implements IService{
。。。。。。。。。。。。。。。。
}
学习一种代码的设计方式,如果一个内部类有多个方法,我只想暴露出其中的一部分方法时,可以通过接口将想要暴露的方法暴露出去。
如果将内部类设置为public,则所有方法都暴露出去了,如果将内部类设置为private,则所有方法其他人都不能调用了
具体实现方式:设置内部类为private的,将想要暴露出去的方法抽取到一个public的接口中
绑定远程服务调用服务方法的流程
- 服务提供者
跟本地服务的代码编写是一样
远程服务的接口定义文件,将.java的后缀名修改为 —> .aidl
把接口定义文件的访问修饰符全部删除,如public、private。系统会在gen文件夹下自动为我们生成.java文件
原来代理人MyBinder,由extend Binder implemet IService修改为 –> extends IService.Stub - 使用服务者
先把远程服务的.aidl文件拷贝到本地应用程序的工程目录里面,包名必须一致,系统会在gen文件夹下自动为我们生成.java文件
获取到代理的iBinder对象后,通过iService = IService.Stub.asInterface(service)得到远程服务的代理对象
通过代理对象调用远程服务的方法
远程服务
* BindService
public class BindService extends Service {
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
class MyBinder extends IService.Stub {
public void ServiceMetod(String name,int money){
requestSMethod(name);
}
}
@Override
public void onCreate() {
System.out.println("远程服务被创建了");
super.onCreate();
}
public void requestSMethod(String name){
System.out.println(name+".....我是远程方法,我被调用了");
System.out.println(Thread.currentThread().getName()+".....................................");
}
}
- 2,IService
interface IService {
void ServiceMetod(String name,int money);
}
3,目录结构
本地服务
1,调用远程服务
public class MainActivity extends Activity {
private Myconn myconn;
private IService iService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void bind(View view){
Intent intent = new Intent();
intent.setAction("com.test.remote.CALL");
myconn = new Myconn();
bindService(intent, myconn, BIND_AUTO_CREATE);
}
public class Myconn implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iService = IService.Stub .asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
public void callbind(View view){
try {
iService.ServiceMetod("哈啊", 100);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
- 2,IService
interface IService {
void ServiceMetod(String name,int money);
}
3,目录结构
系统服务了解
- 系统开启后,就会开启大量的常用服务,以后其他应用想使用系统服务的时候,可以通过context.getSystemService(String 服务名)方法获取到对应的系统服务
监听通话状态
1,获取系统服务,设置通话状态监听器
tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
listener = new MyPhoneListener();
tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
2,创建通话状态监听器
private class MyPhoneListener extends PhoneStateListener {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
// 空闲状态,代表当前没有电话
break;
case TelephonyManager.CALL_STATE_RINGING:
// 响铃状态 break; case TelephonyManager.CALL_STATE_OFFHOOK:
// 通话状态
break;
}
}
3,不使用的时候注销掉监听器,释放资源
tm.listen(listener, PhoneStateListener.LISTEN_NONE);
录音API
1,开始录音
mRecorder = new MediaRecorder();
//从麦克风录音,VOICE_CALL可录双向的,但是法律不允许
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
//输出格式
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
//文件存放位置
mRecorder.setOutputFile("/mnt/sdcard/"+SystemClock.uptimeMillis()+".3gp");
//音频编码方式
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
try {
mRecorder.prepare();
} catch (Exception e) {
System.out.println("prepare() failed");
}
mRecorder.start();
2,停止录音
mRecorder.stop(); mRecorder.release(); mRecorder = null;