您的位置:首页 > 移动开发 > Android开发

Android系统java层次service实现

2015-01-27 16:10 176 查看

前言:

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 -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 的管理服务。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: