第三步:创建服务类,命名为MyService.java代码如下:
package com.jalon.servicestudy;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.text.format.Time;
import android.util.Log;
public class MyService extends Service {
//定义个一个Tag标签
private static final String TAG = "MyService";
//这里定义吧一个Binder类,用在onBind()有方法里,这样Activity那边可以获取到
private MyBinder mBinder = new MyBinder();
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "start IBinder~~~");
return mBinder;
}
@Override
public void onCreate() {
Log.e(TAG, "start onCreate~~~");
super.onCreate();
}
@SuppressWarnings("deprecation")
@Override
public void onStart(Intent intent, int startId) {
Log.e(TAG, "start onStart~~~");
super.onStart(intent, startId);
}
@Override
public void onDestroy() {
Log.e(TAG, "start onDestroy~~~");
super.onDestroy();
}
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG, "start onUnbind~~~");
return super.onUnbind(intent);
}
//这里我写了一个获取当前时间的函数,不过没有格式化就先这么着吧
public String getSystemTime(){
Time t = new Time();
t.setToNow();
return t.toString();
}
public class MyBinder extends Binder{
MyService getService()
{
return MyService.this;
}
}
}
第四步:修改MainActivity.java,通过四个按键分别调用startService,stopService,bindService,unbindService。代码如下:
package com.jalon.servicestudy;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
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;
public class MainActivity extends Activity implements OnClickListener {
private static final String TAG = "MyService";
private MyService mMyService;
private TextView mTextView;
private Button startServiceButton;
private Button stopServiceButton;
private Button bindServiceButton;
private Button unbindServiceButton;
private Context mContext;
//这里需要用到ServiceConnection在Context.bindService和context.unBindService()里用到
private ServiceConnection mServiceConnection = new ServiceConnection() {
//当我bindService时,让TextView显示MyService里getSystemTime()方法的返回值
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
mMyService = ((MyService.MyBinder)service).getService();
mTextView.setText("I am frome Service :" + mMyService.getSystemTime());
}
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupViews();
}
public void setupViews(){
mContext = MainActivity.this;
mTextView = (TextView)findViewById(R.id.text);
startServiceButton = (Button)findViewById(R.id.startservice);
stopServiceButton = (Button)findViewById(R.id.stopservice);
bindServiceButton = (Button)findViewById(R.id.bindservice);
unbindServiceButton = (Button)findViewById(R.id.unbindservice);
startServiceButton.setOnClickListener(this);
stopServiceButton.setOnClickListener(this);
bindServiceButton.setOnClickListener(this);
unbindServiceButton.setOnClickListener(this);
}
public void onClick(View v) {
Log.d(TAG,"IN oNClink function!");
// TODO Auto-generated method stub
if(v == startServiceButton){
Log.i(TAG,"startServiceButton pressed!");
Intent i = new Intent();
i.setClass(MainActivity.this, MyService.class);
mContext.startService(i);
}else if(v == stopServiceButton){
Log.i(TAG,"stopServiceButton pressed!");
Intent i = new Intent();
i.setClass(MainActivity.this, MyService.class);
mContext.stopService(i);
}else if(v == bindServiceButton){
Log.i(TAG,"bindServiceButton pressed!");
Intent i = new Intent();
i.setClass(MainActivity.this, MyService.class);
mContext.bindService(i, mServiceConnection, BIND_AUTO_CREATE);
}else{
Log.i(TAG,"mServiceConnection button pressed!");
mContext.unbindService(mServiceConnection);
}
}
}
通过adb 查看MyService的打印:
logcat -s MyService
连续按三次startService按键,按三次bindService按键,分别按一次unbindService按键和一次stopService按键。
从打印可以看出一个服务可以多次start,但是onCreate只执行一次,onStart执行多次,服务只能被绑定一次。服务没有被引用后才会调用onDestory接口!
调试出现的问题:
点击按键后服务类MyService没有任何打印是因为没有在AndroidManifest.xml中注册实现的服务。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.jalon.servicestudy"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.jalon.servicestudy.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<span style="color:#cc0000;"><service android:name=".MyService" android:exported="true"></service> </span>
</application>
</manifest>
点击获取源代码
第一步:新建工程实现AIDL服务,工程名为serviceStudy。
第二步:在eclipse中在工程的src目录中新建一个包com.jalon.aidl
第三步:在新建的aidl包中新建IMyService.aidl文件,代码如下:
package com.jalon.aidl;
import com.jalon.aidl.Student;
interface IMyService {
List<Student> getStudent();
void addStudent(in Student student);
}
第四步:在aidl包中新建
Student.aidl文件,代码如下:
package com.jalon.aidl;
parcelable Student;
第五步:在aidl包中新建
Student类,Student.java,代码如下:
package com.jalon.aidl;
import java.util.Locale;
import android.os.Parcel;
import android.os.Parcelable;
public final 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() {
}
public static final Parcelable.Creator<Student> CREATOR = new
Parcelable.Creator<Student>() {
public Student createFromParcel(Parcel in) {
return new Student(in);
}
public Student[] newArray(int size) {
return new Student[size];
}
};
private Student(Parcel in) {
readFromParcel(in);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(sno);
dest.writeString(name);
dest.writeInt(sex);
dest.writeInt(age);
}
public void readFromParcel(Parcel in) {
sno = in.readInt();
name = in.readString();
sex = in.readInt();
age = in.readInt();
}
@Override
public String toString() {
return String.format(Locale.ENGLISH, "Student[ %d, %s, %d, %d ]", sno, name, sex, age);
}
}
保存后在gen目录下,com.jalon.aidl包下自动生成IMyService.java类,代码如下:
public interface IMyService extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class <span style="color:#ff6600;">Stub</span> extends <span style="color:#3366ff;">android.os.Binder</span> implements <span style="color:#33ccff;">com.jalon.aidl.IMyService</span>
{//自动生成的IPC stub子类,只需要服务实现这个stub就可以完成ipc通信
private static final java.lang.String DESCRIPTOR = "com.jalon.aidl.IMyService";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
....
}
....
}
生成的
IMyService.java如下如所示:
第六步:在com.jalon.aidlstudy包中新建MyService.java实现服务服务。需要集成Service实列话IPC通信stub类。代码如下:
package com.jalon.aidlstudy;
import java.util.ArrayList;
import java.util.List;
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;
import com.jalon.aidl.Student;
import com.jalon.aidl.IMyService;
public class MyService extends Service
{
private final static String TAG = "MyService";
private static final String PACKAGE_SAYHI = "com.jalon.aidlclient";
// private NotificationManager mNotificationManager;
private boolean mCanRun = true;
private List<Student> mStudents = new ArrayList<Student>();
//这里实现了aidl中的抽象函数
private final IMyService.Stub mBinder = new IMyService.Stub() {
@Override
public List<Student> getStudent() throws RemoteException {
synchronized (mStudents) {
return mStudents;
}
}
@Override
public void addStudent(Student student) throws RemoteException {
synchronized (mStudents) {
if (!mStudents.contains(student)) {
mStudents.add(student);
}
}
}
<span style="color:#009900;"> //在这里可以做权限认证,return false意味着客户端的调用就会失败,比如下面,只允许包名为com.example.test的客户端通过,
//其他apk将无法完成调用过程 </span>
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
String packageName = null;
String[] packages = MyService.this.getPackageManager().
getPackagesForUid(getCallingUid());
if (packages != null && packages.length > 0) {
packageName = packages[0];
}
Log.i(TAG, "onTransact: " + packageName);
if (!PACKAGE_SAYHI.equals(packageName)) {
return false;
}
return super.onTransact(code, data, reply, flags);
}
};
@Override
public void onCreate()
{
Log.i(TAG,"in MyService onCreate function!");
Thread thr = new Thread(null, new ServiceWorker(), "BackgroundService");
thr.start();
synchronized (mStudents) {
for (int i = 1; i < 6; i++) {
Student student = new Student();
student.name = "student#" + i;
student.age = i * 5;
mStudents.add(student);
}
}
// mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
super.onCreate();
}
@Override
public IBinder onBind(Intent intent)
{
Log.d(TAG, String.format("on bind,intent = %s", intent.toString()));
displayNotificationMessage("服务已启动");
return mBinder;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy()
{
mCanRun = false;
super.onDestroy();
}
private void displayNotificationMessage(String message)
{
/*
Notification notification = new Notification(R.drawable.icon, message,
System.currentTimeMillis());
notification.flags = Notification.FLAG_AUTO_CANCEL;
notification.defaults |= Notification.DEFAULT_ALL;
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, MyActivity.class), 0);
notification.setLatestEventInfo(this, "我的通知", message,
contentIntent);
mNotificationManager.notify(R.id.app_notification_id + 1, notification); */
}
class ServiceWorker implements Runnable
{
long counter = 0;
@Override
public void run()
{
// do background processing here.....
while (mCanRun)
{
Log.i(TAG, "" + counter);
counter++;
try
{
Thread.sleep(2000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
}
service只想让某个特定的apk使用,而不是所有apk都能使用,这个时候,你需要重写Stub中的onTransact方法,根据调用者的uid来获得其信息,然后做权限认证,如果返回true,则调用成功,否则调用会失败。对于其他apk,你只要在onTransact中返回false就可以让其无法调用IMyService中的方法,这样就可以解决这个问题了。
注意:一定要修改AndroidManifest.xml和实际一致不然,通信是找不到服务的,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.jalon.aidlstudy"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<span style="color:#3333ff;"><service
android:name="com.jalon.aidlstudy.MyService"
android:process=":remote"
android:exported="true" >
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<action android:name="com.jalon.aidlstudy.MyService" />
</intent-filter>
</service> </span>
</application>
</manifest>
在 AndroidManifest.xml 里 Service 元素的常见选项解释如下:
android:name ------------- 服务类名
android:label -------------- 服务的名字,如果此项不设置,那么默认显示的服务名则为类名
android:icon -------------- 服务的图标
android:permission ------- 申明此服务的权限,这意味着只有提供了该权限的应用才能控制或连接此服务
android:process ---------- 表示该服务是否运行在另外一个进程,如果设置了此项,那么将会在包名后面加上这段字符串表示另一进程的名字
android:enabled ---------- 如果此项设置为 true,那么 Service 将会默认被系统启动,不设置默认此项为 false
android:exported --------- 表示该服务是否能够被其他应用程序所控制或连接,不设置默认此项为 false
客户端的实现步骤
第一步:新建客户端工程,工程名aidlClient
第二步:将上面实现的com.jalon.aidl包拷贝到src目录下,保存刷新eclipse,将会在gen目录下看到生成的IMyService.java。
第三步:实现MainActivity类,代码如下:
package com.jalon.aidlclient;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import com.jalon.aidl.IMyService;
import com.jalon.aidl.Student;
public class MainActivity extends Activity implements OnClickListener {
private static final String ACTION_BIND_SERVICE = "com.jalon.aidlstudy.MyService"; //必须要和上面AndroidMainfest定义的一致
private static final String TAG = "AidlClient";
private IMyService mIMyService;
private ServiceConnection mServiceConnection = new ServiceConnection()
{
@Override
public void onServiceDisconnected(ComponentName name)
{
mIMyService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
Log.i(TAG," bind to the service onServiceConnected!");
//通过服务端onBind方法返回的binder对象得到IMyService的实例,得到实例就可以调用它的方法了
mIMyService = IMyService.Stub.asInterface(service);
try {
Student student = mIMyService.getStudent().get(0);
showDialog(student.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(this) ;
}
public void onClick(View view) {
if (view.getId() == R.id.button1) {
Log.i(TAG,"the button press!");
Intent intentService = new Intent(ACTION_BIND_SERVICE);
intentService.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainActivity.this.bindService(intentService, mServiceConnection, BIND_AUTO_CREATE);
}
}
public void showDialog(String message)
{
new AlertDialog.Builder(MainActivity.this)
.setTitle("scott")
.setMessage(message)
.setPositiveButton("确定", null)
.show();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
遇到的问题:点击后客户端程序崩溃,用logcat *:e,发现是找不到服务类,仔细确认服务类的路径和名字后问题解决!
java系统的服务都是由ServiceManager来管理的,源代码位于frameworks/base/core/java/android/os/ServiceManager.java.提供了用于管理service的addService和getService等接口。安卓的系统服务都是在frameworks/base/services/java/com/android/server/SystemServer.java 中通过ServiceManager加入到系统中的,比如:
if(FeatureOption.MTK_BT_SUPPORT)///if MTK_BT_SUPPORT is on
{
Slog.i(TAG, "Bluetooth Manager Service");
<span style="color:#3366ff;">bluetooth = new BluetoothManagerService(context);
ServiceManager.addService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE, bluetooth);</span>
if (true == FeatureOption.MTK_BT_PROFILE_SPP) {
//bluetoothSocket = new BluetoothSocketService(context, bluetooth);
//ServiceManager.addService(BluetoothSocketService.BLUETOOTH_SOCKET_SERVICE,
// bluetoothSocket);
}
if (true == FeatureOption.MTK_BT_PROFILE_MANAGER) {
BluetoothProfileManager = new BluetoothProfileManagerService(context);
ServiceManager.addService(BluetoothProfileManagerService.BLUETOOTH_PROFILEMANAGER_SERVICE,
BluetoothProfileManager);
}
}//MTK_BT_SUPPORT
}
将蓝牙相关服务加入到系统。
当服务已经加入ServiceManager后,若后面需要使用服务时,只需要通过ServiceManager获取就可了,列如:
mHdmiManager = IMtkHdmiManager.Stub.asInterface(ServiceManager
.getService(Context.MTK_HDMI_SERVICE));
MTK平台获取HDMI 的管理服务。