Android系统java层次service实现
16lz
2021-01-26
前言:
在Android系统java层次service介绍已经安卓服务的种类,下面通过实列看如何实现各种服务!
本地服务的实现步骤:
第一步:新建一个Android工程,我这里命名为servicestudy. 第二步:修改activity_main.xml代码,我这里增加了四个按钮,代码如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/text" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello_world" /> <Button android:id="@+id/startservice" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="startService" /> <Button android:id="@+id/stopservice" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="stopService" /> <Button android:id="@+id/bindservice" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="bindService" /> <Button android:id="@+id/unbindservice" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="unbindService" /> </LinearLayout>
第三步:创建服务类,命名为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 -sMyService
连续按三次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(); } } }; @Overrideprotected 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(); } @Overridepublic 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 的管理服务。
更多相关文章
- tcping测试服务器TCP端口
- Android打电话过程
- Android中OkHttp的使用(详解)
- OkHttp学习系列二:谈谈Android中使用的坑
- 4 行代码实现 ANDROID 快速文件下载
- ART模式下dex2oat出错导致系统无法正常启动
- android 加载自定义图片并在图片上绘图
- Android中怎么启动关闭Service及功能解释 .
- Android(安卓)setBackgroundResource()/setBackgroundDrawable()