Adnroid Server深入解析.docx

上传人:b****5 文档编号:12026959 上传时间:2023-04-16 格式:DOCX 页数:15 大小:79.65KB
下载 相关 举报
Adnroid Server深入解析.docx_第1页
第1页 / 共15页
Adnroid Server深入解析.docx_第2页
第2页 / 共15页
Adnroid Server深入解析.docx_第3页
第3页 / 共15页
Adnroid Server深入解析.docx_第4页
第4页 / 共15页
Adnroid Server深入解析.docx_第5页
第5页 / 共15页
点击查看更多>>
下载资源
资源描述

Adnroid Server深入解析.docx

《Adnroid Server深入解析.docx》由会员分享,可在线阅读,更多相关《Adnroid Server深入解析.docx(15页珍藏版)》请在冰豆网上搜索。

Adnroid Server深入解析.docx

AdnroidServer深入解析

Android的Service深入分析(全)

1.先来看看WhatisService?

AServiceisnotaseparateprocessAnd AServiceisnotathread.一个服务不是一个独立的进程,也不是一个线程。

那Service是什么呢?

 后台运行处理耗时较长的工作

 Service是一个应用程序组件

 Service没有图形化界面

 Service通常用来处理一些耗时比较长的操作

 可以使用Service更新ContentProvider,发送Intent以及启动系统的通知等等

2.接着来看看Service的整个生命周期:

Service的活动生命周期是在onStart()之后,这个方法会处理通过startServices()方法传递来的Intent对象。

音乐Service可以通过开打intent对象来找到要播放的音乐,然后开始后台播放。

Service停止时没有相应的回调方法,即没有onStop()方法。

onCreate()方法和onDestroy()方法是针对所有的Services,无论它们是否启动。

通过Context.startService()和Context.bindService()方法。

然而,只有通过startService()方法启动的Service才会被调用onStart()方法。

如果一个Service允许别人绑定,那么需要实现以下额外的方法:

IBinderonBind(Intentintent)

booleanonUnbind(Intentintent)

voidonRebind(Intentintent)

onBind()回调方法会继续传递通过bindService()传递来的intent对像。

onUnbind()会处理传递给unbindService()的intent对象。

如果Service允许绑定,onBind()会返回客户端与服务互相联系的通信频道。

如果建立了一个新的客户端与服务的链接,onUnbind()方法可以请求调用onRebind()方法。

下面的图表介绍了Service的回调方法,然而,它把通过startService()方法建立的服务从通过bindService()方法建立的服务分离开。

记住任何服务,无果它怎样建立,都默认客户端可以链接,所以任何的Service能够接收onBind()和onUnbind()方法。

 

3.Service组件的通信方式一共有三种:

(1)通过startService来启动的Service;

(2)通过bindService来启动的Service;(3)使用AIDL方式的Service,下面我们来看看它们的具体使用方法,和它们之间有什么区别。

(1)首先来说说通过startService来启动的Service(后台处理工作)

         startService(Intentservice),通过intent值来指定启动哪个Service,可以直接指定目标Service的名,也可以通过Intent的action属性来启动设置了相应action属性的Service

,使用这种方式启动的Service,当启动它的Activity被销毁时,是不会影响到它的运行的,这时它仍然继续在后台运行它的工作。

直至调用StopService(Intentservice)方法时

时或者是当系统资源非常紧缺时,这个服务才会调用onDestory()方法停止运行。

所以这种Service一般可以用做,处理一些耗时的工作。

可能有人会问,如果Service不是独立的

一个进程的话,为什么当Activity退出时,Service仍然可以进行运行呢?

其实是这样的,sdk上说了activity和service默认是运行在应用进程的主线程中,四大组件默认都是和

activity运行在同一个主线程中的,那就是说activity通过startservice方法启动一个服务后,被启动的服务和activity都是在同一个线程中的。

所以当我主动销毁了这个activity,但是

