Android Activity与远程Service的通信学习总结

当一个Service在androidManifest中被声明为 process=":remote", 或者是还有一个应用程序中的Service时,即为远程Service, 远程的意思是和当前程序不在同一个进程中执行。

Activity和远程Service的跨进程通信(IPC)通过Binder机制,使用AIDL服务实现。

一.  定义远程服务端

1.新建一个project,project文件夹例如以下

2. 文件内容

aidl传递复杂对象时,须要该对象实现Parcelable或Serializable接口,并在aidl文件里声明

Student.java

package com.example.aidl;

import java.util.Locale;

import android.R.integer;
import android.os.Parcel;
import android.os.Parcelable;

public class Student implements Parcelable {

	public static final int SEX_MALE = 1;
    public static final int SEX_FEMALE = 2; 

	public int sno;
	public String name;
	public int sex;
	public int age;

	public Student() {
	}

	private Student(Parcel in) {
		readFromParcel(in);
	}

	public void readFromParcel(Parcel in) {
		sno = in.readInt();
		name = in.readString();
		sex = in.readInt();
		age = in.readInt();
	}

	@Override
	public void writeToParcel(Parcel dest, int flags) {
       dest.writeInt(sno);
       dest.writeString(name);
       dest.writeInt(sex);
       dest.writeInt(age);
	}

	public static final Parcelable.Creator<Student> CREATOR = new Parcelable.Creator<Student>() {

		@Override
		public Student createFromParcel(Parcel in) {
			return new Student(in);
		}

		@Override
		public Student[] newArray(int size) {
			return new Student[size];
		}
	};

	@Override
	public int describeContents() {
		return 0;
	}

	@Override
    public String toString() {
        return String.format(Locale.ENGLISH, "Student[ %d, %s, %d, %d ]", sno, name, sex, age);
    } 

}

Student.aidl

package com.example.aidl;

parcelable Student;

IService.aidl

package com.example.aidl;

import com.example.aidl.Student;

 interface IMyService{

    List<Student> getStudent();
    void addStudent(in Student student); //in标记为输入类型
  }

然后再写远程服务类StudentService.java

package com.example.remote_service;

import java.util.LinkedList;
import java.util.List;

import com.example.aidl.IMyService;
import com.example.aidl.Student;

import android.R.integer;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;

public class StudentService extends Service {

	private static final String TAG = "StudentService";

	private static final String PACKAGE_PEMISSION = "com.yjq.service";  

	private LinkedList<Student> studentList = new LinkedList<Student>();

	@Override
	public IBinder onBind(Intent intent) {
		Log.d(TAG, String.format("on bind,intent = %s", intent.toString()));
		return mBinder;
	}

	   //继承由AIDL生成的抽象类
//	实现aidl里的接口的方法 ,以供调用
	//这里实现了aidl中的抽象函数
    private final IMyService.Stub mBinder = new IMyService.Stub() { 

		@Override
		public List<Student> getStudent() throws RemoteException {
			return studentList;
		}

		@Override
		public void addStudent(Student student) throws RemoteException {
			if (student != null) {
				synchronized (studentList) {
					studentList.add(student);
				}
			}
		}		

		//在这里能够做权限认证。return false意味着client的调用就会失败,比方以下。仅仅同意包名为 PACKAGE_PEMISSION 的client通过,
        //其它apk将无法完毕调用过程
		@Override
        public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
                throws RemoteException {
            String packageName = null;
            String[] packages = StudentService.this.getPackageManager().
                    getPackagesForUid(getCallingUid());
            if (packages != null && packages.length > 0) {
                packageName = packages[0];
            }
            Log.d(TAG, "onTransact: " + packageName);
            if (!PACKAGE_PEMISSION.equals(packageName)) {
                return false;
            }
            return super.onTransact(code, data, reply, flags);
        }  

	};

