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

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

Android应用服务器OSBeanthread

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即可

时间: 2024-10-16 07:26:25

android Service Activity三种交互方式(付源码)(转)的相关文章

Service Activity三种交互方式

Service Activity三种交互方式 2012-09-09 22:52 4013人阅读 评论(2) 收藏 举报 serviceandroidimportclassthreadjava service有两种类型:       本地服务(Local Service):用于应用程序内部        远程服务(Remote Sercie):用于android系统内部的应用程序之间 前者用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线

Android service ( 一 ) 三种开启服务方法

一. Service简介 Service是android 系统中的四大组件之一(Activity.Service.BroadcastReceiver.ContentProvider),它跟 Activity的级别差不多,但不能自己运行只能后台运行,并且可以和其他组件进行交互.service可以在很多场合的应用中使用,比如播放多媒体的 时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务总 是藏在后台的. S

【转】WebView的JavaScript与本地代码三种交互方式

WebView的漏洞分析 漏洞产生的原因 最近在开发过程中遇到一个问题,就是 WebView 使用的时候,还是需要解决之前系统(4.2之前)导致的一个漏洞,虽然现在这个系统版本用户很少了,但是也不能忽视,关于这个漏洞,这里就不多做解释了,可能有的同学早就了解了,本来想写一篇文章详细介绍一下,但是网上的知识太多了,而且都很详细,就没弄了,这里大致简单明了的说几句: 漏洞产生的原因 这个漏洞导致的原因主要是因为Android中 WebView 中的 JS访问本地方法 的方式存在缺陷,我们做过交互的都

Android事件分发详解(三)——ViewGroup的dispatchTouchEvent()源码学习

package cc.aa; import android.os.Environment; import android.view.MotionEvent; import android.view.View; public class UnderstandDispatchTouchEvent { /** * dispatchTouchEvent()源码学习及其注释 * 常说事件传递中的流程是:dispatchTouchEvent->onInterceptTouchEvent->onTouchE

Android View体系(七)从源码解析View的measure流程

相关文章 Android View体系(一)视图坐标系 Android View体系(二)实现View滑动的六种方法 Android View体系(三)属性动画 Android View体系(四)从源码解析Scroller Android View体系(五)从源码解析View的事件分发机制 Android View体系(六)从源码解析Activity的构成 前言 在上一篇我们了解了Activity的构成后,开始了解一下View的工作流程,就是measure.layout和draw.measure

【Android 系统开发】CyanogenMod 13.0 源码下载 编译 ROM 制作 ( 手机平台 : 小米4 | 编译平台 : Ubuntu 14.04 LTS 虚拟机)

作者 : 韩曙亮 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/51592930 手机的两种模式 : 在下面有详细的图片示例; -- Recovery 模式 : 音量键增加 + 电源键, 长按上述组合键, 看到 "MI" 的 LOGO 后即进入 Recovery 模式; -- Fastboot 模式 : 音量键减小 + 电源键, 长按上述组合键, 看到 "FASTBOOT" 后, 即 进入 FA

Android斗地主棋牌游戏牌桌实现源码下载

本次给大家分享下Android斗地主棋牌游戏牌桌实现源码下载如下:为了节约内存资源,每张扑克牌都是剪切形成的,当然这也是当前编程的主流方法. 1.主Activity    package com.bison;            import android.app.Activity;      import android.content.pm.ActivityInfo;      import android.os.Bundle;      import android.view.Wind

Android View体系(八)从源码解析View的layout和draw流程

相关文章 Android View体系(一)视图坐标系 Android View体系(二)实现View滑动的六种方法 Android View体系(三)属性动画 Android View体系(四)从源码解析Scroller Android View体系(五)从源码解析View的事件分发机制 Android View体系(六)从源码解析Activity的构成 Android View体系(七)从源码解析View的measure流程 前言 上一篇文章我们讲了View的measure的流程,接下来我们

Android ListView动画特效实现原理及源码

Android 动画分三种,其中属性动画为我们最常用动画,且能满足项目中开发几乎全部需求,google官方包支持3.0+,我们可以引用三方包nineoldandroids来失陪到低版本.本例子中就是用属性动画实现效果. 对普通的View做动画,我们只要定义好要的动画ObjectAnimator或AnimatorSet,然后设置属性启动及可.但是,对ListView做动画应该如何.什么时候.在什么地方.对哪个View做动画属性呢? github上有成熟的listview动画包 https://gi