他所在的线程还是存在的,只不过是这个activity他所占用的资源被释放掉了,这个activity所在的主线程只有当android内存不足才会被杀死掉,否则一般的情况下这个activity所

在的应用程序的线程始终存在,也就是这个activity所启动的服务也会一直运行下去。

        还有一点需要注意的是,如果Service要处理一些比较耗时的工作时,因为Service和Activity默认情况都在同一个主线程中的缘故,所以要操作这些耗时的工作一般是在

Service里另起一个新线程来处理。

这样可以避免主线程的阻塞,影响用户体验性。

(2)然后来说说通过bindService来启动的Service(在本地同进程内与Activity交互)

         这里举一个实例来讲:

 首选,创建一个接口,IService

        packageyy.android.service

       publicinterfaceIService{

          StringgetName();

       }   

 接着,创建一个服务LocalService  

packageyy.android.service;

importandroid.app.Service;

importandroid.content.Intent;

importandroid.os.Binder;

importandroid.os.IBinder;

importandroid.util.Log;

   publicclassLocalServiceextendsService{

     privatestaticfinalStringTAG="LocalService";

      privateMyBindmyBind=newMyBind(); 

      publicIBinderonBind(Intentintent){

       Log.d(TAG,"localServiceonBind");

        returnmyBind;

     } 

    @Override

    publicvoidonCreate(){

      super.onCreate();

      Log.d(TAG,"localServiceonCreate");

    }

    @Override

    publicvoidonDestroy(){

       super.onDestroy();

       Log.d(TAG,"localServiceonDestroy");

    }

    @Override

    publicvoidonStart(Intentintent,intstartId){

      //TODOAuto-generatedmethodstub

      super.onStart(intent,startId); 

      Log.d(TAG,"localServiceonStart");

    } 

   @Override

   publicbooleanonUnbind(Intentintent){

      //TODOAuto-generatedmethodstub

     Log.d(TAG,"localServiceonUnBind");

     returnsuper.onUnbind(intent); 

   }

   publicclassMyBindextendsBinderimplementsIService{

      publicStringgetName(){

      //TODOAuto-generatedmethodstub

      return"YUZHIBOYI"; 

      } 

     } 

   }

 最后就是实现ServiceActivity了:

packageyy.android.service;

importandroid.app.Activity;

importandroid.os.Bundle;

importandroid.content.ComponentName;

importandroid.content.Intent;

importandroid.content.ServiceConnection;

importandroid.os.IBinder; 

importandroid.util.Log;

importandroid.view.View;

importandroid.view.View.OnClickListener;

importandroid.widget.Button;

importandroid.widget.EditText;

