`
yangguangfu
  • 浏览: 1539798 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

android Service Activity三种交互方式(付源码)

阅读更多

android Service Binder交互通信实例

最下边有源代码:

 

 

android SDK提供了Service,用于类似*nix守护进程或者windows的服务。

Service有两种类型:

  1. 本地服务(Local Service):用于应用程序内部
  2. 远程服务(Remote Sercie):用于android系统内部的应用程序之间

前者用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验比较好。

后者可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。

 

编写不需和Activity交互的本地服务示例

本地服务编写比较简单。首先,要创建一个Service类,该类继承android的Service类。这里写了一个计数服务的类,每秒钟为计数器加一。在服务类的内部,还创建了一个线程,用于实现后台执行上述业务逻辑。

 

 

package com.easymorse;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class CountService extends Service {

   
private boolean threadDisable;

   
private int count;

    @Override
   
public IBinder onBind(Intent intent) {
       
return null ;
    }

    @Override
   
public void onCreate() {
       
super .onCreate();
       
new Thread( new Runnable() {

            @Override
           
public void run() {
               
while ( ! threadDisable) {
                   
try {
                        Thread.sleep(
1000 );
                    }
catch (InterruptedException e) {
                    }
                    count
++ ;
                    Log.v(
" CountService " , " Count is " + count);
                }
            }
        }).start();
    }

    @Override
   
public void onDestroy() {
       
super .onDestroy();
       
this .threadDisable = true ;
        Log.v(
" CountService " , " on destroy " );
    }

   
public int getCount() {
       
return count;
    }

}

 需要将该服务注册到配置文件AndroidManifest.xml中,否则无法找到:

<? xml version="1.0" encoding="utf-8" ?>
< manifest xmlns:android ="http://schemas.android.com/apk/res/android"
    package
="com.easymorse" android:versionCode ="1" android:versionName ="1.0" >
   
< application android:icon ="@drawable/icon" android:label ="@string/app_name" >
       
< activity android:name =".LocalServiceDemoActivity"
            android:label
="@string/app_name" >
           
< intent-filter >
               
< action android:name ="android.intent.action.MAIN" />
               
< category android:name ="android.intent.category.LAUNCHER" />
           
</ intent-filter >
       
</ activity >
       
< service android:name ="CountService" />
   
</ application >
   
< uses-sdk android:minSdkVersion ="3" />
</ manifest/>

 

 

在Activity中启动和关闭本地服务。

package com.easymorse;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;

public class LocalServiceDemoActivity extends Activity {
   
/** Called when the activity is first created. */
    @Override
   
public void onCreate(Bundle savedInstanceState) {
       
super .onCreate(savedInstanceState);
        setContentView(R.layout.main);

       
this .startService( new Intent( this , CountService. class ));
    }

    @Override
   
protected void onDestroy() {
       
super .onDestroy();
       
this .stopService( new Intent( this , CountService. class ));
    }
}

 

可通过日志查看到后台线程打印的计数内容。

编写本地服务和Activity交互的示例

上面的示例是通过startService和stopService启动关闭服务的。适用于服务和activity之间没有调用交互的情况。如果之间需要传递参数或者方法调用。需要使用bind和unbind方法。

具体做法是,服务类需要增加接口,比如ICountService,另外,服务类需要有一个内部类,这样可以方便访问外部类的封装数据,这个内部类 需要继承Binder类并实现ICountService接口。还有,就是要实现Service的onBind方法,不能只传回一个null了。

这是新建立的接口代码:

package com.easymorse;

public interface ICountService {
   
public abstract int getCount();
}

 

修改后的CountService代码:

package com.easymorse;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

public class CountService extends Service implements ICountService {

   
private boolean threadDisable;

   
private int count;

   
private ServiceBinder serviceBinder = new ServiceBinder();

   
public class ServiceBinder extends Binder implements ICountService{
        @Override
       
public int getCount() {
           
return count;

        }

    }

    @Override

    public IBinder onBind(Intent intent) {
       
return serviceBinder;
    }

    @Override
   
public void onCreate() {
       
super .onCreate();
       
new Thread( new Runnable() {

            @Override
           
public void run() {
               
while ( ! threadDisable) {
                   
try {
                        Thread.sleep(
1000 );
                    }
catch (InterruptedException e) {
                    }
                    count
++ ;
                    Log.v(
" CountService " , " Count is " + count);
                }
            }
        }).start();
    }

    @Override
   
public void onDestroy() {
       
super .onDestroy();
       
this .threadDisable = true ;
        Log.v(
" CountService " , " on destroy " );
    }

   
/* (non-Javadoc)
     * @see com.easymorse.ICountService#getCount()
    
*/
   
public int getCount() {
       
return count;
    }

}

 

服务的注册也要做改动,AndroidManifest.xml文件:

<? xml version="1.0" encoding="utf-8" ?>
< manifest xmlns:android ="http://schemas.android.com/apk/res/android"
    package
="com.easymorse" android:versionCode ="1" android:versionName ="1.0" >
   
< application android:icon ="@drawable/icon" android:label ="@string/app_name" >
       
< activity android:name =".LocalServiceDemoActivity"
            android:label
="@string/app_name" >
           
< intent-filter >
               
< action android:name ="android.intent.action.MAIN" />
               
< category android:name ="android.intent.category.LAUNCHER" />
           
</ intent-filter >
       
</ activity >
       
< service android:name ="CountService" >
           
< intent-filter >
               
< action android:name ="com.easymorse.CountService" />
           
</ intent-filter >
       
</ service >
   
</ application >
   
< uses-sdk android:minSdkVersion ="3" />
</ manifest >

 

Acitity代码不再通过startSerivce和stopService启动关闭服务,另外,需要通过ServiceConnection的内部类实现来连接Service和Activity。

package com.easymorse;

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.util.Log;

public class LocalServiceDemoActivity extends Activity {

   
private ServiceConnection serviceConnection = new ServiceConnection() {

        @Override
       
public void onServiceConnected(ComponentName name, IBinder service) {
            countService
= (ICountService) service;
            Log.v(
" CountService " , " on serivce connected, count is "
                   
+ countService.getCount());
        }

        @Override
       
public void onServiceDisconnected(ComponentName name) {
            countService
= null ;
        }

    };

   
private ICountService countService;

   
/** Called when the activity is first created. */
    @Override
   
public void onCreate(Bundle savedInstanceState) {
       
super .onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
this .bindService( new Intent( " com.easymorse.CountService " ),
               
this .serviceConnection, BIND_AUTO_CREATE);
    }

    @Override
   
protected void onDestroy() {

          this .unbindService(serviceConnection);        

          super .onDestroy();       //注意先后
    }
}

 

编写传递基本型数据的远程服务

上面的示例,可以扩展为,让其他应用程序复用该服务。这样的服务叫远程(remote)服务,实际上是进程间通信(RPC)。

这时需要使用android接口描述语言(AIDL)来定义远程服务的接口,而不是上述那样简单的java接口。扩展名为aidl而不是java。 可用上面的ICountService改动而成ICountSerivde.aidl,eclipse会自动生成相关的java文件。

package com.easymorse;

interface ICountService {
   
int getCount();
}

 

编写服务(Service)类,稍有差别,主要在binder是通过远程获得的,需要通过桩(Stub)来获取。桩对象是远程对象的本地代理。

package com.easymorse;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

public class CountService extends Service {

   
private boolean threadDisable;

   
private int count;

   
private ICountService.Stub serviceBinder = new ICountService.Stub() {

        @Override
       
public int getCount() throws RemoteException {
           
return count;
        }
    };

    @Override
   
public IBinder onBind(Intent intent) {
       
return serviceBinder;
    }

    @Override
   
public void onCreate() {
       
super .onCreate();
       
new Thread( new Runnable() {

            @Override
           
public void run() {
               
while ( ! threadDisable) {
                   
try {
                        Thread.sleep(
1000 );
                    }
catch (InterruptedException e) {
                    }
                    count
++ ;
                    Log.v(
" CountService " , " Count is " + count);
                }
            }
        }).start();
    }

    @Override
   
public void onDestroy() {
       
super .onDestroy();
       
this .threadDisable = true ;
        Log.v(
" CountService " , " on destroy " );
    }
}

 

配置文件AndroidManifest.xml和上面的类似,没有区别。

在Activity中使用服务的差别不大,只需要对ServiceConnection中的调用远程服务的方法时,要捕获异常。

private ServiceConnection serviceConnection = new ServiceConnection() {

    @Override
   
public void onServiceConnected(ComponentName name, IBinder service) {
        countService
= (ICountService) service;
       
try {
            Log.v(
" CountService " , " on serivce connected, count is "
                   
+ countService.getCount());
        }
catch (RemoteException e) {
           
throw new RuntimeException(e);
        }
    }

    @Override
   
public void onServiceDisconnected(ComponentName name) {
        countService
= null ;
    }

};

 

这样就可以在同一个应用程序中使用远程服务的方式和自己定义的服务交互了。

如果是另外的应用程序使用远程服务,需要做的是复制上面的aidl文件和相应的包构到应用程序中,其他调用等都一样。

编写传递复杂数据类型的远程服务

远程服务往往不只是传递java基本数据类型。这时需要注意android的一些限制和规定:

  1. android支持String和CharSequence
  2. 如果需要在aidl中使用其他aidl接口类型,需要import,即使是在相同包结构下;
  3. android允许传递实现Parcelable接口的类,需要import;
  4. android支持集合接口类型List和Map,但是有一些限制,元素必须是基本型或者上述三种情况,不需要import集合接口类,但是需要对元素涉及到的类型import;
  5. 非基本数据类型,也不是String和CharSequence类型的,需要有方向指示,包括in、out和inout,in表示由客户端设置,out表示由服务端设置,inout是两者均可设置。

这里将前面的例子中返回的int数据改为复杂数据类型:

package com.easymorse;

import android.os.Parcel;
import android.os.Parcelable;

public class CountBean implements Parcelable {

   
public static final Parcelable.Creator < CountBean > CREATOR = new Creator < CountBean > () {

        @Override
       
public CountBean createFromParcel(Parcel source) {
            CountBean bean
= new CountBean();
            bean.count
= source.readInt();
           
return bean;
        }

        @Override
       
public CountBean[] newArray( int size) {
           
return new CountBean[size];
        }

    };

   
public int count;

    @Override
   
public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(
this .count);
    }

    @Override
   
public int describeContents() {
       
return 0 ;
    }

}

 

然后,需要在相同包下建一个同名的aidl文件,用于android生成相应的辅助文件:

package com.easymorse;

parcelable CountBean;

 

这一步是android 1.5后的变化,无法通过adt生成aidl,也不能用一个比如全局的project.aidl文件,具体见:

http://www.anddev.org/viewtopic.php?p=20991

然后,需要在服务的aidl文件中修改如下:

package com.easymorse;

import com.easymorse.CountBean;

interface ICountService {
    CountBean getCount();
}

 

其他的改动很小,只需将CountService和调用CountService的部分修改为使用CountBean即可

分享到:
评论
6 楼 jiduoduo 2016-02-16  
< service android:name ="CountService" >==>service android:name =".CountService"
            < intent-filter >
                < action android:name ="com.easymorse.CountService" />
            </ intent-filter >
        </ service >
5 楼 cydiaone 2012-11-22  
相当不错,当时看精通android3 ,好多没看懂的,现在差不多都懂了
4 楼 yanjin-zhu 2012-11-18  
详细
3 楼 无愧衾影 2011-11-11  
读起来明白。。。
2 楼 micoxi 2011-11-10  
相当经典,定期
1 楼 peng5047 2010-07-12  
学习了

相关推荐

    android Service 与Activity绑定

    Activity可以通过bindService()方法来与Service建立绑定关系,这种绑定方式主要用于当Activity需要与Service进行频繁交互或需要获取Service提供的接口时。绑定后,Activity可以通过返回的IBinder对象与Service进行...

    android service 源码

    总的来说,Android Service的源码学习涉及了Service生命周期、Service与客户端交互、进程通信、线程管理等多个方面。通过对这些知识点的深入理解和实践,开发者可以更好地设计和优化自己的应用程序,提升用户体验。

    Android服务端和客户端交互源码

    - **Activity与Service**:客户端通常由UI(User Interface)活动(Activity)触发服务请求,Service用于在后台执行长时间任务,如网络通信。 - **AsyncTask**:用于在非UI线程中执行耗时操作,避免阻塞主线程,...

    安卓开发观察者模式应用-一个service通知多个activity更新ui的实现

    Service与Activity之间的通信通常有以下三种方法: 1. **接口回调**:这是一种直接的通信方式,通过定义一个接口,Service在数据变化时调用接口的方法,将信息传递给Activity。Activity作为Service的观察者,实现这...

    安卓Android源码——Activity设置相同的action进行判断源码.zip

    在Android源码中,这个选择过程主要由`ActivityResolver`类和`ActivityManagerService`(AMS)完成。AMS是系统服务,负责管理所有应用程序的Activity、服务和广播接收器等。当一个Intent被广播时,AMS会使用`...

    android入门activity跳转源代码

    在Android开发中,Activity是应用程序的基本构建块,用于展示用户界面和处理用户交互。Activity跳转是Android应用中常见的操作,用于在不同的界面之间切换。本篇将详细讲解`android入门activity跳转源代码`的相关...

    Android应用源码之(Activity跳转与操作).zip

    在Android应用开发中,Activity是构成应用程序的基本组件之一,它代表了用户可见并可以与之交互的屏幕。Activity跳转与操作是Android开发者必须掌握的关键技能,涉及到Intent、生命周期、数据传递等多个方面。本资源...

    android-Service的2种应用

    本篇文章将深入探讨Service的两种主要应用:`startService`和`bindService`,并结合提供的源码分析进行详细解释。 首先,`startService`是启动一个Service的方式,它适合那些不需要与启动Service的应用组件直接交互...

    Android中Service源码下载

    在Android应用开发中,Service是四大组件之一,它在后台执行长时间运行的操作,不与用户交互。本资源提供了关于Android中Service的源码,重点展示了Service的生命周期以及如何在Service中播放音乐。通过分析和学习这...

    android 基础教程(第三版)配套源码

    5. **Intent机制**:Intent是Android系统中实现组件间通信的重要手段,源码中会展示如何创建Intent来启动Activity、Service或其他组件。 6. **数据存储**:Android提供了多种数据存储方式,如SharedPreferences、...

    AIDL Demo源码实现Activity与Service进程间通信

    AIDL(Android Interface Definition Language)是Android提供的一种工具,用于方便开发者定义服务接口,实现不同进程间的交互。本篇文章将深入探讨如何通过AIDL在Activity与Service之间进行进程间通信。 首先,...

    Android Activity生命周期Demo源码.rar

    在Android应用开发中,Activity是用户界面的基本组件,它负责展示屏幕上的内容并处理与用户的交互。Activity的生命周期是Android开发者必须深入理解的关键概念,因为它直接影响到应用的性能、资源管理和用户体验。本...

    Android简易本地音乐播放器源码,基于Android的简易本地音乐播放器源码

    10. **媒体库集成**:如果源码更进一步,可能会集成Android的MediaStore类,以系统化的方式访问设备上的音乐库,这样可以获取更丰富的音乐信息。 11. **音量控制**:使用AudioManager类来管理音量,包括媒体音量和...

    安卓Android源码——Android Launcher 源码修改可编译.zip

    6. **Android系统服务**:如Package Manager Service(PMS)用于管理应用的安装、更新和卸载,Activity Manager Service(AMS)则负责调度用户的活动和任务,这些都是与Launcher交互的关键服务。 7. **自定义启动器...

    Android源码——Activity设置相同的action进行判断源码_new_02.7z

    在Android系统中,Activity是应用程序的基本组件之一,用于与用户交互和展示界面。当我们需要根据不同的情况启动同一个Activity时,通常会通过Intent的Action属性来区分不同的启动意图。本压缩包文件提供了关于如何...

    Android Hook Activity 启动劫持

    `Android Hook Activity 启动劫持`是一种高级技术,它允许开发者利用动态代理(Dynamic Proxy)技术来拦截并控制AMS的行为,从而在不修改系统源码的情况下,实现对Activity启动流程的监控或修改。 首先,我们需要...

    service与activity之间的通信

    在Android开发中,Service和Activity是两个非常重要的组件。Service主要负责在后台执行长时间运行的任务,而Activity则作为用户交互的界面。它们之间的通信是Android应用中常见的需求,例如播放音乐、下载数据等。本...

    编写Android Service服务的一个源码例子

    在Android应用开发中,Service是四大组件之一,它在后台长时间运行,即使用户与应用程序的交互界面已经关闭。Service主要用于执行耗时的操作,如音乐播放、网络通信等。本源码例子将帮助初学者理解如何在Android项目...

Global site tag (gtag.js) - Google Analytics