`

android学习之service

 
阅读更多
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即可。
分享到:
评论

相关推荐

    Android学习之Service练习

    在"Android学习之Service练习"中,我们将深入探讨如何创建、启动和绑定到`Service`,以及`Service`在实际应用中的常见用途。 1. **什么是Service?** `Service` 是Android四大组件之一,用于执行长时间运行的操作...

    Android学习之Service开机启动

    ### Android学习之Service开机启动详解 #### 一、引言 在Android开发中,有时我们需要让应用程序中的某个服务(Service)在设备启动时自动运行,例如进行后台数据同步、监控某些变化等。为了实现这一需求,可以...

    android学习之Service启动1

    本篇文章将深入探讨“android学习之Service启动1”的主题,主要关注Service的启动方式及其基本用法。 首先,Service有两种启动模式:startService()和bindService()。`startService()`主要用于启动一个无需与调用者...

    android音乐播放器service学习案例

    本案例“android音乐播放器service学习案例”着重讲解如何利用Service来实现一个音乐播放器,使音乐能够在后台持续播放。 首先,我们需要了解Android Service的基础知识。Service分为两种类型:标准服务...

    Pro Android学习:Android service小例子

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

    Android学习之路——7.Service

    本篇文章将深入探讨“Android学习之路——7.Service”,分析Service的基本概念、使用方式以及常见应用场景,同时结合源码解析Service的工作原理,并提供一个实战Demo——Service_Demo。 一、Service基本概念 ...

    Music_Player_Service.rar_ANDROID 播放_Service android_android serv

    - Service是Android四大组件之一,用于在后台执行任务,如音乐播放、数据同步等。 - Service生命周期包括onCreate()、onStartCommand()、onBind()、onDestroy()等关键方法,开发者需要根据需求在这些方法中处理...

    Android实例三:学习Service

    在Android应用开发中,Service是四大组件之一,它在后台执行长时间运行的操作,不与用户交互。本实例将深入探讨如何在Android应用中使用Service,包括Service的基本概念、生命周期、启动方式以及与Activity的交互。 ...

    Android防止service多次执行startCommand

    在Android应用开发中,Service是四大组件之一,用于在后台长时间运行操作,比如播放音乐、网络通信等。然而,如果不加以控制,用户或者系统可能会多次启动同一个Service,导致不必要的资源消耗和服务的异常行为。本...

    android service 学习(下)

    ### Android Service 学习(下): 进程间通信与 AIDL 在深入探讨 Android Service 的高级用法时,我们不可避免地会接触到进程间通信(IPC)这一关键概念。由于 Android 应用程序通常在各自独立的进程中运行,因此它们...

    android中service组件自我学习练习

    在Android应用开发中,Service组件是四大组件之一,它用于在后台执行长时间运行的操作,而无需与用户交互。Service可以在用户界面关闭或者应用被切换到后台时仍然保持运行状态,这使得Service成为处理音乐播放、后台...

    android--service实例

    在Android系统中,Service是一种非常重要的组件,它用于在后台执行长时间运行的操作,即使用户离开了应用程序,Service仍能持续运行。本教程将深入探讨“android--service实例”,讲解如何创建、启动、绑定以及管理...

    Android停止Service的例程

    在Android应用开发中,Service是四大组件之一,用于在后台执行长时间运行的操作,即使用户离开了应用程序界面,Service依然可以运行。本教程将深入探讨如何正确地停止一个Android Service,同时结合源码分析其内部...

    android service 之一 (start service)

    在Android应用开发中,Service是四大组件之一,它在后台执行长时间运行的操作,不与用户交互。本篇文章将深入探讨Android中的Start Service,这是一种启动Service的方式,它关注的是任务的启动而不是用户界面的反馈...

    android service toast 01

    在Android开发中,Service是应用组件之一,它可以在后台长时间运行,即使用户界面不在活动状态。Service主要用于执行长时间运行的任务,如音乐播放、网络通信等。而`Toast`则是一种轻量级的通知方式,用于显示短暂的...

    android demo,Service服务在android中的应用源代码。

    学习这个demo,开发者可以深入理解Service的工作原理和生命周期,以及如何在实际项目中合理地使用Service组件来实现后台任务。这对于开发需要长时间运行功能的Android应用来说是至关重要的。同时,掌握Service的使用...

    Android服务Service_详解.pdf

    Android服务(Service)是Android操作系统中四个核心应用程序组件之一,其他三个分别是Activity、...通过深入学习Service组件的这些知识点,开发者可以有效地利用Service来丰富Android应用的功能和用户体验。

    android service 源码

    在学习Service源码的过程中,我们还需要关注线程模型,因为Service默认运行在主线程中,如果执行耗时操作会导致ANR(Application Not Responding)。因此,通常需要在Service中创建新的工作线程或者使用...

    Android Service深入解析Demo

    提到的"Exercise"可能是练习文件或者代码示例,通常在学习Service时,开发者会创建一个简单的Service项目,模拟启动Service,然后在另一个Activity中控制Service的启动和停止,或者绑定和解绑,以加深理解。...

Global site tag (gtag.js) - Google Analytics