	@Override
	public void onCreate() {
		super.onCreate();
	    Log.d(TAG, "student服务创建");

	    synchronized (studentList) {
            for (int i = 1; i < 6; i++) {
                Student student = new Student();
                student.name = "student#" + i;
                student.age = i * 5;
                studentList.add(student);
            }
        }  

	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
                Log.d(TAG, "student服务启动");
		return super.onStartCommand(intent, flags, startId);
	}

	@Override
	public void onDestroy() {
		Log.d(TAG, "student服务结束");
		super.onDestroy();
	}

}

Stub这个内部类是一个实现了IMyService接口的Binder抽象类

onTransact()是通过应用程序的包名来限制权限的,通过验证的程序才干绑定。 同意绑定的client程序 的包名。可在client的androidManifist中查看。

并注意在androidManifest中声明

<service
    android:name="com.example.remote_service.StudentService"
    android:process=":remote"
    >
    <intent-filter >
        <!-- 这里的action是隐式bindService时用到的  -->
        <action  android:name="com.example.remoteservice" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>  

</service> 

要声明action以供隐式bindService

二. 本地Activity怎样绑定远程Service

新建一个项目作为绑定远程Service的client,将上面的aidl所在包拷贝到src中,注意整个包名和文件名称都要全然一样,否则无法远程绑定

再写MainActivity.java来进行绑定操作

package com.yjq.local_service;

import java.util.List;

import com.example.aidl.IMyService;
import com.example.aidl.Student;
import com.yjq.local_service.MyService.MyBinder;
import com.yjq.service.R;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;

public class MainActivity extends Activity {

	private static final String TAG = "MainActivity_local";

//绑定远程Service的action
	public static final String BIND_REMOTE_SERVICE_ACTION = "com.example.remoteservice";

	// 远程服务 , 服务的类是在aidl中定义的
	private IMyService mRemoteService;

	private Button bindRemoteServiceButton;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		bindRemoteServiceButton =(Button)findViewById(R.id.bind_remote_service);

                              bindRemoteServiceButton.setOnClickListener( new OnClickListener() {
			@Override
			public void onClick(View v) {
				bindRemoteService();
			}
		});
	}

	/**
	 * 创建并绑定远程Service
	 * */
	private void bindRemoteService() {
		Intent intentService = new Intent(BIND_REMOTE_SERVICE_ACTION);
		intentService.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		bindService(intentService, remoteServiceConnection, BIND_AUTO_CREATE);
	}

	/**
	 * 绑定远程服务的ServiceConnection类
	 */
	ServiceConnection remoteServiceConnection = new ServiceConnection() {

		@Override
		public void onServiceDisconnected(ComponentName name) {
			mRemoteService = null;
		}

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			mRemoteService = IMyService.Stub.asInterface(service);

			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						List<Student> students = mRemoteService.getStudent();
						for (Student s : students) {
							System.out.println("远程调用: " + s.toString());
						}
					} catch (Exception e) {
						// TODO: handle exception
					}
				}
			}).start();

		}
	};

	@Override
	protected void onDestroy() {
		unbindService(remoteServiceConnection);
		super.onDestroy();
	}

}

activity中通过

bindService(intentService, remoteServiceConnection, BIND_AUTO_CREATE);

来绑定远程Service

实现接口的几条说明:

*不会有返回给调用方的异常

*默认IPC调用是同步的。假设已知IPC服务端会花费非常多毫秒才干完毕,那就不要在Activity或View线程中调用,否则会引起应用程序挂起(Android可能会显示“应用程序未响应”对话框),所以上面创建了一个Thread来运行

*AIDL接口中仅仅支持方法,不能声明静态成员。

并且。当调用结束时,应该使用

		unbindService(remoteServiceConnection);

来解除绑定,否则会造成内存泄漏

三. 执行測试 

先安装服务端的程序,再执行client程序。点击绑定button,即看到结果

