您的位置:首页 > 移动开发 > Android开发

Android 第八天_重置版_服务_注意事项

2016-03-28 15:05 471 查看
1 进程概念介绍
  四大组件都是运行在主线程 
  Android中的服务 也是在后台运行  可以理解成是在后台运行并且是没有界面的Activity

  (1)Foreground process 前台进程  用户正在交互  可以理解成相 当于 Activity执行onResume方法
  (2)Visible process 可视进程 用户没有在交互
但用户还一直能看得见页面 相当于Activity执行了onPause方法 
  (3)Service Process  服务进程  通过startService()开启了一个服务
  (4)Background process  后台进程
 当前用户看不见页面 相当于Activity执行了onStop方法
  (5)Empty process 空进程

_______________________

  start方式开启服务
  服务是在后台运行 可以理解成是没有界面的activity
  定义四大组件的方式都是一样的  

  1.定义一个类继承Service
   2.在清单文件中配置服务
  3.在activity中 开启服务
  


        onCreate:服务被创建的时候调用这个方法,记住只会被创建一次。除非服务被销毁;
        onStartCommand :开启服务的时候调用。
        onDestroy:销毁服务。


  特点:
  (1)服务通过startservice方式开启 第一次点击按钮开启服务 会执行服务的onCreate 和 onStartCommand方法
  (2)如果第二次开始在点击按钮开启服务 服务只会执行onStratCommand方法
  (3)服务被开启后 会在设置页面里面的 running里面找得到这个服务 
  ***(4)startservice 方式开启服务 服务就会在后台长期运行 直到用户手工停止 或者调用StopService方法 服务才会被销毁
 ____________________

 new Thread(){}.start();  服务有啥区别 ?
首先他们都是 后台运行,而且没有界面的。
但是 线程的应用程序如果退出了程序,那么他就是一个空进程,空进程就很容易被后台 杀死。
————————
电话监听:










注意一点setAudioSource(如果是MIC只能是单方的。所以我们应该要使用Voice_call两方的声音都可以录下来)

————————————————————
使用服务注册特殊的广播接收者:

特殊的广播接收者,比如锁屏。他不能在清单文件中注册,因为注册无效。
所以只能在activity中注册。

但是在activity中注册,不能后台运行,如果activity的页面关闭了,那么就会失效。

所以我们为了让他后台也能运行,如果我们可以使用服务去注册,因为服务的特点就是
可以再后台运行。

所以我们直接创建一个服务,然后在activity中跳转至服务,然后把代码在服务中实现即可,记得在清单为准

    (1)创建我们要注册的广播接收者 

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.itheima.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) {

return null;

}


//当服务第一次启动的时候调用

@Override

public void onCreate() {


//在这个方法里面注册广播接收者

//[1]获取ScreenReceiver实例

receiver = new ScreenReceiver();


//[2]创建IntentFilter对象

IntentFilter filter = new IntentFilter();

//[3]添加注册的事件

filter.addAction("android.intent.action.SCREEN_OFF");

filter.addAction("android.intent.action.SCREEN_ON");

//[4]通过代码的方式注册

registerReceiver(receiver, filter);


super.onCreate();

}


//当服务销毁的时候调用

@Override

public void onDestroy() {


//当actvivity销毁的时候  取消注册广播接收者 

unregisterReceiver(receiver);



super.onDestroy();

}


}


(3)一定要记得配置service

————————————————————
bind方式开启服务的生命周期:

#bind  Service 方式开启服务的特点 
 09-10 03:15:00.603: E/ActivityThread(11793): Activity com.itheima.service.MainActivity has leaked ServiceConnection com.itheima.service.MainActivity$MyConn@b6445bf8
that was originally bound here
09-10 03:15:00.603: E/ActivityThread(11793): android.app.ServiceConnectionLeaked: Activity com.itheima.service.MainActivity has leaked ServiceConnection com.itheima.service.MainActivity$MyConn@b6445bf8 that was originally
bound here
  
这个错误的问题在于没有在activity销毁的时候  销毁服务。

