`

android Service Activity三种交互方式【转】

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

Service有两种类型:

本地服务(Local Service):用于应用程序内部
远程服务(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的一些限制和规定:

android支持String和CharSequence
如果需要在aidl中使用其他aidl接口类型,需要import,即使是在相同包结构下;
android允许传递实现Parcelable接口的类,需要import;
android支持集合接口类型List和Map,但是有一些限制,元素必须是基本型或者上述三种情况,不需要import集合接口类,但是需要对元素涉及到的类型import;
非基本数据类型,也不是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即可

转载:http://yangguangfu.iteye.com/blog/699306
分享到:
评论

相关推荐

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

    以上就是Service与Activity交互的三种主要方式:通过Intent、Binder和Messenger。每种方式都有其适用的场景,开发者应根据实际需求选择合适的方法。在实际开发中,还需要注意处理线程安全、内存泄漏等问题,确保应用...

    Android Service与Activity交互

    本示例"Android Service与Activity交互"旨在演示如何在Service启动后,通过线程进行异步操作,并在完成特定任务后,通过发送广播(Broadcast)通知Activity来更新用户界面。 首先,我们需要创建一个Service,通常在...

    android中activity和service的交互

    总结来说,Android中的Activity和Service通过绑定的方式可以实现高效、灵活的交互,提供丰富的功能。开发者需要理解它们各自的生命周期,掌握绑定和解绑的时机,以及选择合适的通信机制,以保证应用的稳定性和性能。...

    android多个activity和一个service通信

    Activity代表用户界面,而Service则用于在后台执行长时间运行的任务,不直接与用户交互。在实际项目中,常常需要多个Activity与一个Service进行通信,比如本例中提到的“service在后台下载”场景。这种通信机制对于...

    Android-Service与Activity传值

    在Android应用开发中,`Service`和`Activity`是两个重要的组件。`Service`用于在后台执行长时间运行的任务,而`Activity`则负责用户界面交互。在某些场景下,我们可能需要在`Service`和`Activity`之间传递数据,比如...

    Android Activity 与Service进行数据交互详解

    总结来说,理解Activity与Service的数据交互机制是Android开发中的重要技能。通过bindService,我们可以创建强大的、动态的数据同步机制,使得后台任务与用户界面能够无缝协作,提升用户体验。同时,正确地管理...

    Service与多个Activity交互

    综上所述,Service与Activity通过Broadcast进行交互是一种常见的Android组件通信方式,它能够实现组件间的松耦合,提高代码的可维护性。在实际开发中,需要根据具体需求选择合适的方式来实现组件间的交互。

    activity service 数据交互

    在Android应用开发中,Activity和服务(Service)是两个核心组件,它们之间经常需要进行数据交互。Activity作为用户界面,提供与用户的交互,而Service则在后台执行长时间运行的任务,不依赖于用户界面。本篇文章将...

    android Service 与Activity绑定

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

    浅谈Android Activity与Service的交互方式

    本文主要探讨了四种不同的方式来实现Activity与Service之间的交互,以实现特定的功能,例如更新下载进度。 首先,通过广播交互是一种常见的方法。Service在执行任务时,比如下载,可以创建一个BroadcastReceiver,...

    Service Activity的三种交互方式(详解)

    本文将详细讲解Service与Activity的三种交互方式。 1. **通过startService()启动服务** 这种方式主要用于启动一个服务执行一次性或周期性的任务,例如上面的CountService示例。在`onCreate()`方法中,服务创建一个...

    Service向Activity传值(kotlin)

    Service用于在后台执行长时间运行的任务,而Activity则负责用户界面交互。在某些场景下,我们可能需要Service与Activity之间进行数据传递,例如本例中的“Service向Activity传值,实现Count累加的效果。定时传值”。...

    Service和Activity通过Broadcast共享数据

    "Service和Activity通过Broadcast共享数据"就是解决这种需求的一种常见方式。Broadcast(广播)是Android系统中的一个关键组件,它允许应用程序在不直接互相通信的情况下发送和接收消息。 首先,我们来了解什么是...

    Activity绑定Service(Kotlin)

    将Activity与Service绑定是一种常见的通信方式,尤其在需要在后台运行任务且需要与用户界面保持交互时。本教程将重点讲解如何在Kotlin环境中实现Activity与Service的绑定、启动、解绑以及关闭过程。 1. **Service的...

    Android开发-Activity与Service使用Messenger通信代码

    在Android应用开发中,Activity和Service是两个非常重要的组件。Activity负责用户界面的展示,而Service则用于在后台执行长时间运行的任务,不依赖用户界面。然而,在某些情况下,Activity需要与Service进行通信,...

    Android中Service与Activity之间通信的几种方式

    在本文中,我们将深入探讨两种常见的Service与Activity通信方式:通过Binder对象以及使用Messenger。 1. **通过Binder对象** Binder是Android系统提供的跨进程通信(IPC)机制,它允许不同进程间的对象互相调用...

    初识 Service(三) 演示:Service给 Activity传递消息

    2. **使用Messenger或AIDL**: 这种方式适用于需要更复杂的交互,例如Service向Activity传递数据对象。创建一个Message对象,并通过Binder接口在Service和Activity之间传递。在Service中创建一个Handler,用于处理...

    Android service 传 activity

    Service主要用于在后台执行长时间运行的操作,而Activity则是用户与应用交互的界面。在某些场景下,我们需要在Activity和Service之间进行数据交换,以便在前台的Activity更新用户界面或利用Service获取的数据来驱动...

Global site tag (gtag.js) - Google Analytics