08-20 22:49:48.447: I/System.out(1319): 远程调用: Student[ 0, student#1, 0, 5 ]
08-20 22:49:48.457: I/System.out(1319): 远程调用: Student[ 0, student#2, 0, 10 ]
08-20 22:49:48.457: I/System.out(1319): 远程调用: Student[ 0, student#3, 0, 15 ]
08-20 22:49:48.457: I/System.out(1319): 远程调用: Student[ 0, student#4, 0, 20 ]
08-20 22:49:48.457: I/System.out(1319): 远程调用: Student[ 0, student#5, 0, 25 ]

Demo下载: http://download.csdn.net/detail/guige_csdn/9032089

四. 在android中的应用

摘自:http://blog.csdn.net/u011485531/article/details/12073647

以下我们就讲一个挂断电话的样例,我们知道。Android的api里面是没有挂断电话的操作的

那假设我们的应用就有这样一个需求呢,那怎么办

能够通过java的反射来实现。也能够通过aidl来实现,以下介绍aidl的方法

首先,我们先把两个aidl文件拷贝到src文件夹以下

你肯定会问,这些aidl文件是在那里找到的,那么我能够告诉你,这些是Android的源代码里面找到的,就是在base这个以下的

大家能够下载下来看看。假设有不会的,请看点击这里

既然把aidl文件拷贝过去之后。我们就能够写代码啦

com.xiaobin.endcall.MainActivity

[java] view
plain
copy

  1. package com.xiaobin.endcall;
  2. import java.lang.reflect.Method;
  3. import com.android.internal.telephony.ITelephony;
  4. import android.app.Activity;
  5. import android.os.Bundle;
  6. import android.os.IBinder;
  7. import android.view.View;
  8. public class MainActivity extends Activity
  9. {
  10. @Override
  11. public void onCreate(Bundle savedInstanceState)
  12. {
  13. super.onCreate(savedInstanceState);
  14. this.setContentView(R.layout.main);
  15. }
  16. public void click(View v)
  17. {
  18. endCall();
  19. }
  20. //挂断电话
  21. private void endCall()
  22. {
  23. try
  24. {
  25. //通过反射拿到android.os.ServiceManager里面的getService这种方法的对象
  26. Method method = Class.forName("android.os.ServiceManager").getMethod("getService", String.class);
  27. //通过反射调用这个getService方法,然后拿到IBinder对象,然后就能够进行aidl啦
  28. IBinder iBinder = (IBinder) method.invoke(null, new Object[] {TELEPHONY_SERVICE});
  29. ITelephony telephony = ITelephony.Stub.asInterface(iBinder);
  30. telephony.endCall();
  31. }
  32. catch (Exception e)
  33. {
  34. e.printStackTrace();
  35. }
  36. }
  37. }

由于那个服务没有公开的,所以我们就要用到反射来调用这个服务,来拿到Binder对象

还有重要的一点喔,要加上对应的权限。不然挂不断的喔

[html] view
plain
copy

  1. <uses-permission android:name="android.permission.CALL_PHONE"/>

好啦,到这里。挂断电话的操作就完毕的啦,能够測试一下啦,然后我们手机卫士的这个项目的黑名单那里也有挂断电话的操作的喔

挂断电话的样例下载:http://download.csdn.net/detail/guige_csdn/9032239

时间: 2024-08-01 02:28:25

Android Activity与远程Service的通信学习总结的相关文章

android 中activity调用远程service中的方法之 aidl的使用

服务端:只有服务,没有界面 1.编写interface文件,复制到 .aidl 文件中,并去掉其中的public 等修饰符.系统会自动在gen目录下生成对应的java文件  (对应本地调用中的接口文件) 2.编写service,其中内部类的自定义bind 只需要继承Stub即可.(本地调用则需要继承Bind 并实现 interface接口) 1 public class PayService extends Service { 2 3 @Override 4 public IBinder onB

Android使用Messenger进行Service IPC通信分析

如果想要进行IPC通信,一般写一个AIDL接口,再写一个Service子类,然后实现AIDL接口 当做IBinder返回给Activity界面层. 如果不想写AIDL接口文件,只是单I线程中与Service进行通信 我们可以用Android写好的Messenger类来处理,一样能将消息传递给Service进行通信. 先写上基本代码: public class MyService extends Service { Messenger messenger = null; public MyServ

Android -- 跨应用绑定service并通信

之前记录过跨应用绑定service:http://blog.csdn.net/gaopeng0071/article/details/46049929,那么绑定后如何进行通信呢,下面我们就来学习下. 第一步, 需要修改service1项目中aidl,增加一个方法. package com.example.service1.aidl; interface IMyService { void basicType(); void setName(String name); } setName用于存储n

Android成长日记-Android四大组件之Service组件的学习

1.什么是Service? Service是Android四大组件中与Activity最相似的组件,它们都代表可执行的程序,Service与Activity的区别在于:Service一直在后台运行,它没有用户界面,所以绝不会到前台来.一旦Service被启动起来,它就与Activity一样.它完全具有自己的生命周期. A Service is an application component that can perform long-running operations in the back

android 远程Service以及AIDL的跨进程通信

在Android中,Service是运行在主线程中的,如果在Service中处理一些耗时的操作,就会导致程序出现ANR. 但如果将本地的Service转换成一个远程的Service,就不会出现这样的问题了. 转换成远程Service非常简单,只需要在注册Service的时候将他的android:process的属性制定成 :remote就可以了. 重新运行项目,你会发现,不会出现ANR了. 为什么将MyService转换成远程Service后就不会导致程序ANR了呢?这是由于,使用了远程Serv

Android 两种启动Service(远程)的方式:Bind 与Start

前言:本文主要讨论启动远程Service. Service和Activity不在一个工程里面,也即不在一个App里面.不在一个进程里,所以会用到AIDL. Service的android:process属性未指定. 一.startService 1.通过调用startService启动服务的过程: onCreate ->onStartCommand ->onStart startService 仅用于启动服务,如果Activity需要与Service进行通信,需利用Broadcast. 2.而

Android基础笔记(十一)- Service基础和注意事项以及Activity与Service的通信

Service的基本概念 为什么要有Service Service的基本用法 电话窃听器的小案例 Service和Activity通信 Service和Thread的关系 向光明而行! Service的基本概念 Service是Android的四大组件之一,在每一个应用程序中都扮演者非常重要的角色. 它主要用于在后台处理一些耗时的逻辑,或者去执行某些需要长期运行的任务.必要的时候,我们甚至可以在程序退出的情况下,让Service在后台继续保持运行状态. 既然都是被用于处理耗时的操作,那么我们什么

Android:(本地、可通信的、前台、远程)Service使用全面介绍

前言 Service作为Android四大组件之一,应用非常广泛 本文将介绍Service最基础的知识:Service的生命周期 如果你对Service还未了解,建议先阅读我写的文章: Android四大组件:Service史上最全面解析 目录 1. Service分类 1.1 Service的类型 1.2 特点 2.具体使用解析 2.1 本地Service 这是最普通.最常用的后台服务Service. 2.1.1 使用步骤 步骤1:新建子类继承Service类 需重写父类的onCreate()

Android Service IPC通信之Messenger机制

概述 之前我写过一篇博客介绍Service:Android Service全面解析,里面讲过如何实现Service的跨进程(IPC)通信,主要是通过编写AIDL接口文件来实现的.本篇我们来讲讲Service IPC通信的另外一种方式-Messenger. Messenger,也称为信使,通过它可以在不同的进程间传递message对象,在message中放入我们需要传递的数据你就可以实现跨进程通信和传递数据了.所以说Messenger机制是基于消息的跨进程通信方式. 可以看到,我们可以在客户端发送