`

android编写Service入门用法与教程 (Local Service)&(Remote Sercie)

    博客分类:
  • AIDL
阅读更多
android编写Service入门用法与教程

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() {
        super.onDestroy();
        this.unbindService(serviceConnection);
    }
}



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


上面的示例,可以扩展为,让其他应用程序复用该服务。这样的服务叫远程(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即可。

原文出自:http://marshal.easymorse.com/archives/1564
分享到:
评论

相关推荐

    android编写Service入门_本地和远程调用参照.pdf

    在Android开发中,Service是四大组件之一,它主要用于在后台执行长时间运行的任务,不与用户界面直接交互。Service有两种主要类型:本地服务(Local Service)和远程服务(Remote Service),它们各自有不同的应用...

    Android local service demo

    本示例“Android local service demo”聚焦于本地服务(Local Service),它是Android Service的一种类型,主要处理应用内部的任务,不涉及与其他应用的交互。 服务的创建通常涉及到以下几个步骤: 1. **定义服务...

    Android service讲解文档ppt

    本讲解文档将深入探讨Local Service和Remote Service的实现与使用,以及广播接收器的重要作用。 首先,我们来看Local Service。Local Service是运行在同一个应用程序进程中的服务,主要用于处理那些不需要用户界面...

    Centos7-Systemd-Service自定义编写Service应用服务配置说明整理.docx

    CentOS 7 Systemd 服务自定义配置详解 Systemd 是 Linux 系统中的一种 init 系统,负责管理系统服务。CentOS 7 中的 systemd 服务可以自定义配置...通过编写服务配置文件和使用服务管理命令,可以轻松地管理系统服务。

    Android Local Service

    在实际的项目中,我们可以使用JUnit和AndroidX Test框架来编写Service测试。首先,创建一个测试类继承自`AndroidJUnit4`,然后使用`@RunWith(AndroidJUnit4.class)` 注解。通过`Instrumentation` 对象,可以启动和...

    Android 平台Service用法.doc

    在Android的API Demo中,通常会提供几个Service使用的示例,如LocalService。LocalService是一个后台Service,可以通过LocalServiceController.java中的Button来控制Service的启动和停止。LocalServiceBinding.java...

    Android service详解

    Service与Thread的区别在于,Thread是程序执行的基本单元,而Service是Android系统的一个组件。Thread在单独的线程中执行,不受Activity生命周期的影响,但当Activity被销毁时,若未正确管理Thread,可能导致内存...

    Local和Remote方式访问EJB

    客户端(Local或Remote)访问EJB时,需要使用JNDI(Java Naming and Directory Interface)查找EJB的引用,并通过该引用调用方法。对于Local访问,可以直接注入bean实例;对于Remote访问,需要使用`InitialContext`...

    Android Service Test

    本文将深入探讨“Android Service Test”中涉及的两个关键知识点:本地服务(Local Service)和远程服务(Remote Service)。 一、本地服务(Local Service) 本地服务是在同一个应用程序中运行的服务,主要用来在...

    localService

    在Android开发中,`LocalService` 是一个常用于在同一个应用程序内部进行组件间通信的机制。这个机制允许一个服务(Service)与应用的其他部分,如Activity或BroadcastReceiver,进行高效且安全的数据交换。在标题...

    ServiceDemo安卓服务的具体实现方法

    在Android应用开发中,服务(Service)是一种用于在后台长时间运行的任务,即使用户与应用程序的交互界面(UI)已关闭,服务仍可继续执行。ServiceDemo是安卓开发中的一个示例,它展示了如何创建和使用服务。下面...

    ANDROIDService讲稿3

    **startService与bindService同时启动的服务** - **操作**: 需同时使用`stopService`和`unbindService`。 #### Service的生命周期 Service的生命周期包括几个关键方法:`onCreate()`, `onStart()`, `onDestroy()`,...

    本地service练习,简易音乐播放器

    - **Service与后台播放**:将音乐播放逻辑放入Service,即使用户离开应用,音乐仍然可以继续播放。 - **通知栏控制**:为了使用户在后台知道音乐正在播放,可以使用Notification提供一个操作入口,让用户能够控制...

    Local Service Management Framework

    A local service management Framework .which can develop and control windows local service application

    Android经典入门教程

    - 解压下载的Android SDK到指定位置,例如在Linux系统中,一般选择/usr/opt/local。 - 如果未安装Eclipse,需要下载并安装Eclipse IDE for Java Developers。 - 在Eclipse中安装ADT插件,通过菜单栏的“帮助”→...

    Pro Android学习:Android service小例子

    这是Pro Android学习系列中Android Service部分的例子源代码。相关学习笔记见:http://blog.csdn.net/flowingflying/article/details/6212512

    Android WebView 报 Not allowed to load local resource错误的解决办法

    Android WebView 报 Not allowed to load local resource错误的解决办法 博客地址:http://blog.csdn.net/yuzhiqiang_1993/article/details/76228541

    Android底层结构-SDK_Service线程知多少.doc

    本篇文章将深入探讨Android底层结构中关于SDK Service线程的知识,包括Local Service和Remote Service的区别以及它们如何与主线程交互。 首先,当我们在Android应用中创建一个Service时,它默认是在进程的主线程...

    Android底层结构-Service线程详解

    接下来,我们将分别介绍本地`Service` (Local Service) 和远程`Service` (Remote Service) 的线程模型。 #### 三、Local Service线程模型 **Local Service**是指那些只在当前应用内部使用的`Service`。当`Service`...

Global site tag (gtag.js) - Google Analytics