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

Android Service讲解 和 aidl 实现

2016-11-10 16:46 453 查看

Android Service讲解 和 aidl 实现

代码下载 Android Service讲解 和 aidl 实现

一、Android Service

1.建立一个service

service和activity很相识,只是service在后台运行,activity在前台运行,他们都属于同一个同一个线程里,都属于UI线程,所以service和Thread是完全不一样的东西。一些耗时的操作在Service里运行也要开辟新的线程。

新建一个自己的service,只需要继承系统Service就行了,看下面代码:

public class AIDLService extends Service {
private static final String TAG = "AIDLService";
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate() called");
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand() called");
return super.onStartCommand(intent, flags, startId);

}

@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind() called");
return stub;
}

@Override
public boolean onUnbind(Intent intent) {
Log.i(TAG, "onUnbind() called");
return true;
}

@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy() called");
}


这样就建好了一个service,service建好了了,现在也并不能直接启动,也要像activity一样注册进AndroidManifest.xml中才能,运行它。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="mangues.com.aidl_service">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<service android:name=".AIDLService">
</service>
</application>

</manifest>


2、启动service

现在我们建好了service,也注册进AndroidManifest.xml中怎么才能运行他呢。

有两种方式可以运行:startService 和 bindService

这两种方式的区别:

执行startService时,Service会经历onCreate->onStartCommand。当执行stopService时,直接调用onDestroy方法。调用者如果没有stopService,Service会一直在后台运行,下次调用者再起来仍然可以stopService。

执行bindService时,Service会经历onCreate->onBind。这个时候调用者和Service绑定在一起。调用者调用unbindService方法或者调用者Context不存在了(如Activity被finish了),Service就会调用onUnbind->onDestroy。这里所谓的绑定在一起就是说两者共存亡了。

多次调用startService,该Service只能被创建一次,即该Service的onCreate方法只会被调用一次。但是每次调用startService,onStartCommand方法都会被调用。Service的onStart方法在API 5时被废弃,替代它的是onStartCommand方法。

第一次执行bindService时,onCreate和onBind方法会被调用,但是多次执行bindService时,onCreate和onBind方法并不会被多次调用,即并不会多次创建服务和绑定服务。

2.1、startService

和startActivity一样使用就行了,停止的时候直接调用stopService 就行了。

@Override
public void onClick(View view) {
Intent startIntent = new Intent(this, AIDLService.class);
switch (view.getId()){
case R.id.btn_start:
startService(startIntent);
break;
case R.id.btn_stop:
stopService(startIntent);
break;
case R.id.btn_bind:

break;
case R.id.btn_unbind:

break;

}
}


多次点击start时,看打印日志



证明了

多次调用startService,该Service只能被创建一次,即该Service的onCreate方法只会被调用一次。但是每次调用startService,onStartCommand方法都会被调用。

2.1、bindService

1.这时候绑定的service会和该activity共存亡。不会单独存在。

2.利用该种方法绑定的service可以和activity交互,不单单只是启动。

看代码:

package mangues.com.aidl_service;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

import java.util.Date;

import mangues.com.aidl.IPerson;

public class AIDLService extends Service {
private static final String TAG = "AIDLService";
private MyBinder mBinder = new MyBinder();
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate() called");
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onBind() onStartCommand");
return super.onStartCommand(intent, flags, startId);

}

@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind() called");
return mBinder;
}

@Override
public boolean onUnbind(Intent intent) {
Log.i(TAG, "onUnbind() called");
return true;
}

@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy() called");
}

class MyBinder extends Binder {

public String getMyBinder() {
Log.d(TAG, "MyBinder() called");
return new Date().getTime()+"";  //获取时间
}

}
}


利用binder 把数据传出service给activity获取到,只要写个内部类 继承Binder,通过binder写个方法 在利用onBind把这个binder return出去,activity就可以获得这个binder进而得到方法getMyBinder,获得service中数据

Activity代码:

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

private Button mBtnBind;
private Button mBtnUnBind;

private AIDLService.MyBinder myBinder;

private ServiceConnection connection = new ServiceConnection() {

@Override
public void onServiceDisconnected(ComponentName name) {
}

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder = (AIDLService.MyBinder) service;
String  time = myBinder.getMyBinder();
Log.i("MainActivity",time);
}
};

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

}

private void init(){

mBtnBind = (Button)findViewById(R.id.btn_bind);
mBtnUnBind = (Button)findViewById(R.id.btn_unbind);

mBtnBind.setOnClickListener(this);
mBtnUnBind.setOnClickListener(this);
}

@Override
public void onClick(View view) {
Intent startIntent = new Intent(this, AIDLService.class);
switch (view.getId()){
case R.id.btn_bind:
Intent bindIntent = new Intent(this, AIDLService.class);
//这里传入BIND_AUTO_CREATE表示在Activity和
//Service建立关联后自动创建Service,这会使得
//MyService中的onCreate()方法得到执行,但
//onStartCommand()方法不会执行。
bindService(bindIntent, connection, BIND_AUTO_CREATE);
break;
case R.id.btn_unbind:
unbindService(connection);
break;

}
}
}


