起名Android组件系列—-Android Service组件深入剖析

  【声明】 

11

欢迎转载,但要保留文章原来出处→_→ 

恨一些口,一些从,甚至恨着这个世界 ,总是在怀念,为什么是自我,为什么承受整个痛苦之还必须是本人,我只想做一个惯常的娃子,开心读书,找工作,恋爱,和你并了平淡的在……可是,这么普通的周,对于自,却这样的不便……总感到冷似乎产生同一双双眼睛,带在揶揄的笑意看正在,
然后,摇摇头,走开了…… ”

生壹号:http://www.cnblogs.com/smyhvae/

       
开学,绪有矣女性对象。经常约会,偶尔逃课,或者夜不归宿。我们打趣,小子不要堕落于温和乡里!寝室的兄弟凑份子,在山脚的夜市吃烧烤、喝啤酒,打桌球。算是拜这小子嫁出去了。她的女性对象是系里的学妹,娴静的江南妇女,温文尔雅。绪对我们的敬酒啊是热忱。他拿稍女友紧紧地保护在身后,如母鸡照顾小鸡一样,不让半碰于惊吓之机,惹得寝室其他几单只有眼馋的客。只有当酒桌达展现高低了。
 

文章来源:http://www.cnblogs.com/smyhvae/p/4070518.html

        临近毕业,毕业论文、答辩,忙在摸工作,一切一切,都过得极度抢。   

 

       
做论文,面对正在计算机发呆,却敲不来一个许来,身边的咖啡已日趋发凉,耳机里连连出圆润的音乐声,抽一支付支烟,烟蒂堆满了烟灰缸。此时,已是黎明,你啊非知道凡是啊时候成为这样的,像穴居动物一般。绪进来,喝杯水,进了浴场,又闻他当澡堂歌唱。出来,四处搜寻烟,点及,倚在自我的计算机桌旁,看我愣的则:“去天台清醒清醒。”

【前言】

       
我失去洗手间洗把脸,拿烟和他上了天台。凌晨隔三差五之宁静,被冷空气包裹,有风掠过,有些冷。远处的晨光,透着天涯一点点亮色,路灯都经息了,可以瞥见水泥丛林狰狞的脸面。

费了周末简单上的岁月,整理了一晃用作Android四大组件有的Service的基础知识,通过这篇稿子,应该可以知道:对Service的喻、在啊地方采取、怎么利用、要注意什么问题相当。

       
两口背在风点在刺激,静默无语。我看无展现他的颜,只烟头的光辉在广阔的夜光中一样闪一扭。绪像是从来不说话找话,又比如说喃喃自语,“这么快就毕业了呀!……”

【本文主要内容】

        “额……”

如出一辙、Service的基本概念(四老大组件有)
二、定义(启动)一个Service

       “毕业有什么打算?”

  • 1、如何定义(启动)一个Service:
  • 2、停止一个started服务来少栽办法
  • 3、onStartCommand方法的返回值

       
学校时之优质和向往早就在酒精和网的浸淫里易得模糊不清而可笑。面对现实,工作,上班,周而复始。在一个地方要得最为遥远,慵懒而麻木,离开的想法有点不正边际。

三、IntentService

       
“最近无见绮茗?”绪背靠护栏,仰头吐个眼圈。忽然想起是殊长远无呈现了绮茗了。“绮茗是只大好的女孩……就从未有过想过跟它们以一块儿?她爱而……”

  • 1、IntentService的引入
  • 2、IntentService的作用
  • 3、IntentService的用法
  • 4、Service和Thread的关系

       
凌晨底氛围有硌冷,有风吹了,我不由得缩缩脖子,后悔没有带来外套上来。抽太多烟,嗓子好苦。

季、使用Bind Service完成Service和Activity之间的通信

       
他卡掉烟蒂,用揶揄的弦外之音晒笑,“怎么?还以坚持不懈而心灵深处那片爱情净土呀…….等您的子若?”

  • 1、Bind Service的介绍
  • 2、实现Service和Activity之间通信步骤
  • 3、started服务同bind服务的别
  • 4、Service的生命周期

       
入晚,还窝在叫卷里。收到绮茗短信:“我保证丢了,接自己,海边……”于是打车出门,过去以提心吊胆她饿在,买了蛋糕和酸奶。

五、使用Bind Service完成IPC进程中通信:(在与一个APP内拟)

       
阴云密布的晚,天是焦黑的,海是黑的,水天一色,黑喷漆漆的同一切片,凝结在海面上。狂风骤起,海浪呼啸,惊涛拍岸,像大的黑色怪兽,咆哮扑来,要吞没海中之满,也如抢占岸上的浑。巨浪在征服的大洋之后,到达对岸逐渐筋疲力尽,最后用老全力,扑倒在海滩上。望眼过去那么开阔无边的海洋,雄浑而广大,把城市之狭小、拥挤、嘈杂全都淹没在冰冷苍凉里。

  • 1、Bind Service的介绍
  • 2、在客户端绑定一个服务之步子
  • 3、IPC(Inter-Process Communication)进程之中通信机制
  • 4、AIDL(Android Interface Definition Language)Android接口定义语言
  • 5、IPC(进程之中通讯)具体的步子如下
  • 6、让Activity与一个长途Service建立涉的步骤:(在同一个APP内拟)
  • 7、AIDL支持的自定义数据类型

       
夜晚底海边,游人都早就散去,带走了白天之鼓噪繁杂,寥落的海滩愈发苍凉。绮茗一个总人口于沙滩,依稀中海边那个相同曳长裙的孤独女孩,柔弱得叫人可惜。我在它底身旁坐下来。她正在哭泣,我默然无语,不理解怎么劝其。我摸摸口袋,没有拉动烟。

六、使用Bind Service完成IPC进程之中通信:(两独APP之间)
七、Messenger的使用

        “冷……能抱抱我么?”

 

       
我轻轻地拥她以怀里,心里的痛犹如海水般蔓延起来来,无边无际,一点点碰上着内心防线,有种植窒息的痛感,我闭上眼去,夜晚底海滩,远处的都,叶树婆娑、点点渔火,还有头发清香的气味,萦绕在方圆,一切还早已隐隐错位。

【正文】

        毕业,我及绮茗同在了。

同等、Service的基本概念(四百般组件有)

       
绮茗不予以粉黛,整天穿在睡衣,光着脚丫在屋子里晃荡。她聊现出的肚腩,和坐内分泌失调冒出的好多痘痘,总让它好窝火。

Service是Android中贯彻程序后台运行的缓解方案,非常适合用于去实施怎样不欲跟用户交互而且还求老运行的任务。不可知运行在一个独的进程中,而是因与创建服务时所当的应用程序进程。只能在后台运行,并且可同其他零件进行互。

       
绮茗是单善良的子女。她会见以街边的同修流浪狗停下脚步,也会见为了桥头的无业游民频频回头;她见面因送她小物乐不可支,也会见以电视剧的始末泪眼婆娑……每天晚上也会吵架着让其谈故事,早晨距的早晚,会露出个稍头:“哥哥,什么时回来呀?陪绮茗玩…..”每天下楼,总会相它在平台之身形。她吧会见当转悠街之时节不留意说有同样句:“哥哥好帅呀!”俨然是友善的微福……

Service可以于诸多场地以,比如播放多媒体的时段用户启动了其余Activity,此时如果在后台继续播放;比如检测SD卡上文件之扭转;比如以后台记录你的地理信息位置的变更等等,总之服务是整存在后台的。

       
朋友回家,寄养了只稍狗。我于是纸箱带它回家,它当纸箱里瞪大了眼球盯在本人同样动不动。我们给它从名叫皮皮。皮皮刚生月余,还聊会走路,总是磕磕绊绊着缓慢倒,不深受祥和摔倒。

劳不见面自动开线程,我们用在服务之内手动创建子线程,并在此地实行实际的职责。关于多线程的知:可以参照另外一首文章:Android多线程—-异步消息处理体制的Handler详解

       
它因此墨的眼球四处打量着陌生的条件。每天的功课虽是困、吃饭。绮茗待其跟小孩一样,给它洗澡,梳理毛发,它总挣扎着想逃离,轻声呜咽。

 

       
等耳熟能详了,它四处乱窜,把她由以为好的东西作为敌人,并轮奸一番,迅速忽视。它来协调的如出一辙片领地,把她的玩意儿,骨头都搬至的床铺底下,还有珍贵的鞋子。

二、定义(启动)一个Service:

       
每次上班,它连接迫不及待在由门缝里挤下,一下跑得那个远,回头等你。可怜之粗家一道,在爱妻闷得太老,期待异地的风光。

1、如何定义(启动)一个Service:

       
皮皮长得好快。胖乎乎的血肉之躯调皮而出狡黠,它掌握乃呀时火,什么时候喜欢。它吗会玩得记不清了时还是藏起来给你摸不至它们。皮皮初时常不见面被,每天在家听到绮茗“汪汪”学狗吃。初时她不见面达成生楼梯,总是徘徊这不乐意迈出脚来。每次上下楼都是绮茗手把手扶在她上来下去。

着力步骤如下:

       
周末,绪和女友回复,一起进餐,然后带皮皮去海边散步。可爱之微家并很讲究好少的散步时,奔跑、和其他比其个头非常群的同类嬉戏。

  • 创立一个类继承android.app.Service类,实现抽象方法onBind(),重写onCreate()、onStartCommand()、onDestry();
  • 当清单文件中配备Service。

       
“我无欣赏欢绪的女朋友……因为其免希罕皮皮……”孩子样的绮茗站在狗的角度审视着周围的方方面面,并论好的好恶。

新建一个Android项目ServiceTest,具体步骤如下:

       
还受每户的生活里,绮茗总是以夜间哭着清醒过来:“哥哥,我思念皮皮了!”我搂在绮茗在怀里,惹人犹怜。没有皮皮的小日子,生活中凡遗失了若干什么事物。

