android学习笔记五。1、Service深入学习
一、Service,服务是没有界面而在后台长期运行的程序,可以看做是后台的Activity。
1、在Android中按返回键退出一个应用并不会(内存充足时)直接销毁一个进程,所以其中的子线程也可以在后台运行,这种线程和服务的区别是优先级不同,如果内存不足,被销毁的顺序不同。而且即使服务所在进程被销毁,如果内存充足会自动重新运行。
作为Android四大组件之一,Service只要继承Service类,并在清单文件中配置即可使用。
!!!2、有两种方式开启Service,①使用startService();②使用bindService()。两者的区别在于
①前者创建一个服务之后,就与这个服务没有关联了,因为没有方法可以在获取这个服务的实例了。但是进行联系还需要复杂的操作,并且还要区分进程内绑定本地服务和进程外绑定远程服务
②通过绑定开启的service,一旦调用这个服务的activity被销毁则这个服务也被销毁。即服务不能长期存在。

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; public class MainActivity extends Activity {
private MyConn conn ;
private IMiddlePerson mp; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
} @Override
protected void onDestroy() {
System.out.println("啊啊啊,我是activity,我挂了");
super.onDestroy();
} //绑定服务
public void bind(View view){
//3.activity采用绑定的方式去开启服务。
//激活一个服务的意图
Intent intent = new Intent(this,MyService.class);
//保持联系的连接对象
conn = new MyConn();
bindService(intent, conn, BIND_AUTO_CREATE); }
//解除绑定服务
public void unbind(View view){
unbindService(conn);
} private class MyConn implements ServiceConnection{
//4. 当服务被连接的时候调用,服务被成功绑定的时候调用。IBinder就是绑定的Service的onBind()的返回值,
//!!!这就是联系所在
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
System.out.println("在activity里面成功得到了中间人");
mp = (IMiddlePerson) service;
}
//当服务失去连接的时候调用(一般进程挂了,服务被异常杀死)
@Override
public void onServiceDisconnected(ComponentName name) { }
} //调用服务里面的方法。
public void call(View view){
//5.通过中间人调用服务里面的方法。
mp.callMethodInService(55);
}
}
调用方
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.widget.Toast; public class MyService extends Service { //2.实现服务成功绑定的代码 ,返回一个中间人(一个符合IBinder要求的类,这里就是下面的内部类)。
@Override
public IBinder onBind(Intent arg0) {
System.out.println("服务被成功绑定了。。。。");
return new MiddlePerson();
} @Override
public boolean onUnbind(Intent intent) {
System.out.println("onunbind");
return super.onUnbind(intent);
} @Override
public void onCreate() {
System.out.println("oncreate");
super.onCreate();
} @Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("onstartcommand");
return super.onStartCommand(intent, flags, startId);
} @Override
public void onDestroy() {
System.out.println("ondestory");
super.onDestroy();
} /**
* 这是服务里面的一个方法
*/
public void methodInService(){
Toast.makeText(this, "哈哈,服务给你办好了暂住证。", 0).show();
} //1.第一步服务要暴露方法 必须要有一个中间人
private class MiddlePerson extends Binder implements IMiddlePerson{
/**
* 代办暂住证
* @param money 给钱 50块钱以上才给办。
*/
public void callMethodInService(int money){
if(money>=50){
methodInService();
}else{
Toast.makeText(getApplicationContext(), "多准备点钱。", 0).show();
}
}
/**
* 陪领导打麻将
*/
public void playMajiang(){
System.out.println("陪领导打麻将。");
}
}
}
service方
注意:上面的service方的中间人内部类是私有的,所以向外传递时不能直接将其抛出,所以在这里使用了一个接口作为中转,将需要暴露的方法通过接口暴露。
为了解决上面两种开启服务的缺点,可以使用混合的启动方式,即先startService()然后bindService(),此时关闭同样需要混合关闭。
参考:http://blog.csdn.net/ryantang03/article/details/7770939。
3、Service和Activity的异同点:
Service虽然叫服务,运行在后台,但是并不是新开了一个线程,而是依然运行在Activity的线程中,即UI线程中,所以如果在Service中执行耗时的操作,也会出现ANR异常。所以,Service和Activity一样,需要在子线程中进行耗时操作。
那Service和Activity的区别在哪里?为什么需要有Service呢?
这是因为Activity退出之后,其创建的子线程都会销毁,而Service可以继续运行在后台,而且通过绑定,当Activity再次启动时,可以获取一个Binder实例来获取后台运行数据。
4、其他类型的Service:
①前台Service:Service通常运行在后台,但是其优先级较低,在系统内存不足时可能会被回收。这时可以考虑使用前台Service来确保Service不会由于内存不足而回收。前台Service并没有什么特别的,只是在启动时需要创建一个notification在通知栏上进行显示。
Notification.Builder localBuilder = new Notification.Builder(this);
localBuilder.setContentIntent(PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0));
localBuilder.setAutoCancel(false);
localBuilder.setSmallIcon(R.drawable.pi);
localBuilder.setTicker("Foreground Service Start");
localBuilder.setContentTitle("Socket服务端");
localBuilder.setContentText("正在运行..."); //调用这一句开启前台服务
startForeground(1, localBuilder.getNotification());
前台Service
②IntentServvice:自动创建新消息线程HandlerThread的Service,将消息需要处理的数据通过Intent进行传递。具体的处理逻辑写在onHandleIntent()中,这是对外的接口。
public class TestService3 extends IntentService {
private final String TAG = "hehe";
//必须实现父类的构造方法
public TestService3()
{
super("TestService3");
}
//必须重写的核心方法
@Override
protected void onHandleIntent(Intent intent) {
//Intent是从Activity发过来的,携带识别参数,根据参数不同执行不同的任务
String action = intent.getExtras().getString("param");
if(action.equals("s1"))Log.i(TAG,"启动service1");
else if(action.equals("s2"))Log.i(TAG,"启动service2");
else if(action.equals("s3"))Log.i(TAG,"启动service3");
//让服务休眠2秒
try{
Thread.sleep(2000);
}catch(InterruptedException e){e.printStackTrace();}
}
//重写其他方法,用于查看方法的调用顺序
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG,"onBind");
return super.onBind(intent);
}
@Override
public void onCreate() {
Log.i(TAG,"onCreate");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG,"onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void setIntentRedelivery(boolean enabled) {
super.setIntentRedelivery(enabled);
Log.i(TAG,"setIntentRedelivery");
}
@Override
public void onDestroy() {
Log.i(TAG,"onDestroy");
super.onDestroy();
}
}
IntentService示例
这是android自带的一种对原始Service进行封装的类,直接使用的Service的优点是:
a、创建独立线程,可以直接安全的进行操作,而无需创建线程。线程使用的是HandlerThread,针对HandlerThread,IntentServvice内部实现了一个ServiceHandler类继承自Handler,将消息源与生成的子线程进行绑定。对此具体介绍见http://www.cnblogs.com/songfeilong2325/p/5412424.html。
b、在该消息处理完成之后,自动调用Service的stopSelf()将该Service进行销毁。
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
//调用这个方法处理消息,!!!所以这个方法是必须要继承实现
onHandleIntent((Intent)msg.obj);
//结束Service
stopSelf(msg.arg1);
}
}
ServiceHandler
③远程Service:就是在清单文件中<service>的android:process=":remote"进行设置,此时开启服务时就是在一个新的进程中。而此时使用start方式开启Service和原来一样,但是bind开启服务进行交互的方式需要改变,需要使用android的跨进程通讯机制。
a、使用Messenger:这是和Handler不同的进程间消息机制。同样使用Handler进行消息处理,但是使用Messenger来发送消息和获取Binder对象。
public class MessengerService extends Service {
/** Command to the service to display a message */
static final int MSG_SAY_HELLO = 1;
/**
* 通过handler处理消息
*/
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}
}
/**
*!!! 一个Messenger 对象,在Service端就是用于在onBind()中获取BInder对象
*/
final Messenger mMessenger = new Messenger(new IncomingHandler());
@Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
}
Service端
public class ActivityMessenger extends Activity {
/** Messenger for communicating with the service. */
Messenger mService = null;
boolean mBound;
/**
* 创建一个连接对象,用于和Service组件进行连接
*/
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// !!!在这里初始化Messenger对象,用于下面发送消息
mService = new Messenger(service);
mBound = true;
}
public void onServiceDisconnected(ComponentName className) {
mService = null;
mBound = false;
}
};
public void sayHello(View v) {
if (!mBound) return;
// Create and send a message to the service, using a supported 'what' value
Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
try {
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onStart() {
super.onStart();
// Bind to the service
bindService(new Intent(this, MessengerService.class), mConnection,
Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
}
调用端
b、使用AIDL方式:(Android Interface Definition Language)是Android接口定义语言的意思。使用了一个接口文件(类似.java文件但是以.aidl结尾)。关于AIDL的具体使用参考http://blog.csdn.net/lmj623565791/article/details/38461079,http://blog.csdn.net/guolin_blog/article/details/9797169
注意:使用Messenger的内部也是用AIDL的方式实现的,只是进行了简化。参考:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0723/3216.html
5、注意点:
①如果一个service没有绑定(bind),直接调用unBind()会报错,java.lang.IllegalArgumentException: Service not registered。
②绑定方式需要的ServiceConnection类需要实现两个,一个在Activity和service建立联系时调用,另一个在解除关联时调用。但是后者onServiceDisconnected方法在正常情况下是不被调用的,它的调用时机是当Service服务被异外销毁时,例如内存的资源不足时这个方法才被自动调用。
③为了确保安全,Service应该使用显示Intent来启动,而且只应该被自身应用启动,通过添加 android:exported 属性并将其设置为 "false",确保服务仅适用于您的应用。
6、深入探究---Binder机制
android学习笔记五。1、Service深入学习的更多相关文章
- Typescript 学习笔记五:类
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- Linux学习笔记(五) 账号管理
1.用户与组账号 用户账号:包括实际人员和逻辑性对象(例如应用程序执行特定工作的账号) 每一个用户账号包含一个唯一的用户 ID 和组 ID 标准用户是系统安装过程中自动创建的用户账号,其中除 root ...
- go微服务框架kratos学习笔记五(kratos 配置中心 paladin config sdk [断剑重铸之日,骑士归来之时])
目录 go微服务框架kratos学习笔记五(kratos 配置中心 paladin config sdk [断剑重铸之日,骑士归来之时]) 静态配置 flag注入 在线热加载配置 远程配置中心 go微 ...
- C#可扩展编程之MEF学习笔记(五):MEF高级进阶
好久没有写博客了,今天抽空继续写MEF系列的文章.有园友提出这种系列的文章要做个目录,看起来方便,所以就抽空做了一个,放到每篇文章的最后. 前面四篇讲了MEF的基础知识,学完了前四篇,MEF中比较常用 ...
- (转)Qt Model/View 学习笔记 (五)——View 类
Qt Model/View 学习笔记 (五) View 类 概念 在model/view架构中,view从model中获得数据项然后显示给用户.数据显示的方式不必与model提供的表示方式相同,可以与 ...
- java之jvm学习笔记五(实践写自己的类装载器)
java之jvm学习笔记五(实践写自己的类装载器) 课程源码:http://download.csdn.net/detail/yfqnihao/4866501 前面第三和第四节我们一直在强调一句话,类 ...
- Learning ROS for Robotics Programming Second Edition学习笔记(五) indigo computer vision
中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...
- ES6学习笔记<五> Module的操作——import、export、as
import export 这两个家伙对应的就是es6自己的 module功能. 我们之前写的Javascript一直都没有模块化的体系,无法将一个庞大的js工程拆分成一个个功能相对独立但相互依赖的小 ...
- muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor
目录 muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor Connector 系统函数connect 处理非阻塞connect的步骤: Connetor时序图 Accep ...
- python3.4学习笔记(五) IDLE显示行号问题,插件安装和其他开发工具介绍
python3.4学习笔记(五) IDLE显示行号问题,插件安装和其他开发工具介绍 IDLE默认不能显示行号,使用ALT+G 跳到对应行号,在右下角有显示光标所在行.列.pycharm免费社区版.Su ...
随机推荐
- 《剑指offer》二叉树的镜像
一.题目描述 操作给定的二叉树,将其变换为源二叉树的镜像. 二.输入描述 二叉树的镜像定义:源二叉树 8 / \ 6 10 / \ / \ 5 7 9 11 三.输出描述 镜像二叉树 8 / \ 10 ...
- sys.path
sys.path.append() 和 sys.path.insert() python程序中使用 import XXX 时,python解析器会在当前目录.已安装和第三方模块中搜索 xxx,如果都搜 ...
- nginx旧版本升级新版本
比如我们现在所用的是 nginx 是1.4 版本,过了一段时间后我们有新的稳定版 1.6 问世,我们想升级到新的版本怎么办? 1.把新版本解压.安装,然后将 sbin/ng ...
- 使用jemdoc制作个人主页
jemdoc官网说明: http://jemdoc.jaboc.net/index.html 作者的个人主页:https://jemnz.com/ 将下载的jemdoc.py文件和需要转化的xxx.j ...
- 【Round #36 (Div. 2 only) C】Socks Pairs
[题目链接]:https://csacademy.com/contest/round-36/task/socks-pairs/ [题意] 给你n种颜色的袜子,每种颜色颜色的袜子有ai只; 假设你在取袜 ...
- Java 学习(12):重写(Override)与重载(Overload) & 多态
目录 --- 重写 --- 重载 --- 多态 重写(Override) 重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变.即外壳不变,核心重写! 重写的好处在于子类可 ...
- MYSQL 更新时间自己主动同步与创建时间默认值共存问题
本文作者:苏生米沿 本文地址:http://blog.csdn.net/sushengmiyan/article/details/50326259 在使用SQL的时候,希望在更新数据的时候自己主动填充 ...
- JAVA 不同类载入器命名空间的理解
曾经一直有这样一个疑惑: 都说在JAVA中,由不同类载入器载入的类在虚拟机中位于不同的命名空间下,不同命名空间下的类相互不可见. 这让我产生了一个迷惑:假设有一个类A使用了ja ...
- android 2048游戏实现
android 的2048小游戏完整实现:GridLayout布局(android 4.0及以上). 曾经做过一个2048的算法题,学了几天android,认为能够实现个安卓版的.也就动手写了个. 包 ...
- IOS-7-纪念一下刚刚接到的第一份offer(下面是面试遇到的问题)
1.多线程技术 有四种开启线程的方式,基本的为:NSThread.NSOperation.GCD:还有一种已经老掉牙了.基于C语言.就不写了,基本不用. 样例:家在网络图片显示在手机界面上 第一步:代 ...