publicclassServiceActivityextendsActivity{ 

   

 privatestaticfinalStringTAG="ServiceActivity";

  privateIServiceiService=null;

  privateEditTextedit;

  privateButtonmBind; 

  ServiceConnectionconnection=newServiceConnection(){

    publicvoidonServiceDisconnected(ComponentNamename){

     Log.d(TAG,"DisConnection");

      System.out.println("DisConnection!

!

!

");

    }

    publicvoidonServiceConnected(ComponentNamename,IBinderservice){

      //TODOAuto-generatedmethodstub 

       Log.d(TAG,"Connection");

       System.out.println("Connection!

!

!

");

       iService=(IService)service;

       edit.setText(iService.getName());

      //text.setText(iService.getName());

    }

  }; 

  @Override 

  publicvoidonCreate(BundlesavedInstanceState){ 

    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);

   // Log.d(TAG,"Start");

    edit=(EditText)findViewById(R.id.edit); 

    mBind=(Button)findViewById(R.id.Connection);

    mBind.setOnClickListener(newOnClickListener(){ 

      publicvoidonClick(Viewv){

         Intentintent=newIntent(ServiceActivity.this,LocalService.class);

         bindService(intent,connection,BIND_AUTO_CREATE);  

      }

    });

  }

}

AndroidManifest.xml注册LocalService

name=".LocalService"> 

       

       

 

布局文件:

xmlversion="1.0"encoding="utf-8"?

>

android="

  android:

layout_width="fill_parent"

  android:

layout_height="fill_parent"

  android:

orientation="vertical">

   

    android:

id="@+id/edit"

    android:

layout_width="fill_parent"

    android:

layout_height="wrap_content"

   >   

   

    android:

id="@+id/Connection"

    android:

layout_height="wrap_content"

    android:

layout_width="wrap_content"

    android:

text="@string/Bind"/>

当运行程序是,日志信息是这样的:

05-1013:

46:

28.353:

D/LocalService(1328):

localServiceonCreate

                                 05-1013:

46:

28.353:

D/LocalService(1328):

localServiceonBind

                                 05-1013:

46:

28.385:

D/ServiceActivity(1328):

Connection

当点击模拟器的back按钮时,日志信息:

  05-1013:

46:

57.953:

D/LocalService(1328):

localServiceonUnBind

                                      05-1013:

46:

57.953:

D/LocalService(1328):

localServiceonDestroy

从日志信息可以分析出,整个程序的运行过程是这样的:

点用户点击绑定服务按钮时Activity调用bindService()方法,然后系统就去调用onCreate创建服务,然后系统继续调用onBind()方法向Activity传递一个IBinder类型的对象,是传递给Activity里的ServiceConnection里的onServiceConnected(ComponentNamename,IBinderservice)的第二个参数,然后通过这个参数可以获得IService的方法。

进行本地的Activity和Service交互。

(在同一个进程里进行的),当用户点击back建时,系统就调用onUnbind()再接着调用onDestory()方法销毁服务。

总结可以理解成:

bindSevice()->onCreate()->onBind()->onServiceConnected();这里需要注意的一点是,启动的LocalService是和ServiceActivity在同一个进程里的,因为在注册服务时,没有配置它的android:

process = "xxxx" 属性。

具体android:

process的用法可以自己去看其他资料。

(3)最后要说的是使用AIDL方式的Service(进行跨进程的通信)

AIDL(AndroidInterfaceDefinitionLanguage) IPC机制是面向对象的,轻量级的。

通过AIDL定义的接口可以实现服务器端与客户端的IPC通信。

在Android上,一个进程不能简单的像访问本进程内存一样访问其他进程的内存。

所以,进程间想要对话,需要将对象拆解为操作系统可以理解的基本数据单元,并且有序的通过进程边界。

通过代码来实现这个数据传输过程是冗长乏味的,所幸的是android提供了AIDL工具来帮我们完成了此项工作。

注意:

仅仅在你需要A应用程序的客户端访问B应用程序的服务器端来实现IPC通信,并且在服务器端需要处理多线程(客户端)访问的情况下使用AIDL。

如果不需要使用到进程间的IPC通信,那么通过Binder接口实现将更为合适,如果需要实现进程间的IPC通信,但不需要处理多线程(多客户端),通过Messager接口来实现将更为合适。

不管怎样,在使用AIDL之前,应先确保已理解了BoundService。

AIDL接口的调用采用的是直接的函数调用方式,但你无法预知哪个进程(或线程)将调用该接口。

同进程的线程调用和其他进程调用该接口之间是有所区别的:

∙在同进程中调用AIDL接口,AIDL接口代码的执行将在调用该AIDL接口的线程中完成,如果在主UI线程中调用AIDL接口,那么AIDL接口代码的执行将会在这个主UI线程中完成。

如果是其他线程,AIDL接口代码的执行将在service中完成。

因此,如果仅仅是本进程中的线程访问该服务,你完全可以控制哪些线程将访问这个服务(但是如果是这样,那就完全没必要使用AIDL了,而采取Binder接口的方式更为合适)。

∙远程进程(其他线程)调用AIDL接口时,将会在AIDL所属的进程的线程池中分派一个线程来执行该AIDL代码,所以编写AIDL时,你必须准备好可能有未知线程访问、同一时间可能有多个调用发生(多个线程的访问),所以ADIL接口的实现必须是线程安全的。

∙可以用关键字oneway来标明远程调用的行为属性,如果使用了该关键字,那么远程调用将仅仅是调用所需的数据传输过来并立即返回,而不会等待结果的返回,也即是说不会阻塞远程线程的运行。

AIDL接口将最终将获得一个从Binder线程池中产生的调用(和普通的远程调用类似)。

如果关键字oneway在本地调用中被使用,将不会对函数调用有任何影响。

 

定义AIDL接口

AIDL接口使用后缀名位.aidl的文件来定义,.aidl文件使用java语法编写,并且将该.aidl文件保存在src/目录下(无论是服务端还是客户端都得保存同样的一份拷贝,也就是说只要是需要使用到该AIDL接口的应用程序都得在其src目录下拥有一份.aidl文件的拷贝)。

编译时,Androidsdk工具将会为src/目录下的.aidl文件在gen/目录下产生一个IBinder接口。

服务端必须相应的实现该IBinder接口。

客户端可以绑定该服务、调用其中的方法实现IPC通信。

 

创建一个用AIDL实现的服务端,需要以下几个步骤:

 

   1.创建.aidl文件:

       该文件(YourInterface.aidl)定义了客户端可用的方法和数据的接口

   2.实现这个接口:

       AndroidSDK将会根据你的.aidl文件产生AIDL接口。

生成的接口包含一个名为Stub的抽象内部类,该类声明了所有.aidl中描述的方法,你必须在代码里继承该Stub类并且实现.aidl中定义的方法。

   3.向客户端公开服务端的接口:

       实现一个Service,并且在onBinder方法中返回第2步中实现的那个Stub类的子类(实现类)。

注意:

服务端AIDL的任何修改都必须的同步到所有的客户端,否则客户端调用服务端得接口可能会导致程序异常(因为此时客户端此时可能会调用到服务端已不再支持的接口

1.创建.aidl文件

AIDL使用简单的语法来声明接口,描述其方法以及方法的参数和返回值。

这些参数和返回值可以是任何类型,甚至是其他AIDL生成的接口。

重要的是必须导入所有非内置类型,哪怕是这些类型是在与接口相同的包中。

默认的AIDL支持一下的数据类型(这些类型不需要通过import导入):

∙java语言的原始数据类型(包括int,long,char,boolen等等)

∙String

∙CharSequence:

该类是被TextView和其他控件对象使用的字符序列

∙List:

列表中的所有元素必须是在此列出的类型,包括其他AIDL生成的接口和可打包类型。

List可以像一般的类(例如List)那样使用,另一边接收的具体类一般是一个ArrayList,这些方法会使用List接口

∙Map:

Map中的所有元素必须是在此列出的类型,包括其他AIDL生成的接口和可打包类型。

一般的maps(例如Map)不被支持,另一边接收的具体类一般是一个HashMap,这些方法会使用Map接口。

对于其他的类型,在aidl中必须使用import导入,即使该类型和aidl处于同一包内。

定义一个服务端接口时,注意一下几点:

∙方法可以有0个或多个参数,可以使空返回值也可以返回所需的数据。

∙所有非原始数据类型的参数必须指定参数方向(是传入参数,还是传出参数),传入参数使用in关键字标记,传出参数使用out,传入传出参数使用inout。

如果没有显示的指定,那么将缺省使用in。

∙在aidl文件中所有的注释都将会包含在生成的IBinder接口中(在Import和pacakge语句之上的注释除外)。

∙aidl中只支持成员方法,不支持成员变量。

 

我们通过一个例子来说明:

(服务端)YAIDLService工程里的包yy.service.aidl有以下三个文件

IAIDLService.aidl

packageyy.service.aidl; 

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工程科技 > 能源化工

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1