(1)新建一个MyService类,继承自Service,并重新写父类的onCreate()、onStartCommand()和onDestroy()方法,代码如下:

       
皮皮丢了凡好老后的事情,朋友打电话过来,告诉自己皮皮丢了。绮茗为之哭了长久,逛街之早晚遇到别的小狗,她会流连好老,“皮皮饿了怎么处置?会无会见为人家虐待。”

 1 package com.example.servicetest;
 2 
 3 import android.app.Service;
 4 import android.content.Intent;
 5 import android.os.IBinder;
 6 import android.util.Log;
 7 
 8 public class MyService extends Service {  
 9       
10     public static final String TAG = "MyService";  
11   
12     //创建服务时调用
13     @Override  
14     public void onCreate() {  
15         super.onCreate();  
16         Log.d(TAG, "onCreate");  
17     }  
18   
19     //服务执行的操作
20     @Override  
21     public int onStartCommand(Intent intent, int flags, int startId) {  
22         Log.d(TAG, "onStartCommand");  
23         return super.onStartCommand(intent, flags, startId);  
24     }  
25       
26     //销毁服务时调用
27     @Override  
28     public void onDestroy() {  
29         super.onDestroy();  
30         Log.d(TAG, "onDestroy");  
31     }  
32   
33     @Override  
34     public IBinder onBind(Intent intent) {  
35         return null;  
36     }  
37 }

       
看在绮茗伤心,就象是自己之儿童丢了相同,看皮皮调皮的相片,睡觉的、吃食的、奔跑的、嬉戏的……一全套一律全套,心里有点点沉重,她是暨皮皮同孤独的幼儿呀!

好看看,我们只是在onCreate()、onStartCommand()和onDestroy()方法吃分别打印了千篇一律词话,并没展开任何任何的操作,注意代码注释中马上三单点子的图。

onBind()方法是Service中绝无仅有的一个架空方法,所以必须要以子类里心想事成。我们知晓,Service可以有些许栽启动方式:一种植是startService(),另一样种是bindService()。第二种启动方式才会就此到onBind()方法。我们当下先用第一种办法启动Service,所以临时忽略onBind()方法。

(2)在清单文件中宣示:(和Activity标签并列)

 <service android:name=".MyService">        </service>

(3)修改activity_main.xml代码,如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:orientation="vertical" >  

    <Button  
        android:id="@+id/button1_start_service"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:text="Start Service" />  

    <Button  
        android:id="@+id/button2_stop_service"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:text="Stop Service" />  

</LinearLayout> 

咱在布局文件被进入了一定量只按钮,一个用于启动Service,一个用来停止Service。

(4)在MainActivity作为次的主Activity,在里在启动Service和平息Service的逻辑,代码如下:

 1 package com.example.servicetest;
 2 
 3 import android.app.Activity;
 4 import android.content.Intent;
 5 import android.os.Bundle;
 6 import android.view.View;
 7 import android.view.View.OnClickListener;
 8 import android.widget.Button;
 9 
10 
11 public class MainActivity extends Activity implements OnClickListener {  
12       
13     private Button button1_start_service;  
14   
15     private Button button2_stop_service;  
16   
17     @Override  
18     protected void onCreate(Bundle savedInstanceState) {  
19         super.onCreate(savedInstanceState);  
20         setContentView(R.layout.activity_main);  
21         button1_start_service = (Button) findViewById(R.id.button1_start_service);  
22         button2_stop_service = (Button) findViewById(R.id.button2_stop_service);  
23         button1_start_service.setOnClickListener(this);  
24         button2_stop_service.setOnClickListener(this);  
25     }  
26   
27     @Override  
28     public void onClick(View v) {  
29         switch (v.getId()) {  
30         case R.id.button1_start_service:  
31             Intent startIntent = new Intent(this, MyService.class);  
32             startService(startIntent);  
33             break;  
34         case R.id.button2_stop_service:  
35             Intent stopIntent = new Intent(this, MyService.class);  
36             stopService(stopIntent);  
37             break;  
38         default:  
39             break;  
40         }  
41     }  
42   
43 }

基本代码:31实行至32实行、35实行及36推行。

足见到,在Start
Service按钮的点击事件里,我们构建起了一个Intent对象,并调用startService()方法来启动MyService。然后以Stop
Serivce按钮的点击事件里,我们同构建起了一个Intent对象,并调用stopService()方法来歇MyService。代码的逻辑非常简单。

这样的话,一个简便的蕴藏Service功能的先后就算形容好了。

启航与停止服务:

概念好服务后,接下看一下哪些启动与住一个劳务,这第一是依赖Intent来实现的。注意startService()和stopService()方法都是概念在Context类当中的,所以可以以MainActivity中一直调用眼看点儿单主意。

运作方面的顺序,点击button1_start_service按钮,启动服务,后台打印日志如下:

起名 1

证服务启动成功。

那么要自身又连接点三浅button1_start_service按钮,后台增加的日志如下:

起名 2

事实上,onCreate()方法只有见面当Service第一潮为创造的时光调用,而onStartCommand()方法在每次启动服务的时都见面调用

俺们还好以方“设置–应用—运行”中找到这个服务,如下图所示:

起名 3

接触起来及图中的红框部分,可以观看:

起名 4

假如我们还点击button2_stop_service按钮或者点击上图中的“Stop”,MyService服务就是歇掉了:

起名 5

消专注的凡:

  • 劳动对象又就会发一个
  • 默认情况下,一个started的Service与开行他的零件在同一个线程中。上面的实例中,服务就是以主线程遭遇运行的,如果是于服务被就耗时操作的话,容易造成主线程阻塞。

2、停止一个started服务有一定量种方法:

(1)在外表使用stopService()

(2)在服务之中(onStartCommand方法中)使用stopSelf()方法。

3、onStartCommand方法的返回值:

onStartCommand方法执行时,返回的凡一个int型。这个整型可以有三只返回值:START_NOT_STICKY、START_STICKY、START_REDELIVER_INTENT

  • START_NOT_STICKY:“非粘性的”。使用这个返回值经常,如果当推行完onStartCommand方法后,服务为那个kill掉,系统非会见活动重新开该服务。
  • START_STICKY:如果Service进程被kill掉,保留Service的状态呢发端状态,但非保留递送的intent对象。随后系统会尝试再次创设Service,由于服务状态也初步状态,所以创建服务后定会调用onStartCommand(Intent,int,int)方法。如果在这期间从未其他启动命令于传送至Service,那么参数Intent将为null。
  • START_REDELIVER_INTENT:重传Intent。使用此返回值经常,系统会活动重新开该服务,并以Intent的价值传入。

 

三、IntentService

1、IntentService的引入:

我们以首先段子受到虽曾说了,服务遭遇的代码默认运行于主线程中,如果直接在劳动里实施有耗时操作,容易招ANR(Application
Not Responding)异常,所以即便需要为此到大半线程的知了。

因此一个较规范的劳务可如此形容

 1 package com.example.servicetest;
 2 
 3 import android.app.Service;
 4 import android.content.Intent;
 5 import android.os.IBinder;
 6 
 7 public class MyService extends Service {  
 8       
 9     public static final String TAG = "MyService";   
10   
11     //服务执行的操作
12     @Override  
13     public int onStartCommand(Intent intent, int flags, int startId) {  
14         new Thread(new Runnable() {
15             public void run() {
16                 //处理具体的逻辑
17                 stopSelf();  //服务执行完毕后自动停止
18             }
19         }).start();        
20         return super.onStartCommand(intent, flags, startId);  
21     }
22 
23     @Override
24     public IBinder onBind(Intent intent) {
25         // TODO Auto-generated method stub
26         return null;
27     }      
28  
29 }

基本代码:14届19实施,在子线程中处理具体的逻辑。

欲注意的是,如果无第17行的stopSelf(),服务如启动后,就会见一直处在运行状态,必须调用stopService()或者stopSelf()方法才会被服务停止下来;所以我们补充加了17实践的stopSelf(),服务推行完毕后会活动终止

则上面的这种写法并无复杂,但总会发生一对先后猿忘记打开线程,或者忘记调用stopSelf()方法。为了可省略地创造一个异步的、会自行终止的劳动,Android专门供了一个IntentService类,这个仿佛就异常好的缓解了方所涉的个别种植骑虎难下。另外,可以启动IntentService多次,而各个一个耗时操作会以干活排的法在IntentService的onHandleIntent()回调方法吃实行,并且每次只有会履行一个做事线程,执行完毕第一单后,再履行第二只,以此类推。

2、IntentService的作用:

当我们得如此一次性就的职责时,就可以使用IntentService来成功。

3、IntentService的用法:

咱们当地方的色ServiceTest基础上展开改动,步骤如下:

(1)新建一个MyIntentService类,继承自IntentService,并重新写父类的onHandleIntent()方法,代码如下:

 1 package com.example.servicetest;
 2 
 3 import android.app.IntentService;
 4 import android.content.Intent;
 5 import android.util.Log;
 6 
 7 public class MyIntentService extends IntentService{
 8 
 9     public MyIntentService() {
10         super("MyIntentService");//调用父类有参构造函数。这里我们手动给服务起个名字为:MyIntentService
11         // TODO Auto-generated constructor stub
12     }
13 
14     //该方法在会在一个单独的线程中执行,来完成工作任务。任务结束后,该Service自动停止
15     @Override
16     protected void onHandleIntent(Intent intent) {
17         // TODO Auto-generated method stub
18         for(int i = 0;i<3;i++) {
19             //打印当前线程的id
20             Log.d("MyIntentService","IntentService线程的id是:"+Thread.currentThread().getId());
21             try {
22                 Thread.sleep(1000);
23             } catch (InterruptedException e) {
24                 // TODO Auto-generated catch block
25                 e.printStackTrace();
26             }
27         }        
28     }
29 
30     @Override
31     public void onDestroy() {
32         // TODO Auto-generated method stub
33         super.onDestroy();
34         Log.d("MyIntentService","onDestroy");
35     }
36 }

此间首先使供一个无参的构造方法,并且要于其里面调用父类的有参构造方法(9暨12履行),我们在第10履行手动将服务之名改成呢“MyIntentService”。

接下来于子类中贯彻onHandleIntent()这个抽象方法,可以于此措施里去处理部分实际的逻辑,我们虽因故三差for循环,打印当前线程的id,每次延时1秒。

坐此服务以运作了晚会自行停止,所以我们于onDestroy()方法被打印日志验证一下。