注意一点:我们一定要在activity销毁的时候 调用unbindservice方法。
不然有时候会报错。

  (1)当点击按钮第一次开启服务 会执行服务的onCreate方法 和 onBind()方法
   (2) 当我第二次点击按钮在调用bindservice  服务没有响应 
   **(3) 当activity销毁的时候服务也销毁  不求同时生但求同时死 
  (4)通过bind方式开启服务  服务不能再设置页面里面找到  相当于是一个隐形的服务
  (5)bindservice不能多次解绑 多次解绑会报错。你最后绑定的是哪一个对象,就是哪一个。
————————————————————

为什么要引入bindService:

目的为了调用服务里面的方法
因为你如果创建一个myservice去继承service,然后在清单文件中注册。然后在这个类中
写入一个自己的方法。
然后从activity 中用Start方式开始服务。然后new 一个myservice对象。
然后使用这个对象去调用方法。会报错。因为你这样new出来的对象没有上下文的环境。
会出现空指针异常。假设你使用吐司去输出的时候。

当然你也可以传递一个Context过去。

————————————————————

通过bindservice方式调用服务方法里面的过程:

注意一点,使用bind方式开启服务,他先运行oncrate 然后就会运行 onbind方法。












注意这里的中间人对象,是我们在activity中去创建bindservice方式开启服务的时候。
调用service里面的onbind方法返回的 IBinder类型的 对象。



——————————————————————————

通过接口方式调用服务里面的方法:




这里使用的是多态。不清楚可以看我的Java 回顾笔记——多态

我们首先创建一个接口类。
然后在接口类里面写上你要暴露给其他人的方法,不能写方法体。

然后我们在中间人对象(是一个内部类,我们可以把他私有)。
myBind extends Binder(实际上就是IBender接口的实现类) implments 接口
然后在里面写入 你要暴露的方法的 方法体。
这样我们就在onBind方法中返回一个 myBind的对象。
记住myBind 应该是私有内部类。(这样的好处在于,有一些方法不想暴露给别人)

然后我们在接收IBinder对象的时候 让他强转为 接口类型。(多态)

这样的好处就是我们 定义的内部类 可以私有化,这样我们可以把要暴露的方法,
放在接口中。通过接口去调用可以暴露的方法。
——————————————————————————————————

混合方式开启服务 
  (1)先调用startService()方法 保证服务在后台长期运行
  (2)调用bindservice()目的获取我们定义的中间人对象 调用服务里面的方法
  (3)unbindservice() 服务不会销毁
  (4)最后调用stopservice() 停止服务 

这个顺序是规定好的 不能改变。

——————————————

aidl介绍:

 (1)远程服务 :运行在其他应用里面的服务  
 
 (2)本地服务 :运行在自己应用里面的服务 

 (3)进行进程间通信  IPC 

 (4)aidl Android interface Defination Language Android接口定义语言 
     功能:专门是用来

解决进程间通信的 

————————————————————————————————

 aidl 实现步骤和之前调用服务里面的方法的区别 :
  为了实现两个应用程序之间的通讯,其实我们就是使用IPC 
  安卓中 就是使用aidl来实现IPC 

 第一步我们定义一个应用程序,这和上面的使用bindservice开启服务是一样的。

 然后我们继续定义另外一个应用程序,这一次我们使用 隐式意图 开启 服务,
 并设置 action。

然后我们在第一个应用里面的清单文件中 定义service ,并且给这个service 加入一个过滤器 过滤器写入前面定义的action 

 (1)先把Iservice.java文件变成aidl文件 
 (2)adil 不认识public 把public 给我去掉
 (3)会自动生成一个Stub类 实现ipc 
 (4)我们定义的中间人对象 直接继承stub
 (5)想要保证2个应用程序的aidl文件是同一个 要求aidl文件所在包名相同
 (6)获取中间人对象Stub.asinterface(Ibinder obj) 

——————————————————————

aidl的应用场景 :
 支付宝  非常有名 支付的方法  
 基本上是有名的 APP 你才敢去调用它的接口 。

——————————
小技巧:在注释的时候加上//TODO 可以在最右边出现一个标记,可以快速定位

 

注意一点:我们一定要在activity销毁的时候 调用unbindservice方法。
不然有时候会报错。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Android