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

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

分享到:
评论
4 楼 Vin-G 2011-06-17  
我也正在学习中啊!!不明白啊!望请教
3 楼 super_smooth 2011-03-26  
请教!
"编写传递复杂数据类型的远程服务"这部分可以写的更详细些么?!

CountService.java具体应该怎么修改?
int count;
需要修改为CountBean count;么?
count++;需要修改么?

2 楼 pc125864418 2011-03-20  
有压缩包吗?让我在自己的机器上跑下看看吧
1 楼 pc125864418 2011-03-20  
写的这么好怎么没人赞呢。。。。   

相关推荐

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

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

    android开发快速入门教程

    《Android开发快速入门教程》是一本专为有一定Java基础的学习者设计的指南,旨在帮助他们迅速掌握Android应用开发的基本技能。在本教程中,我们将深入探讨Android开发环境的配置、新项目的创建以及如何导出APK安装包...

    android开发入门教程PDF(两部)

    这两部PDF教程,"Android开发入门教程"和"Android手机程序电子书开发",都是针对初学者精心编写的指南,旨在帮助他们快速理解和掌握Android应用开发的基础知识。 首先,"Android开发入门教程"可能涵盖了以下几个...

    Android开发入门与实战 第二版 源码 最新更新

    Android开发中,经常使用到诸如Glide(图片加载库)、Retrofit(网络请求库)、Butter Knife(视图绑定库)等第三方库,理解它们的工作原理和使用方法能提高开发效率。 《Android开发入门与实战 第二版》附带的源码...

    Android从入门到精通经典教程

    《Android从入门到精通经典教程》是一套全面且深入的学习资源,旨在帮助初学者和有一定基础的开发者系统地掌握Android应用开发技术。本教程涵盖了从基础概念到高级特性的广泛内容,结合实际案例,使学习者能够快速...

    android开发入门与实践体验-光盘代码

    在Android开发领域,入门与实践是提升技能的关键步骤。"Android开发入门与实践体验-光盘代码"提供了宝贵的资源,帮助初学者通过实际操作来学习Android应用开发。这本书的代码部分旨在让读者深入理解Android应用的...

    Android编程入门教程word集合

    【Android编程入门教程word集合】 本教程集合是针对想要学习Android编程初学者的一份宝贵资源,涵盖了从基础知识到深入实践的多个方面。Android是全球最流行的智能手机操作系统,开发者可以通过编写应用程序来实现...

    Android开发从入门到精通.pdf

    《Android开发从入门到精通》是一本专门为Android编程新手量身打造的教程。这本书全面覆盖了Android开发的基础知识,旨在帮助读者快速掌握Android应用开发的核心技能。以下是对书中的主要知识点进行的详细解读: 1....

    android开发从入门到精通光盘源代码

    开发者使用Java或Kotlin语言编写应用程序,通过Android Studio集成开发环境进行开发。 1. **环境搭建**:开始Android开发前,需要安装Android Studio,它包含了Android SDK、模拟器以及各种工具,能提供代码编辑、...

    android入门快速入门第一天

    理解这些生命周期方法,如onCreate()、onStart()、onResume()、onPause()、onStop()和onDestroy(),并学会在适当的时候执行相应操作,是编写高效、稳定应用的关键。 7. **资源管理**:Android应用中包含许多资源,...

    Android studio 入门教程

    - 探索各种UI组件,如TextView、EditText、ImageView等,以及使用方法。 - 学习使用动画库实现过渡、滑动、旋转等视觉效果。 10. **测试与发布**: - 编写单元测试和UI测试,使用JUnit和Espresso框架。 - 配置...

    Android应用开发入门教程(经典版)&android;快速入门

    通过阅读《Android应用开发入门教程(经典版)》和《Android快速入门》这两本书,你可以逐步掌握上述知识点,从而构建自己的第一个Android应用。在实践中不断学习和迭代,你将逐渐成长为一名熟练的Android开发者。记住...

    Android从入门到精通源代码 孙更新.rar

    《Android从入门到精通源代码 孙更新》是一份针对初学者和进阶开发者精心编写的资源包,旨在帮助读者全面掌握Android应用开发的核心技术。这份资料由知名Android讲师孙更新提供,通过深入浅出的讲解和实际源代码示例...

    Android开发入门实战教程

    【Android开发入门实战教程】 Android开发是当今移动应用开发领域中的一个重要组成部分,尤其对于想要进入这个领域的初学者来说,掌握Android开发的基本技能至关重要。本教程将带你深入理解Android开发的基础知识,...

    Google Android开发入门与实战.(配书源码)

    在Android开发领域,Google Android开发入门与实战是一本颇受欢迎的书籍,旨在引导初学者进入Android应用开发的世界。这本书由靳岩和姚尚朗合著,由人民邮电出版社出版,提供了丰富的实例和源代码来辅助学习。由于...

    Android移动开发入门与进阶 源代码

    《Android移动开发入门与进阶》是一本专为Android初学者和有一定经验的开发者设计的教程书籍,其源代码提供了一手的实践材料,帮助读者深入理解和应用Android开发技术。以下将详细介绍书中涵盖的一些关键知识点。 1...

    android开发入门与实践

    在Android开发领域,入门与实践是每位开发者必须要经历的过程。Android是一种开源的移动操作系统,由Google主导,并由开放手机联盟支持。它广泛应用于智能手机、平板电脑以及智能电视等多种设备上。本教程将针对2、3...

    android开发入门教程

    Android开发入门教程是针对想要学习Android应用程序开发的初学者精心准备的一份教程。这份教程将带你逐步走进Android的世界,理解其基本概念、开发环境搭建、编程语言基础以及应用的生命周期管理,直至完成一个简单...

    Android从入门到精通 经典教程

    接着,教程会详细介绍Android的开发工具Android Studio的使用,包括创建项目、编写代码、调试应用等基本操作。Android Studio集成了IntelliJ IDEA,提供了强大的代码编辑、重构、性能分析等功能,对于新手来说,熟悉...

    Android开发入门教程

    【Android开发入门教程】 在移动应用开发领域,Android是最受欢迎的操作系统之一,为开发者提供了丰富的平台来构建创新的应用。这个“Android开发入门教程”旨在帮助初学者快速掌握Android应用程序开发的基础知识,...

Global site tag (gtag.js) - Google Analytics