(2)在清单文件中对服务开展注册服务:

<service android:name=".MyIntentService"> </service>

(3)在activity_main.xml中上加一个按钮button3_stop_intentservice,用于启动MyIntentService服务,代码略。

(4)在MainActivity其中在启动IntentService的逻辑,核心代码如下:

1       case R.id.button3_stop_intentservice:
2             Log.d("MainActivity","主线程的id是:"+Thread.currentThread().getId());
3             Intent intentService = new Intent(this,MyIntentService.class);
4             startService(intentService);
5         default:

咱俩当第02行饱受,打印主线程的id。

运转程序,点击按钮button3_stop_intentservice,显示如下:

起名 6

由此可见,启动一个IntentService和开行一个常备的Service,步骤是一样的。

4、Service和Thread的关系:

无数Android初家都或会见产生这般的迷离,Service和Thread到底发生啊关系为?什么时候理应据此Service,什么时还要该为此Thread?答案可能会见起硌被你吃惊,因为Service和Thread之间从来不其它关系!

因而产生众多人口见面把它联系起来,主要就是以Service的后台概念。Thread我们大家还晓得,是用以开启一个子线程,在此失去履行有耗时操作就非会见堵塞主线程的运行。而Service我们最初知道的早晚,总会看它是因此来拍卖部分后台任务的,一些比较耗时的操作也可在这里运行,这就算会见受人产生模糊了。但是,如果自己报你Service其实是运作于主线程里的,你还会见认为她与Thread有啊关系也?

实际上,后台和子线程是片只了两样之概念:

Android的后台就是靠,它的运转是了不依赖UI的。即使Activity被销毁,或者程序让关门,只要经过还当,Service就好继承运行。比如说有应用程序,始终要以及服务器之间始终维持正心跳连接,就可以应用Service来实现。你或许而会问,Service既然是运行于主线程里,在此间一直施行方心跳连接,难道就是不见面堵塞主线程的运行也?当然会,但是我们可以以Service中重复创一个子线程,然后以此地失去处理耗时逻辑就是没有问题了。

既然在Service里也如创建一个子线程,那干什么未直接在Activity里创建为?这是坐Activity很麻烦对Thread进行支配,当Activity被灭绝后,就从未另外其它的法子可以还重复得到到前创建的子线程的实例;而且以一个Activity中开创的子线程,另一个Activity无法对那进展操作。但是Service就不同了,所有的Activity都得跟Service进行关联,然后可以十分便宜地操作间的法,即使Activity被灭绝了,之后如果再和Service建立关系,就又能拿走到旧的Service中Binder的实例。因此,使用Service来处理后台任务,Activity就可放心地finish,完全无需操心无法对后台任务进行支配的景况。

故说,一个较规范的Service,就好形容成本段中第1节约之师。

 

季、使用Bind Service完成Service和Activity之间的通信

发无来什么措施能够于它们俩底关系更多有吗?比如说在Activity中挥Service去干啊,Service就错过干啊。当然可以,只需要让Activity和Service建立关系就吓了。

1、Bind Service的介绍:

应用程序组件(客户端)通过调用bindService()方法能绑定服务,然后Android系统会调用服务的onBind()回调方法,则只方法会返回一个跟服务器端交互的Binder对象。

本条绑定是异步的,bindService()方法就回去,并且不为客户端返回IBinder对象。要接到IBinder对象,客户端必须创造一个ServiceConnection类的实例,并且将此实例传递给bindService()方法。ServiceConnection对象涵盖了一个网调用的传递IBinder对象的回调方法。

注意:只有Activity、Service、Content
Provider能够绑定服务;BroadcastReceiver广播接收器不可知绑定服务。

2、实现Service和Activity之间通信步骤:

俺们照例以其次段子被之门类ServiceTest基础上进行修改。

观察地方第二段子中MyService中之代码,你晤面发现直接发一个onBind()方法我们且未曾利用到,这个点子其实就算是用来与Activity建立关系的,修改MyService中的代码,如下所示:

 1 package com.example.servicetest;
 2 
 3 import android.app.Service;
 4 import android.content.Intent;
 5 import android.os.Binder;
 6 import android.os.IBinder;
 7 import android.util.Log;
 8 
 9 public class MyService extends Service {  
10       
11     public static final String TAG = "MyService";  
12   
13     private MyBinder mBinder = new MyBinder();  
14   
15     @Override  
16     public void onCreate() {  
17         super.onCreate();  
18         Log.d(TAG, "onCreate");  
19     }  
20   
21     @Override  
22     public int onStartCommand(Intent intent, int flags, int startId) {  
23         Log.d(TAG, "onStartCommand");  
24         return super.onStartCommand(intent, flags, startId);  
25     }  
26   
27     @Override  
28     public void onDestroy() {  
29         super.onDestroy();  
30         Log.d(TAG, "onDestroy");  
31     }  
32   
33     @Override  
34     public IBinder onBind(Intent intent) {  
35         return mBinder;  //在这里返回新建的MyBinder类
36     }  
37   
38     //MyBinder类,继承Binder:让里面的方法执行下载任务,并获取下载进度
39     class MyBinder extends Binder {  
40   
41         public void startDownload() {  
42             Log.d("TAG", "startDownload() executed");  
43             // 执行具体的下载任务  
44         }
45         public int getProgress(){
46             Log.d("TAG", "getProgress() executed");  
47             return 0;
48         }
49   
50     }  
51   
52 }  

38至50推行:新建一个MyBinder类,继承Binder:让其中的不二法门执行下载任务,并获得下充斥进度。当然,这里才是少单拟方法,并无落实真正的效用,我们透过打印日志的款型来反映。

进而创建MyBinder的实例(13推行),然后于onBind()方法里返回这个实例(35执行)。

着力代码凡35履,返回这个mBinder,是一个IBinder类型,就好把这IBinder类型传递至MainActivity中,从而调用Service里面的方式。下面将扣押同样拘禁,在MainActivity是如何调用Service里面的个别单办法的。

(2)检查清单文件,是否业已针对性Service进行注册:

<service android:name=".MyService" > </service> 

(3)在activity_main.xml中继续补加少单按钮button3_bind_service和button4_unbind_service,用于绑定服务与撤回绑定服务。最终,activity_main.xml的完整代码如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/button1_start_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start Service" />

    <Button
        android:id="@+id/button2_stop_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Stop Service" />

    <Button
        android:id="@+id/button3_bind_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="bind Service" />

    <Button
        android:id="@+id/button4_unbind_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="unbind Service" />

</LinearLayout> 

(4)接下还修改MainActivity中的代码,让MainActivity和MyService之间成立关系,代码如下所示:

 1 package com.example.servicetest;
 2 
 3 import android.app.Activity;
 4 import android.content.ComponentName;
 5 import android.content.Intent;
 6 import android.content.ServiceConnection;
 7 import android.os.Bundle;
 8 import android.os.IBinder;
 9 import android.util.Log;
10 import android.view.View;
11 import android.view.View.OnClickListener;
12 import android.widget.Button;
13 
14 public class MainActivity extends Activity implements OnClickListener {
15 
16     private Button button1_start_service;
17     private Button button2_stop_service;
18     private Button button3_bind_service;
19     private Button button4_unbind_service;
20 
21     private MyService.MyBinder myBinder;
22     
23     //匿名内部类:服务连接对象
24     private ServiceConnection connection = new ServiceConnection() {
25         
26         //当服务异常终止时会调用。注意,解除绑定服务时不会调用
27         @Override
28         public void onServiceDisconnected(ComponentName name) {
29         }
30         
31         //和服务绑定成功后,服务会回调该方法
32         @Override
33         public void onServiceConnected(ComponentName name, IBinder service) {
34             myBinder = (MyService.MyBinder) service;
35             //在Activity中调用Service里面的方法
36             myBinder.startDownload();
37             myBinder.getProgress();
38         }
39     };
40 
41     @Override
42     protected void onCreate(Bundle savedInstanceState) {
43         super.onCreate(savedInstanceState);
44         setContentView(R.layout.activity_main);
45         button1_start_service = (Button) findViewById(R.id.button1_start_service);
46         button2_stop_service = (Button) findViewById(R.id.button2_stop_service);
47         button3_bind_service = (Button) findViewById(R.id.button3_bind_service);
48         button4_unbind_service = (Button) findViewById(R.id.button4_unbind_service);
49 
50         button1_start_service.setOnClickListener(this);
51         button2_stop_service.setOnClickListener(this);
52         button3_bind_service.setOnClickListener(this);
53         button4_unbind_service.setOnClickListener(this);
54     }
55 
56     @Override
57     public void onClick(View v) {
58         switch (v.getId()) {
59         case R.id.button1_start_service:
60             Intent startIntent = new Intent(this, MyService.class);
61             startService(startIntent);
62             break;
63         case R.id.button2_stop_service:
64             Intent stopIntent = new Intent(this, MyService.class);
65             stopService(stopIntent);
66             break;
67         case R.id.button3_bind_service:
68             Intent bindIntent = new Intent(this, MyService.class);
69             bindService(bindIntent, connection, BIND_AUTO_CREATE);
70             break;
71         case R.id.button4_unbind_service:
72             unbindService(connection);
73             break;
74 
75         default:
76             break;
77         }
78     }
79 
80 }

得看到,这里我们先是创建了一个ServiceConnection的匿名类(24尽),在中间又写了onServiceConnected()方法及onServiceDisconnected()方法,如果手上Activity与劳动连接成后,服务会磨调onServiceConnected()方法,

于onServiceConnected()方法吃,我们又经过奔下转型取得了MyBinder的实例(34行),有了这个实例,Activity和Service之间的关联就变换得那个严谨了。现在我们好以Activity中冲实际的状况来调用MyBinder中之另外public方法(36、37行),即实现了Activity指挥Service干什么Service就去干啊的机能。

