android ServiceManager
2017-05-14 本文已影响146人
京生京世
之前使用Android绑定服务的功能,每次使用的时候都不是很方便,因为是异步的,代码也比较多,我现在想用同步的方式去调用服务的方法,一是代码少,二是调用方便。
之前尝试先绑定服务,然后保留得到的服务接口对象,可是事与愿违,服务接口对象永不了多久就断开连接了。翻看了TelephonyManager代码,里面保存IBinder对象,于是就尝试保存服务的IBinder对象,需要调用服务的方法时通过IBinder对象去获取服务对象接口,测试之后没问题。
ServiceManager
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.IBinder;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
/**
* 本地服务和远程服务的管理器。
* 更加便捷的调用服务,以一种同步的方法去调用服务方法,
* 调用之前需要先做好前提工作,之后就可以以同步的方式去调用服务方法
* Created by 徐仕海 on 2017/5/13.
*/
public class ServiceManager {
private static ServiceManager instance;
/**
* 线程安全的到懒汉单例模式
*
* @return
*/
public static ServiceManager getDefault() {
ServiceManager tmp = instance;
if (tmp == null) {
synchronized (ServiceManager.class) {
instance = tmp = new ServiceManager();
}
}
return tmp;
}
private Map<String, IBinder> cache = new Hashtable<>();//线程安全的Map
/**
* 添加动作为action的服务(IBinder)到cache中
* 添加成功后便可以一直以同步的方法去调用服务方法。
* 保存的IBinder对象不会像保存服务的接口对象会常常死掉。
* 以后每次使用服务的方法时声称一次服务的接口就可以了,方便又安全。
*
* @param context
* @param action
*/
public void addService(final Context context, final String action) {
if (isIBinderEnabled(action))
return;
Intent intent = getExplicitIntent(context, new Intent(action));
if (intent == null)
return;
boolean ret = context.bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
cache.put(action, service);
context.unbindService(this);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}, Context.BIND_AUTO_CREATE);
}
/**
* 获取显式的Intent,android5.0之后绑定服务只能是显式Intent不能用隐式Intent.
*
* @param context
* @param implicitIntent
* @return
*/
private 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;
}
/**
* 获取action对应的服务的IBinder对象,这种对象可以用来生成可以直接使用的服务接口对象
*
* @param action
* @return
*/
public IBinder getService(String action) {
return cache.get(action);
}
/**
* 判断action对应的远程服务的IBinder是否可用
*
* @param action
* @return
*/
public boolean isIBinderEnabled(String action) {
IBinder localBinder = getService(action);
return localBinder != null && localBinder.isBinderAlive();
}
}
DeviceManager
import android.content.Context;
import com.math.IMathAidlInterface;
/**
* Created by Administrator on 2017/5/13.
*/
public class DeviceManager extends ServiceManager {
private static DeviceManager instance;
/**
* 线程安全的到懒汉单例模式
*
* @return
*/
public static DeviceManager getDefault() {
DeviceManager tmp = instance;
if (tmp == null) {
synchronized (DeviceManager.class) {
instance = tmp = new DeviceManager();
}
}
return tmp;
}
/**********************************************************************************************************************/
final String ACTION_MATH = "com.math";
public void addMathService(Context context) {
addService(context, ACTION_MATH);
}
/**
* 将action对应的远程服务转换成可用的IInterface
*
* @return
*/
public IMathAidlInterface getIMath() {
return IMathAidlInterface.Stub.asInterface(getService(ACTION_MATH));
}
}
使用方法
findViewById(R.id.tv_name).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
IMathAidlInterface iMathAidlInterface = DeviceManager.getDefault().getIMath();
try {
Toast.makeText(MainActivity.this, "" + iMathAidlInterface.add(1, 33), Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
DeviceManager.getDefault().addMathService(this);