点击开始和结束 日志如下:



看第四行:activity 获取到了service中数据

3、注销service

第一种、startService stopService

第二种、bindService unBindService

上面都好理解,那么如果我们既点击了startService按钮,又点击了bindService按钮会怎么样呢?

这个时候你会发现,不管你是单独点击stopService按钮还是unbindService按钮,Service都不会被销毁,必要将两个按钮都点击一下,Service才会被销毁。也就是说,点击Stop Service按钮只会让Service停止,点击Unbind Service按钮只会让Service和Activity解除关联,一个Service必须要在既没有和任何Activity关联又处理停止状态的时候才会被销毁。

看日志:

只执行stopService 或者 unbindService 根本没有注销



只有全部执行才会 注销



4.远程service

只要在service中注册信息中加上 android:process=”:remote” 就行了

<service android:name=".AIDLService"
android:process=":remote">
</service>


远程service有什么用呢?

远程service的作用只是重新建立一个新进程执行,可以独立出去。其他app可以调用这个service。因为是一个新的进程,所以也不能用bind来建立关联了。

可以用新的方式来建立关系就是下面要讲的aidl技术。

二、aidl实现

1.首先我建立2个app工程,通过aidl实现一个app调用另一个app的service

目录结构如下:

service提供端app



利用aidl调用service的app



2.在两个app中都建立一个文件 IPerson.aidl注意 包名 要相同

IPerson.aidl只是一个接口文件,用来aidl交互的,建立好之后gradle一下就行了,studio会自动创建需要的文件,具体什么文件你不用管,我们用不到,你在代码里可以看到



IPerson.aidl代码

package mangues.com.aidl;
interface IPerson {
String greet(String someone);
}


3.在aidl_service 中建立AIDLService

这个IPerson.Stub 就是通过IPerson.aidl 自动生成的binder 文件,你实现下,然后onBind return出去就好了,就和Android Service实现和activity交互一样。

代码:

public class AIDLService extends Service {
private static final String TAG = "AIDLService";

IPerson.Stub stub = new IPerson.Stub() {
@Override
public String greet(String someone) throws RemoteException {
Log.i(TAG, "greet() called");
return "hello, " + someone;
}
};

@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate() called");
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onBind() onStartCommand");
return super.onStartCommand(intent, flags, startId);

}

@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind() called");
return stub;
}

@Override
public boolean onUnbind(Intent intent) {
Log.i(TAG, "onUnbind() called");
return true;
}

@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy() called");
}
}


4.aidl_service MainActivity 中启动这个service

简单点就不写关闭什么的了;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent startIntent = new Intent(this, AIDLService.class);
startService(startIntent);

}


在AndroidManifest.xml注册

<service android:name=".AIDLService"
android:process=":remote">
<intent-filter>
<action android:name="android.intent.action.AIDLService" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>


作用就是把这个service暴露出去,让别的APP可以利用

android.intent.action.AIDLService 字段隐形绑定这个service,获取数据。

5.aidl_client 中绑定aidl_service service 获取数据

代码:

public class MainActivity extends AppCompatActivity {

private IPerson person;
private ServiceConnection conn = new ServiceConnection() {

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("ServiceConnection", "onServiceConnected() called");

person = IPerson.Stub.asInterface(service);
String retVal = null;
try {
retVal = person.greet("scott");
} catch (RemoteException e) {
e.printStackTrace();
}
Toast.makeText(MainActivity.this, retVal, Toast.LENGTH_SHORT).show();
}

@Override
public void onServiceDisconnected(ComponentName name) {
//This is called when the connection with the service has been unexpectedly disconnected,
//that is, its process crashed. Because it is running in our same process, we should never see this happen.
Log.i("ServiceConnection", "onServiceDisconnected() called");
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent mIntent = new Intent();
mIntent.setAction("android.intent.action.AIDLService");
Intent eintent = new Intent(getExplicitIntent(this,mIntent));
bindService(eintent, conn, Context.BIND_AUTO_CREATE);

}

public static Intent getExplicitIntent(Context context, Intent implicitIntent) {
// Retrieve all services that can match the given intent
PackageManager pm = context.getPackageManager();
List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
// Make sure only one match was found
if (resolveInfo == null || resolveInfo.size() != 1) {
return null;
}
// Get component info and create ComponentName
ResolveInfo serviceInfo = resolveInfo.get(0);
String packageName = serviceInfo.serviceInfo.packageName;
String className = serviceInfo.serviceInfo.name;
ComponentName component = new ComponentName(packageName, className);
// Create a new intent. Use the old one for extras and such reuse
Intent explicitIntent = new Intent(implicitIntent);
// Set the component to be explicit
explicitIntent.setComponent(component);
return explicitIntent;
}
}


和Android Service 中学习的调用MyBinder获取service中数据一样,这边只是吧MyBinder 改成了aidl定义的接口IPerson 本质上还是一个Binder

因为android 5.0 不允许隐形启用service 所有用getExplicitIntent转一下

好了现在看下效果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  aidl service android