理所当然,现在Activity和Service其实还无干起来了呢,这个职能是当Bind
Service按钮的点击事件里好的。可以看到,这里我们还是是构建出了一个Intent对象,然后调用bindService()方法以Activity和Service进行绑定。bindService()方法接收三单参数,第一单参数就是刚刚构建起之Intent对象,第二独参数是眼前创建有底ServiceConnection的实例,第三单参数是一个标志位,这里传出BIND_AUTO_CREATE代表于Activity和Service建立关系后会自行创建Service(即使之前没开创Service也没涉及),这会使MyService中之onCreate()方法取得实施,但onStartCommand()方法无会见实施。

下一场如何我们怀念消除Activity和Service之间的关联怎么收拾为?调用一下unbindService()方法就可了,这吗是Unbind
Service按钮的点击事件里心想事成之逻辑。

现叫咱再运行一下次吧,在MainActivity中点击一下Bind
Service按钮,LogCat里之打印日志如下图所示:

起名 7

好看来,只点击了Bind
Service按钮,但是oncreate()方法得到了推行,而onStartCommand()方法不见面实施。

除此以外要留意,任何一个Service在普应用程序范围外都是通用的,即MyService不仅可以和MainActivity建立关联,还得同其余一个Activity建立关系,而且以起关系时它们都可博到同的MyBinder实例。

怎样销毁Service:

因地方第一段子的文化,我们介绍了销毁Service最简便的一样种植情形:现在卸载程序,重新运行程序,点击Start
Service按钮启动Service,再点击Stop
Service按钮停止Service,这样MyService就被灭绝了:

起名 8

今日回去本段内容。卸载程序,重新开始。那么一旦我们就点击的Bind
Service按钮呢?由于在绑定Service的时光指定的表明位是BIND_AUTO_CREATE,说明点击Bind
Service按钮的时段Service也会吃创造,这时该怎么销毁Service呢?其实呢十分简短,点击一下Unbind
Service按钮,将Activity和Service的涉嫌解除就可了:

起名 9

上述这有限种植销毁之艺术还很好明。那么只要我们既点击了Start
Service按钮,又点击了Bind
Service按钮会怎么样呢?这个时节你晤面发现,不管而是独立点击Stop
Service按钮还是Unbind Service按钮,Service都非会见让灭绝,必备将Unbind Service按钮和Stop
Service按钮都点击一下(没有先后顺序),Service才会于销毁
。也就是说,点击Stop
Service按钮只见面叫Service停止,点击Unbind
Service按钮只见面让Service和Activity解除关系,一个Service必须要在既无和任何Activity关联而处理停止状态的时光才见面给灭绝。

点击Unbind Service按钮后,再次点击Unbind
Service按钮按钮引发的题材:

比方现在Service和Activity已经彼此关联了,点击Unbind
Service按钮能够排除绑定,如果持续点击Unbind
Service按钮,程序会十分退出,这证明代码不够全面,我们要以代码中加一个断定是否绑定的号子mBound。在改MainActivity中增一些代码,最终改MainActivity的总体代码如下:(加多少字是丰富的情节)

 1 package com.example.servicetest02;
 2 
 3 import android.app.Activity;
 4 import android.content.ComponentName;
 5 import android.content.Intent;
 6 import android.content.ServiceConnection;
 7 import android.os.Bundle;
 8 import android.os.IBinder;
 9 import android.util.Log;
10 import android.view.View;
11 import android.view.View.OnClickListener;
12 import android.widget.Button;
13 
14 public class MainActivity extends Activity implements OnClickListener {
15     private Button button1_start_service;
16     private Button button2_stop_service;
17     private Button button3_bind_service;
18     private Button button4_unbind_service;
19     private MyService.MyBinder myBinder;
20     
21     boolean mBound = false; //一开始,并没有和Service绑定.这个参数是用来显示绑定状态
22     
23     //匿名内部类:服务连接对象
24     private ServiceConnection connection = new ServiceConnection() {
25         
26         //当服务异常终止时会调用。注意,解除绑定服务时不会调用
27         @Override
28         public void onServiceDisconnected(ComponentName name) {
29             mBound = false; //服务异常终止时,状态为未绑定
30         }
31         
32         //和服务绑定成功后,服务会回调该方法
33         @Override
34         public void onServiceConnected(ComponentName name, IBinder service) {
35             myBinder = (MyService.MyBinder) service;
36             //在Activity中调用Service里面的方法
37             myBinder.startDownload();
38             myBinder.getProgress();
39             mBound = true; //true说明是绑定状态
40         }
41     };
42     @Override
43     protected void onCreate(Bundle savedInstanceState) {
44         super.onCreate(savedInstanceState);
45         setContentView(R.layout.activity_main);
46         button1_start_service = (Button) findViewById(R.id.button1_start_service);
47         button2_stop_service = (Button) findViewById(R.id.button2_stop_service);
48         button3_bind_service = (Button) findViewById(R.id.button3_bind_service);
49         button4_unbind_service = (Button) findViewById(R.id.button4_unbind_service);
50         button1_start_service.setOnClickListener(this);
51         button2_stop_service.setOnClickListener(this);
52         button3_bind_service.setOnClickListener(this);
53         button4_unbind_service.setOnClickListener(this);
54     }
55     @Override
56     public void onClick(View v) {
57         switch (v.getId()) {
58         case R.id.button1_start_service:
59             Intent startIntent = new Intent(this, MyService.class);
60             startService(startIntent);
61             break;
62         case R.id.button2_stop_service:
63             Intent stopIntent = new Intent(this, MyService.class);
64             stopService(stopIntent);
65             break;
66         case R.id.button3_bind_service:
67             Intent bindIntent = new Intent(this, MyService.class);
68             bindService(bindIntent, connection, BIND_AUTO_CREATE);
69             break;
70         case R.id.button4_unbind_service:
71             //如果和Service是绑定的状态,就解除绑定。
72             if(mBound){
73                 unbindService(connection);
74                 mBound=false;
75             }
76             break;
77 
78         default:
79             break;
80         }
81     }
82 }

长底代码是第21执行、29执行、72执行至74实施。

这样的话,连续点击Unbind Service按钮,就无见面如程序出现异常。

3、started服务与bind服务的分别:

分一:生命周期

  • 经过started方式的劳务会直接运转在后台,需要由组件本身还是外部组件来歇服务才见面为收运行
  • bind方式的服务,生命周期就要负绑定的零件

有别于二:参数传递

  • started服务好被启动之服务目标传递参数,但无法获得服务遭遇法的返回值
  • bind服务可吃启动之劳务目标传递参数,也可以由此绑定的政工对象获得返回结果

骨子里支出被的技能;

  • 先是赖先下started方式来启动一个劳务
  • 日后可以动用bind的方法绑定服务,从而得以一直调用业务方法取得返回值

4、Service的生命周期:

起名 10

假设在列之任何位置调用了Context的startService()方法,相应的劳务就会启动起来,并拨调onstartCommand()方法。如果此服务前还无创造了,onCreate()方法会先于onstartCommand()方法执行。服务启动了后,会一直保持运行状态,直到stopService()或stopself()方法为调用。注意虽然每次调用同一不好startService()方法,onstartCommand()方法就会见因实践同一不行,但骨子里每个服务还不过会在一个实例。所以管您调用了稍稍坏startService()方法,只待调用一蹩脚stopService()或stopself()方法,服务就是见面终止。

除此以外,还可调用Context的bindService()来取得一个服务之持久连接,这时便会回调服务被的onBind()方法。类似地,如果是服务前还不曾开创了,onCreate()方法会先于onBind()方法执行。之后调用方可以博到onBind()方法里返回的IBinder对象的实例,这样,就可知轻易地与劳务拓展通信了。只要调用方和劳动期间的连接没有断开,服务就是会见直接维系运行状态。

 

五、使用Bind Service完成IPC进程之中通信:(在同一个APP内学)

既然是在当和一个APP内拟进程之中通信,其实就算是得过程内通信,但是原理都是千篇一律的呗。

也就是说,要贯彻:让Activity与一个远距离Service建立涉,这将使AIDL来拓展超越进程通信了(IPC)。这里拿Bind
Service及另外的概念再还一下:

1、Bind Service的介绍:

应用程序组件(客户端)通过调用bindService()方法会绑定服务,然后Android系统会调用服务的onBind()回调方法,则只方法会返回一个与服务器端交互的Binder对象。

此绑定是异步的,bindService()方法就回去,并且不吃客户端返回IBinder对象。要收下IBinder对象,客户端必须创造一个ServiceConnection类的实例,并且将这个实例传递给bindService()方法。ServiceConnection对象涵盖了一个系调用的传递IBinder对象的回调方法。

留意:只有Activity、Service、Content
Provider能够绑定服务;BroadcastReceiver广播接收器不能够绑定服务。

2、在客户端绑定一个服务之手续:

(1)实现ServiceConnection抽象类。实现过程中,必须再次写一下少于独回调方法:

  • onServiceConnected() 
    和服务绑定成功后,系统会调用这个办法来发送由劳动的onBind()方法返回的IBinder对象
  • onServiceDisconnected()  
    当服务很终止时见面调用(如服务崩溃或让死死时)。注意,在客户端解除绑定时不见面调用该方法。

(2)调用bindService()方法来传递ServiceConnection类的落实;

(3)当系统调用你的onServiceConnected()回调方法时,你尽管足以起来动接口中定义之方来调用服务了

(4)调用unbindService()方法断开与服务的链接。

横流:bindService()和unbindService()方法还是Context类中的艺术。

3、IPC(Inter-Process Communication)进程中通信机制:

于同等进程被,各个零部件进行通信是异常惠及的,普通的函数调用就可化解;但是对不同之过程被的机件来说,要进行通信,就需利用Android的IPC机制了。

本着采用开发者来说,Android的IBinder/Binder框架实现了Android的IPC通信。当然,IBinder/Binder框架也得以据此来实现经过内通信(本地通信),也得实现进程中通信(远程通信)

自从Android
SDK中针对IBinder/Binder的分解可知,IBinder/Binder是Android远程对象的为主接口,它是Android用于提供高性能IPC通信而规划之一律套轻量级远程调用机制的主干部分。该接口描述了跟一个长距离对象开展通信的肤浅协议。

4、AIDL(Android Interface Definition
Language)Android接口定义语言:

AIDL它好用于受有Service与多只应用程序组件之间开展过进程通信,从而可以实现多只应用程序共享同一个Service的力量。

AIDL支持之项目:八雅核心数据类、String类型、CharSequence、List、Map、自定义。

来拘禁下的当下张原理图:

起名 11

齐图中,如果A应用程序想访问B应用程序中之政工对象,可以先让A绑定B应用被的Service,然后通过Service去访问B中之作业对象。我们得用AIDL来描述得为人家调用的接口(即B中之事情对象)。

5、IPC(进程之中通讯)具体的步子如下:

  • 运AIDL定义业务接口,通过ADT工具来蛮成一个java类,此类实现了经过中远程通讯的代理
  • 编排好之业务类(继承生成的类似中之Stub)来兑现工作接口功能
  • 复通过绑定Service的点子来暴露者业务对象,给其他组件提供功能
  • 调用者组件通过bindService方法绑定服务,从而赢得绑定成功后的远程业务对象或当地工作对象,然后就可以调用相关力量。
  • 专注:一般以动用完绑定服务后,需要消除绑定。

脚就经过代码来实现。

6、让Activity与一个长途Service建立涉的步骤:(在同一个APP内学)

新建一个全新的Android工程ServiceTest02。

(1)新建IPerson.aidl文件,代码如下所示:

1 package com.example.servicetest02;  
2 interface IPerson{  
3     void setName(String name); 
4     void setSex(String sex);
5     void setAge(int age);
6     String getPerson();
7 }

这个文件里,添加我们需要的事体方法。第01推行是包名。注意不要写public等修饰符。(如果此文件写错了,程序会报错,后面的Java文件也不见面由生成)

文件保留之后,ADT会在gen目录下自动生成一个遥相呼应之Java文件,如下图所示:

起名 12

以后,程序运行的时候使用的凡此Java文件,与aidl文件就从不涉嫌了。

俺们来大概分析一下者自动生成的Java文件。完整版本代码如下:

起名 13起名 14

  1 /*
  2  * This file is auto-generated.  DO NOT MODIFY.
  3  * Original file: E:\\workspace\\xiongdilian\\ServiceTest02\\src\\com\\example\\servicetest02\\IPerson.aidl
  4  */
  5 package com.example.servicetest02;
  6 
  7 public interface IPerson extends android.os.IInterface {
  8     /** Local-side IPC implementation stub class. */
  9     public static abstract class Stub extends android.os.Binder implements
 10             com.example.servicetest02.IPerson {
 11         private static final java.lang.String DESCRIPTOR = "com.example.servicetest02.IPerson";
 12 
 13         /** Construct the stub at attach it to the interface. */
 14         public Stub() {
 15             this.attachInterface(this, DESCRIPTOR);
 16         }
 17 
 18         /**
 19          * Cast an IBinder object into an com.example.servicetest02.IPerson
 20          * interface, generating a proxy if needed.
 21          */
 22         public static com.example.servicetest02.IPerson asInterface(
 23                 android.os.IBinder obj) {
 24             if ((obj == null)) {
 25                 return null;
 26             }
 27             android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
 28             if (((iin != null) && (iin instanceof com.example.servicetest02.IPerson))) {
 29                 return ((com.example.servicetest02.IPerson) iin);
 30             }
 31             return new com.example.servicetest02.IPerson.Stub.Proxy(obj);
 32         }
 33 
 34         @Override
 35         public android.os.IBinder asBinder() {
 36             return this;
 37         }
 38 
 39         @Override
 40         public boolean onTransact(int code, android.os.Parcel data,
 41                 android.os.Parcel reply, int flags)
 42                 throws android.os.RemoteException {
 43             switch (code) {
 44             case INTERFACE_TRANSACTION: {
 45                 reply.writeString(DESCRIPTOR);
 46                 return true;
 47             }
 48             case TRANSACTION_setName: {
 49                 data.enforceInterface(DESCRIPTOR);
 50                 java.lang.String _arg0;
 51                 _arg0 = data.readString();
 52                 this.setName(_arg0);
 53                 reply.writeNoException();
 54                 return true;
 55             }
 56             case TRANSACTION_setSex: {
 57                 data.enforceInterface(DESCRIPTOR);
 58                 java.lang.String _arg0;
 59                 _arg0 = data.readString();
 60                 this.setSex(_arg0);
 61                 reply.writeNoException();
 62                 return true;
 63             }
 64             case TRANSACTION_setAge: {
 65                 data.enforceInterface(DESCRIPTOR);
 66                 int _arg0;
 67                 _arg0 = data.readInt();
 68                 this.setAge(_arg0);
 69                 reply.writeNoException();
 70                 return true;
 71             }
 72             case TRANSACTION_getPerson: {
 73                 data.enforceInterface(DESCRIPTOR);
 74                 java.lang.String _result = this.getPerson();
 75                 reply.writeNoException();
 76                 reply.writeString(_result);
 77                 return true;
 78             }
 79             }
 80             return super.onTransact(code, data, reply, flags);
 81         }
 82 
 83         private static class Proxy implements com.example.servicetest02.IPerson {
 84             private android.os.IBinder mRemote;
 85 
 86             Proxy(android.os.IBinder remote) {
 87                 mRemote = remote;
 88             }
 89 
 90             @Override
 91             public android.os.IBinder asBinder() {
 92                 return mRemote;
 93             }
 94 
 95             public java.lang.String getInterfaceDescriptor() {
 96                 return DESCRIPTOR;
 97             }
 98 
 99             @Override
100             public void setName(java.lang.String name)
101                     throws android.os.RemoteException {
102                 android.os.Parcel _data = android.os.Parcel.obtain();
103                 android.os.Parcel _reply = android.os.Parcel.obtain();
104                 try {
105                     _data.writeInterfaceToken(DESCRIPTOR);
106                     _data.writeString(name);
107                     mRemote.transact(Stub.TRANSACTION_setName, _data, _reply, 0);
108                     _reply.readException();
109                 } finally {
110                     _reply.recycle();
111                     _data.recycle();
112                 }
113             }
114 
115             @Override
116             public void setSex(java.lang.String sex)
117                     throws android.os.RemoteException {
118                 android.os.Parcel _data = android.os.Parcel.obtain();
119                 android.os.Parcel _reply = android.os.Parcel.obtain();
120                 try {
121                     _data.writeInterfaceToken(DESCRIPTOR);
122                     _data.writeString(sex);
123                     mRemote.transact(Stub.TRANSACTION_setSex, _data, _reply, 0);
124                     _reply.readException();
125                 } finally {
126                     _reply.recycle();
127                     _data.recycle();
128                 }
129             }
130 
131             @Override
132             public void setAge(int age) throws android.os.RemoteException {
133                 android.os.Parcel _data = android.os.Parcel.obtain();
134                 android.os.Parcel _reply = android.os.Parcel.obtain();
135                 try {
136                     _data.writeInterfaceToken(DESCRIPTOR);
137                     _data.writeInt(age);
138                     mRemote.transact(Stub.TRANSACTION_setAge, _data, _reply, 0);
139                     _reply.readException();
140                 } finally {
141                     _reply.recycle();
142                     _data.recycle();
143                 }
144             }
145 
146             @Override
147             public java.lang.String getPerson()
148                     throws android.os.RemoteException {
149                 android.os.Parcel _data = android.os.Parcel.obtain();
150                 android.os.Parcel _reply = android.os.Parcel.obtain();
151                 java.lang.String _result;
152                 try {
153                     _data.writeInterfaceToken(DESCRIPTOR);
154                     mRemote.transact(Stub.TRANSACTION_getPerson, _data, _reply,
155                             0);
156                     _reply.readException();
157                     _result = _reply.readString();
158                 } finally {
159                     _reply.recycle();
160                     _data.recycle();
161                 }
162                 return _result;
163             }
164         }
165 
166         static final int TRANSACTION_setName = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
167         static final int TRANSACTION_setSex = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
168         static final int TRANSACTION_setAge = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
169         static final int TRANSACTION_getPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
170     }
171 
172     public void setName(java.lang.String name)
173             throws android.os.RemoteException;
174 
175     public void setSex(java.lang.String sex) throws android.os.RemoteException;
176 
177     public void setAge(int age) throws android.os.RemoteException;
178 
179     public java.lang.String getPerson() throws android.os.RemoteException;
180 }

IPerson.java

分析:

起名 15

这个Java文件实际上是一个接口,同时转了以aidl文件中定义之季单方法,并丢掉来了长途调用的死。我们随停Ctrl键,点开上图被蓝框部分的IInterface,查看一下源代码:

起名 16

可以看出,在IInterface接口里,定义了一个接口IBinder,这是IPC机制的主导接口。

重新回去看IPerson.java文件之第9行定义了这么一个抽象类:

起名 17

落得图被之Stub类可以比作存根。Stub类继承了Binder类,同时实现了IPerson接口(没有实现IPerson里之方法)。所以更加了解吧:Stub既是IPerson里之其中类,也是一个IPerson。

(2)新建PersonImpl类,继承IPerson.Stub类,重写父类里之章程。代码如下:(也就是说,根据上面的java类,生成业务对象,即原理图中B应用的工作对象)

 1 package com.example.servicetest02;
 2 
 3 import android.os.RemoteException;
 4 
 5 public class PersonImpl extends IPerson.Stub{
 6     
 7     private String name;
 8     private String sex;
 9     private int age;
10 
11     @Override
12     public void setName(String name) throws RemoteException {
13         // TODO Auto-generated method stub
14         this.name = name;
15         
16     }
17 
18     @Override
19     public void setSex(String sex) throws RemoteException {
20         // TODO Auto-generated method stub
21         this.sex = sex;
22         
23     }
24     @Override
25     public void setAge(int age) throws RemoteException {
26         // TODO Auto-generated method stub
27         this.age = age;
28         
29     }
30 
31     @Override
32     public String getPerson() throws RemoteException {
33         // TODO Auto-generated method stub
34         return "name="+name+",sex="+sex+",age="+age;
35     }
36 }

(3)新建类MyService,代码如下:

 1 package com.example.servicetest02;
 2 
 3 import android.app.Service;
 4 import android.content.Intent;
 5 import android.os.IBinder;
 6 import android.util.Log;
 7 
 8 public class MyService extends Service {  
 9       
10     public static final String TAG = "MyService";  
11   
12      PersonImpl mBinder = new PersonImpl();
13   
14     @Override  
15     public void onCreate() {  
16         super.onCreate();  
17         Log.d(TAG, "onCreate");  
18     }  
19   
20     @Override  
21     public int onStartCommand(Intent intent, int flags, int startId) {  
22         Log.d(TAG, "onStartCommand");  
23         return super.onStartCommand(intent, flags, startId);  
24     }  
25   
26     @Override  
27     public void onDestroy() {  
28         super.onDestroy();  
29         Log.d(TAG, "onDestroy");  
30     }  
31   
32     @Override  
33     public IBinder onBind(Intent intent) { 
34         Log.d("MyService", "onBind");
35         return mBinder;  //在这里返回新建的MyBinder类
36     }
37   
38 }  

主干代码:12履和35执。

盖PersonImpl类继承了IPerson.Stub,而Stub继承了Binder,Binder又实现了IBinder。所以,PersonImpl可以领略吧一个IBinder。于是可以在第35履行返回PersonImpl的实例。

(4)在清单文件被补充加权限:

<service android:name=".MyService"> </service>

 

现行,B应用之政工对象及劳务建立好了。B应用之作业对象通过和Service绑定,让Service把工作对象暴露被了A应用或其它的采用。也就是说,Service最终连无实现业务职能。

而如让A应用来拜会,该怎么开啊?

(5)在activity_main.xml中补充加少独按钮button_bind_service和button_unbind_service,用于绑定远程服务及撤回绑定。activity_main.xml的代码如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/button_bind_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="bind Service" />

    <Button
        android:id="@+id/button_unbind_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="unbind Service" />

</LinearLayout>

(6)MainActivity中的代码,如下所示:

 1 package com.example.servicetest02;
 2 
 3 import android.app.Activity;
 4 import android.content.ComponentName;
 5 import android.content.Intent;
 6 import android.content.ServiceConnection;
 7 import android.os.Bundle;
 8 import android.os.IBinder;
 9 import android.os.RemoteException;
10 import android.util.Log;
11 import android.view.View;
12 import android.view.View.OnClickListener;
13 import android.widget.Button;
14 
15 public class MainActivity extends Activity implements OnClickListener {
16 
17     public static final String TAG = "MainActivity";
18     private Button button_bind_service;
19     private Button button_unbind_service;
20 
21     private IPerson person;
22 
23     boolean mBound = false; // 一开始,并没有和Service绑定.这个参数是用来判断绑定状态
24 
25     // 匿名内部类:服务连接对象
26     private ServiceConnection connection = new ServiceConnection() {
27 
28         // 当服务异常终止时会调用。注意,解除绑定服务时不会调用
29         @Override
30         public void onServiceDisconnected(ComponentName name) {
31             mBound = false; // 服务异常终止时,状态为未绑定
32         }
33 
34         // 和服务绑定成功后,服务会回调该方法。在这个方法里调用的业务对象中的内容
35         @Override
36         public void onServiceConnected(ComponentName name, IBinder service) {
37             Log.d(TAG, "onServiceConnected");
38             person = IPerson.Stub.asInterface(service); // 得到person对象
39             Log.d("person", "person对象的内存地址是" + person); // 打印出person对象的内存地址
40             try {
41                 person.setName("生命壹号");
42                 person.setAge(22);
43                 person.setSex("男");
44                 String p = person.getPerson();
45                 Log.d("person", "person的信息是" + p);
46             } catch (RemoteException e) {
47                 // TODO Auto-generated catch block
48                 e.printStackTrace();
49             }
50             mBound = true; //true说明是绑定状态
51 
52         }
53     };
54 
55     @Override
56     protected void onCreate(Bundle savedInstanceState) {
57         super.onCreate(savedInstanceState);
58         setContentView(R.layout.activity_main);
59         button_bind_service = (Button) findViewById(R.id.button_bind_service);
60         button_unbind_service = (Button) findViewById(R.id.button_unbind_service);
61         button_bind_service.setOnClickListener(this);
62         button_unbind_service.setOnClickListener(this);
63 
64     }
65 
66     @Override
67     public void onClick(View v) {
68         switch (v.getId()) {
69         case R.id.button_bind_service:
70             Intent bindIntent = new Intent(this, MyService.class);
71             bindService(bindIntent, connection, BIND_AUTO_CREATE);
72             break;
73         case R.id.button_unbind_service:
74             // 如果和Service是绑定的状态,就解除绑定。
75             if (mBound) {
76                 unbindService(connection);
77                 mBound = false;
78             }
79             break;
80 
81         default:
82             break;
83         }
84     }
85 
86 }

主导代码是第38行:可以见到,这里首先利用了MyAIDLService.Stub.asInterface()方法将盛传的IBinder对象传换成了IPerson对象,接下去就是得调用在IPerson.aidl文件中定义的富有接口了(41到44行)。调用之后,我们以后台打印输出。

运转程序,点击按钮,效果如下:

起名 18

有鉴于此,我们真都打响落实超越进程通信了,在一个进程面临访问到了另外一个历程遭到之方。
注意,这个Service是运行在主线程当中之,毕竟我们是于该地模拟的呗。

除此以外注意蓝色箭头处,可以看出,这个person其实就是personImpl,因为凡于地方调用。所以说,目前的逾进程通信其实并从未啊本色上之图,因为马上只是在一个Activity里调用了同一个应用程序的Service里的方。而超进程通信的真的含义是为着给一个应用程序去访问另一个应用程序中之Service,以贯彻共享Service的成效。那么下我们自然要修一下,如何才会以另外的应用程序中调用到MyService里的不二法门。

后续回顾第(1)步着自动生成的IPerson.java文件,截取第22顶32推行,摘抄如下:

 1         public static com.example.servicetest02.IPerson asInterface(
 2                 android.os.IBinder obj) {
 3             if ((obj == null)) {
 4                 return null;
 5             }
 6             android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
 7             if (((iin != null) && (iin instanceof com.example.servicetest.IPerson))) {
 8                 return ((com.example.servicetest.IPerson) iin);
 9             }
10             return new com.example.servicetest.IPerson.Stub.Proxy(obj);
11         }

代码解释:

上面第06执行之iin代表的凡,查询当地对象回来的结果。

07执:如果iin不为空,并且iin为IPerson,那就拿iin强制转换为IPerson(08行)。很明白,这里是经过内通信(本地通信)若果为此到之。也尽管是本段中之例证。

10实践:代表的凡过程中通信(远程通信),此时第07行底if语句不建,于是返回第10尽的代办对象Proxy(obj)。

 

实现进程中通信的有数独法子:

假使一旦贯彻进程中通信,就不能不于MainActivity和Service相互独立。有少独主意:

(1)办法一:将本地的Service设置为远程。特需要在清单文件中注册Service的时段以它的android:process属性指定成:remote就足以了,代码如下所示:

<service android:name=".MyService" android:process=":remote"> </service>

后台打印日志如下:

起名 19

达成图的红框部分显得,Service和Activity并非以同一个线程内,连包名都无一样。而IPeron也毫无是当地的IPeron。

若果用这种方式应用到者的季段落遭遇,情形是这般的:

点击button1_start_service,服务启动。既然都拿Service的android:process属性指定成:remote,此时Service和Activity不在和一个线程内,那么就以Service的onStartCommand()方法中实践耗时操作而未又开启子线程,程序为未会见卡住。

然而,如果点击button3_bind_service按钮绑定服务,程序会崩溃的。这是因,目前MyService已经是一个远程Service了,Activity和Service运行在片个不同之经过当中,这时就不克重新利用传统的成立涉的方法,程序吗就算夭折了。

现咱们总一下:

季段落遭遇运用的凡传统的法门以及Service建立涉,默认MainActivity和MyService在和一个线程内,如果用Service的android:process属性指定成:remote,此时MainActivity和MyService将在不同的线程内,但是力不从心绑定服务。

本段中(第五段子)使用的是IPC跨进程通信,MainActivity以及MyService在不同之过程中,可以绑定远程服务。

(2)办法二:新建另外一个工程,真正实现远程通信。旋即即是咱们下同样段子(第六段子)要讲话的内容。

俺们要事先回过头来再巩固一下本段中AIDL的文化吧。

 

7、AIDL支持之自定义数据类型:

咱们于本段中的第4小毕讲到,AIDL支持之类别:八老大中心数据类、String类型、CharSequence、List、Map、自定义,那咱们就算来详细说下此自定义数据类型。

鉴于当时是以不同之经过中传递数据,Android对及时好像数据的格式支持是那个少的,基本上只能传递Java的中坚数据列、字符串、List或Map等。那么要自己怀念传递一个自定义的近乎该怎么处置吧?这即得要给这个类似去实现Parcelable接口,并且要受这个近乎为定义一个同名的AIDL文件进行宣示。这一部分情连无复杂,而且与Service关系不大。具体操作如下:

再次砌一个工程ServiceTest03。步骤如下:

(1)新建一个Student类去贯彻Parcelable接口。Student类是作传递的自定义类:

 1 package com.example.servicetest;
 2 
 3 import android.os.Parcel;
 4 import android.os.Parcelable;
 5 
 6 public class Student implements Parcelable {
 7     private String name;
 8     private String sex;
 9 
10     public Student() {
11         super();
12     }
13 
14     public String getName() {
15         return name;
16     }
17 
18     public void setName(String name) {
19         this.name = name;
20     }
21 
22     public String getSex() {
23         return sex;
24     }
25 
26     public void setSex(String sex) {
27         this.sex = sex;
28     }
29 
30     @Override
31     public int describeContents() {
32         // TODO Auto-generated method stub
33         return 0;
34     }
35 
36     // 重写父类的方法:将需要传送的数据放进来
37     @Override
38     public void writeToParcel(Parcel dest, int flags) {
39         // TODO Auto-generated method stub
40         dest.writeString(name);
41         dest.writeString(name);
42     }
43 
44     public static final Parcelable.Creator<Student> CREATOR = new Parcelable.Creator<Student>() {
45         public Student createFromParcel(Parcel in) {
46             Student s = new Student();
47             s.setName(in.readString());
48             s.setSex(in.readString());
49             return s;
50         }
51 
52         public Student[] newArray(int size) {
53             return new Student[size];
54         }
55     };
56 
57 }

我们于这个仿佛中放入了name和age这片独参数,并促成了Parcelable接口。注意第44执到55尽代码的改动。

继,新建一个暨相近同名的aidl文件,即新建Student.aidl,代码如下:

parcelable Student;

 

只顾是parcelable的第一单假名是有些写。

连续,新建IStudent.aidl,作为需要远距离传递的业务方法。代码如下:

1 package com.example.servicetest03;
2 
3 import com.example.servicetest03.Student;
4 interface IStudent{
5     void setStudent(String name,String sex);
6     Student getStudent();
7 }

着力代码是第03行,虽然Student类文件和准文件是于同一个包下,但是还是要导包,否则用无法辨别Student类。然后于第06执行代码中,就可把Student这个近乎传递出了。注意了,第06实践返回的凡Student类型,这不纵ADIL所支撑之自定义类型嘛。

文件结构如下:

起名 20

概括,传递自定义类,有三只步骤:

  • 从今定义类实现Parcelable接口
  • 新建同名的aidl文件,声明是Parcelable类型的自定义类
  • 以待长途传递的aidl文件被导包,引用进来

这就是说连下去的步调就是同本段中之第6小节一样了,就不再多讲了,这里只有贴代码:

(2)新建StudentImpl类,继承IStudent.Stub类。代码如下:(也就是说,根据步骤(1)中之java类,生成业务对象,即原理图中B应用的事务对象)

 1 package com.example.servicetest03;
 2 
 3 import android.os.RemoteException;
 4 
 5 //业务对象的实现
 6 public class StudentImpl extends IStudent.Stub{
 7 
 8     private Student student;
 9     
10     public StudentImpl(){
11         student = new Student();
12     }
13     @Override
14     public void setStudent(String name, String sex) throws RemoteException {
15         // TODO Auto-generated method stub
16         student.setName(name);
17         student.setSex(sex);
18         
19     }
20 
21     @Override
22     public Student getStudent() throws RemoteException {
23         // TODO Auto-generated method stub
24         return student;
25     }
26 
27 }

(3)新建Service类,代码如下:

 1 package com.example.servicetest03;
 2 
 3 import android.app.Service;
 4 import android.content.Intent;
 5 import android.os.IBinder;
 6 import android.util.Log;
 7 
 8 public class MyService extends Service {  
 9       
10     public static final String TAG = "MyService";  
11   
12     private  StudentImpl studentImpl ;
13   
14     @Override  
15     public void onCreate() {  
16         super.onCreate();  
17         Log.d(TAG, "onCreate");  
18     }  
19   
20     @Override  
21     public int onStartCommand(Intent intent, int flags, int startId) {  
22         Log.d(TAG, "onStartCommand");  
23         return super.onStartCommand(intent, flags, startId);  
24     }  
25   
26     @Override  
27     public void onDestroy() {  
28         super.onDestroy();  
29         Log.d(TAG, "onDestroy");  
30     }  
31   
32     @Override  
33     public IBinder onBind(Intent intent) { 
34         Log.d("MyService", "onBind");
35         studentImpl = new StudentImpl();
36         return studentImpl;  //在这里返回新建的MyBinder类
37     }
38   
39 }

着力代码:12执、35执、36尽。

(4)在清单文件中上加权限:

<service android:name=".MyService"> </service> 

今,B应用之事体对象及服务建立好了。B应用的政工对象通过和Service绑定,让Service把事情对象暴露被了A应用或其它的以。也就是说,Service最终连不曾实现工作功能。

只要要是让A应用来拜会,该怎么开吧?

(5)在activity_main.xml中上加点儿独按钮button1_setStudent和button2_getStudent。activity_main.xml的代码如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <Button
        android:id="@+id/button1_setStudent"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="调用setStudent方法" />

    <Button
        android:id="@+id/button2_getStudent"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="调用getStudent方法" />
</LinearLayout>

流动:布局文件里不再添加绑定服务和撤销绑定的按钮,我们小晚以Activity的生命周期里好这宗事。

(6)MainActivity中之代码,如下所示:

 1 package com.example.servicetest03;
 2 
 3 import android.app.Activity;
 4 import android.content.ComponentName;
 5 import android.content.Intent;
 6 import android.content.ServiceConnection;
 7 import android.os.Bundle;
 8 import android.os.IBinder;
 9 import android.os.RemoteException;
10 import android.view.View;
11 import android.view.View.OnClickListener;
12 import android.widget.Button;
13 import android.widget.Toast;
14 
15 
16 public class MainActivity extends Activity implements OnClickListener {
17     public static final String TAG = "MainActivity";
18     private Button button1_setStudent;
19     private Button button2_getStudent;
20     private IStudent studentImpl;
21     boolean mBound = false; // 一开始,并没有和Service绑定.这个参数是用来判断绑定状态
22 
23     @Override
24     protected void onCreate(Bundle savedInstanceState) {
25         super.onCreate(savedInstanceState);
26         setContentView(R.layout.activity_main);
27         button1_setStudent = (Button) findViewById(R.id.button1_setStudent);
28         button2_getStudent = (Button) findViewById(R.id.button2_getStudent);
29         button1_setStudent.setOnClickListener(this);
30         button2_getStudent.setOnClickListener(this);
31     }    
32 
33     
34     // 匿名内部类:服务连接对象
35     private ServiceConnection connection = new ServiceConnection() {
36         // 当服务异常终止时会调用。注意,解除绑定服务时不会调用
37         @Override
38         public void onServiceDisconnected(ComponentName name) {
39             mBound = false; // 服务异常终止时,状态为未绑定
40         }
41         // 和服务绑定成功后,服务会回调该方法。在这个方法里调用的业务对象中的内容
42         @Override
43         public void onServiceConnected(ComponentName name, IBinder service) {
44             studentImpl = IStudent.Stub.asInterface(service); // 得到person对象
45             mBound = true; //true说明是绑定状态
46         }
47     };
48     
49     //程序启动时,开始绑定服务
50     @Override
51     protected void onStart() {
52         super.onStart();
53         Intent bindIntent = new Intent(this, MyService.class);
54         bindService(bindIntent, connection, BIND_AUTO_CREATE);
55     }
56     
57     //程序退出时,取消绑定服务
58     @Override
59     protected void onDestroy() {
60         super.onDestroy();
61         // 如果和Service是绑定的状态,就解除绑定。
62         if (mBound) {
63             unbindService(connection);
64             mBound = false;
65         }
66     }
67     
68     
69     @Override
70     public void onClick(View v) {
71         switch (v.getId()) {
72         //点击button1_setStudent按钮,设置Student的值
73         case R.id.button1_setStudent:
74             try {
75                 studentImpl.setStudent("生命壹号", "男");
76                 Toast.makeText(this, "设置成功", Toast.LENGTH_SHORT).show();
77             } catch (RemoteException e) {
78                 // TODO Auto-generated catch block
79                 e.printStackTrace();
80             }
81             break;
82         //点击button2_getStudent按钮,获取Student的值
83         case R.id.button2_getStudent:
84             Student s;
85             try {
86                 s = studentImpl.getStudent();
87                 Toast.makeText(this, "name="+s.getName()+",sex="+s.getSex(), Toast.LENGTH_SHORT).show();
88             } catch (RemoteException e) {
89                 // TODO Auto-generated catch block
90                 e.printStackTrace();
91             }
92             break;
93 
94         default:
95             break;
96         }
97     }
98 }

中心代码是第44行。

咱以第75推行、86暨87履行使用到了IStudent中之事情方法。

运行程序,点击第一独按钮,然后点击第二个按钮,效果如下:

起名 21

这样,Acitivity就打响调用了长途Service的自定义类。

 

六、使用Bind Service完成IPC进程之中通信:(两单APP之间)

直达同截被的超进程通信其实并没什么本质上的图,因为及时只有是以一个Activity里调用了和一个应用程序的Service里的点子。而超进程通信的真含义是为吃一个应用程序去拜谒另一个应用程序中之Service,以促成共享Service的意义。那么下我们当要读一下,如何才会于其余的应用程序中调用到MyService里的计。

当第四段受到我们已知道,如果想使给Activity与Service之间确立涉,需要调用bindService()方法,并以Intent作为参数传递进去,在Intent里指定好而绑定的Service,核心代码如下:

Intent bindIntent = new Intent(this, MyService.class);
bindService(bindIntent, connection, BIND_AUTO_CREATE);

此处当构建Intent的时光是运MyService.class来指定要绑定哪一个Service的,但是当旁一个应用程序中错过绑定Service的上并不曾MyService这个近乎,这时就非得采取及隐式Intent了。

具体步骤如下:

我们在第六段子被之MyService02这个工程文件被进行修改。代码实现如下:

(1)现在修改AndroidManifest.xml中的代码,给MyService加上一个action,如下所示:

1         <service android:name=".MyService" >
2             <intent-filter>
3                 <action android:name="com.example.servicetest02.MyService" />
4             </intent-filter>
5         </service> 

随即便证实,MyService可以响应带有com.example.servicetest02.MyService这个action的Intent

本再也运行一下MyService02这个序,这样尽管把远程Service端的行事总体得了。

然后新建一个新的工程,起名为ClientTest,我们即便尝试在是程序中远程调用MyService中之计。

ClientTest中的Activity如果想如果和MyService建立涉其实也非碍事,首先需要拿IPerson.aidl文件从ServiceTest02项目被拷贝过来,注意要以原本的包路径一起拷贝过来,完成后项目之构造要下图所示:

起名 22

(2)在activity_main.xml中上加点儿个按钮button_bind_service和button_unbind_service,用于绑定远程服务同注销绑定。activity_main.xml的代码如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <Button
        android:id="@+id/button_bind_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="bind Service" />

    <Button
        android:id="@+id/button_unbind_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="unbind Service" />
</LinearLayout>

(3)在MainActivity中投入与远程的MyService建立关系的代码,如下所示:

 1 package com.example.clienttest;
 2 
 3 import android.app.Activity;
 4 import android.content.ComponentName;
 5 import android.content.Intent;
 6 import android.content.ServiceConnection;
 7 import android.os.Bundle;
 8 import android.os.IBinder;
 9 import android.os.RemoteException;
10 import android.util.Log;
11 import android.view.View;
12 import android.view.View.OnClickListener;
13 import android.widget.Button;
14 
15 import com.example.servicetest02.IPerson;
16 
17 
18 public class MainActivity extends Activity implements OnClickListener {
19     public static final String TAG = "MainActivity";
20     private Button button_bind_service;
21     private Button button_unbind_service;
22     private IPerson person;
23     boolean mBound = false; // 一开始,并没有和Service绑定.这个参数是用来判断绑定状态
24     // 匿名内部类:服务连接对象
25     private ServiceConnection connection = new ServiceConnection() {
26         // 当服务异常终止时会调用。注意,解除绑定服务时不会调用
27         @Override
28         public void onServiceDisconnected(ComponentName name) {
29             mBound = false; // 服务异常终止时,状态为未绑定
30         }
31         // 和服务绑定成功后,服务会回调该方法。在这个方法里调用的业务对象中的内容
32         @Override
33         public void onServiceConnected(ComponentName name, IBinder service) {
34             Log.d(TAG, "onServiceConnected");
35             person = IPerson.Stub.asInterface(service); // 得到person对象
36             Log.d("person", "person对象的内存地址是" + person); // 打印出person对象的内存地址
37             try {
38                 person.setName("生命壹号");
39                 person.setAge(22);
40                 person.setSex("男");
41                 String p = person.getPerson();
42                 Log.d("person", "person的信息是" + p);
43             } catch (RemoteException e) {
44                 // TODO Auto-generated catch block
45                 e.printStackTrace();
46             }
47             mBound = true; //true说明是绑定状态
48         }
49     };
50     @Override
51     protected void onCreate(Bundle savedInstanceState) {
52         super.onCreate(savedInstanceState);
53         setContentView(R.layout.activity_main);
54         button_bind_service = (Button) findViewById(R.id.button_bind_service);
55         button_unbind_service = (Button) findViewById(R.id.button_unbind_service);
56         button_bind_service.setOnClickListener(this);
57         button_unbind_service.setOnClickListener(this);
58     }
59     @Override
60     public void onClick(View v) {
61         switch (v.getId()) {
62         case R.id.button_bind_service:
63             Intent bindIntent = new Intent("com.example.servicetest02.MyService");
64             bindService(bindIntent, connection, BIND_AUTO_CREATE);
65             break;
66         case R.id.button_unbind_service:
67             // 如果和Service是绑定的状态,就解除绑定。
68             if (mBound) {
69                 unbindService(connection);
70                 mBound = false;
71             }
72             break;
73         default:
74             break;
75         }
76     }
77 }

即有些代码大家自然会死熟知吧?没错,这同于ServiceTest02的MainActivity中之代码几乎是完全相同的,只是当让Activity和Service建立涉的上我们使用了隐式Intent,将Intent的action指定成了com.example.servicetest02.MyAIDLService(63行)。

于眼前Activity和MyService建立关系之后,我们还是调用了setName、setAge、setSex、getPerson()这几只主意,远程的MyService会对传播的参数进行拍卖并返结果,然后用结果打印出来。

这样的话,ClientTest中之代码也就算全部得了,现在运作一下是类型,然后点击Bind
Service按钮,此时即会去与远程的MyService建立关联,观察LogCat中的打印信息如下所示:

起名 23

注意红框部分,包名是不一致的哦。由此可见,我们的确就成促成跨越进程通信了,在一个序中走访到了另外一个主次中之措施。

 

七、Messenger的使用:

public final class Messenger extends Object implements Parcelable

 

介绍:Messenger实现了IPC通信,底层也是采取了AIDL方式。和AIDL方式各异之是,Messenger方式是应用Handler形式处理,因此,它是线程安全之,这为意味着其不支持并发处理;而AIDL方式是非线程安全之,支持并发处理,因此,我们下AIDL方式时,需要确保代码的线程安全。大部分情况下,应用被不需出现处理,因此我们日常就需要以Messenger方式。

过程:以过程A中开创一个Message,将以此Message对象通过Messenger.send(message)方法传递到过程B的音信队列里,然后交由Handler去处理。

本,Message对象自我是无力回天为传送及过程B的,send(message)方法会使一个Pacel对象对Message对象编集,再用Pacel对象传递至过程B中,然后去掉编集,得到一个暨过程A中之Message对象内容相同的目标。

至于多线程的Handler机制,如果无亮堂的话,可以参见本人另外一篇博客:

使用Messenger来实现IPC的步骤:

  • 每当Service中开创一个Messenger对象并绑定一个Handler
  • 于onBind方法被经过Messenger.getIbinder方法返回一个IBinder对象。
  • 以调用的零件中之ServiceConnection的onServiceConnected事件方中因iBinder对象来创造一个Messenger对象。这样,两单Messenger就又绑定到一个IBinder上,从而实现通信。
  • 每当调用的组件中行使Messenger的send方法来发送信息及Service的Messenger对象中。

那么咱们经过代码来落实以下吧。新建一个全新的工MessengerTest。步骤如下:

(1)新建一个MessengerService类,继承Service类,代码如下:

 1 package com.example.messengertest;
 2 
 3 import android.app.Service;
 4 import android.content.Intent;
 5 import android.os.Handler;
 6 import android.os.IBinder;
 7 import android.os.Message;
 8 import android.os.Messenger;
 9 import android.util.Log;
10 import android.widget.Toast;
11 
12 public class MessengerService extends Service{
13 
14     public static final int MSG_SAY_HELLO = 1;
15     
16     private Handler handler = new Handler() {
17         public void handleMessage(Message msg) {
18             switch (msg.what) {
19             case MSG_SAY_HELLO:
20                 //在服务里定义业务方法
21                 Toast.makeText(MessengerService.this, "hello", Toast.LENGTH_SHORT).show();
22                 Log.d("MessengerService", "MessengerService thread id is " + Thread.currentThread().getId()); //打印MessengerService的线程id
23                 break;
24             default:
25                 break;
26             }
27         }
28     };
29     
30     
31     private Messenger messenger = new Messenger(handler);
32     
33     
34     @Override
35     public IBinder onBind(Intent intent) {
36         // TODO Auto-generated method stub
37         return messenger.getBinder();
38     }
39 }

着力代码:16到28执行、31执行、37实施。

37实施吃,将IBinder类型返回下,就已与Messenger进行绑定了。

(2)在清单文件被登记服务:(和Activity标签并列)

<service android:name=".MessengerService"> </service>

 

(3)修改activity_main.xml代码,添加一个按钮,用于发送Message,代码如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/button_messenger"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="使用messenger" />
</LinearLayout>

(4)在MainActivity作为次的主Activity,在里边在发送Message消息和建Service连接的逻辑,代码如下:

 1 package com.example.messengertest;
 2 
 3 import android.app.Activity;
 4 import android.content.ComponentName;
 5 import android.content.Intent;
 6 import android.content.ServiceConnection;
 7 import android.os.Bundle;
 8 import android.os.IBinder;
 9 import android.os.Message;
10 import android.os.Messenger;
11 import android.os.RemoteException;
12 import android.util.Log;
13 import android.view.View;
14 import android.view.View.OnClickListener;
15 import android.widget.Button;
16 
17 public class MainActivity extends Activity implements OnClickListener {
18 
19     private Button button_messenger;
20 
21     private Messenger messenger;
22     boolean mBound = false;
23 
24     @Override
25     protected void onCreate(Bundle savedInstanceState) {
26         super.onCreate(savedInstanceState);
27         setContentView(R.layout.activity_main);
28         button_messenger = (Button) findViewById(R.id.button_messenger);
29         button_messenger.setOnClickListener(this);
30     }
31 
32     @Override
33     protected void onStart() {
34         // TODO Auto-generated method stub
35         super.onStart();
36         Intent bindIntent = new Intent(this, MessengerService.class);
37         bindService(bindIntent, connection, BIND_AUTO_CREATE);
38     }
39 
40     @Override
41     protected void onDestroy() {
42         // TODO Auto-generated method stub
43         super.onDestroy();
44         if (mBound) {
45             unbindService(connection);
46             mBound = false;
47         }
48     }
49 
50     private ServiceConnection connection = new ServiceConnection() {
51         @Override
52         public void onServiceConnected(ComponentName name, IBinder service) {
53             // TODO Auto-generated method stub
54             messenger = new Messenger(service);            
55             
56             mBound = true;
57         }
58 
59         @Override
60         public void onServiceDisconnected(ComponentName name) {
61             // TODO Auto-generated method stub
62             mBound = false;
63 
64         }
65 
66     };
67 
68     //点击按钮,发送Message消息,在MessengerService里接收,从而执行Service里面的方法
69     @Override
70     public void onClick(View v) {
71         switch (v.getId()) {
72         case R.id.button_messenger:
73             Message  msg  = Message.obtain();
74             msg.what = MessengerService.MSG_SAY_HELLO;
75             try {
76                 messenger.send(msg);
77                   Log.d("MainActivity", "MainActivity thread id is " + Thread.currentThread().getId()); //打印MainActivity的线程id
78             } catch (RemoteException e) {
79                 // TODO Auto-generated catch block
80                 e.printStackTrace();
81             }
82             break;
83 
84         default:
85             break;
86         }
87     }
88 
89 }

咱们于达到同样步之MessengerService类新建了一个Messenger,在这里还要新建另一个Messenger(54行)。两单Messenger绑定了和一个劳务,Activity就足以同Service实现通讯了。

点击按钮(72实施),发送信息,让MessengerService类里之Messenger去接,然后交给handler去处理,从而执行handleMessage()里方法,也就是说,执行了Service里面的不二法门。

运行程序,点击按钮,显示效果如下:

起名 24

后台打印日志如下:

起名 25

证实这MessengerService和普通Service一样,也是运行于主线程当中之。

本来矣,这里的Messenger的落实比较简单,如果以后要实现复杂IPC访问,还是用好去写AIDL才越直接有效,可控性强。

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图