Android 系统开发提供Api供三方应用(四、实现系统回调)
经过第二章与第三章的内容,我们已经实现了,应用层封装sdk去调用framework的层的方法了,但是我们还会经常遇到另外一种情况,就是类似监听的功能,比如我想监听framework里面某一些参数的变化,那么想实现这个功能就需要写一个回调函数。
在正常应用层开发的时候我们说想实现这个功能就是定义一个接口就可以了,那么在framework中其实我们也需要一个接口,只不过这个接口不是java类,一定是一个aidl文件。好的直接上代码。
(1)、创建ILookCallBack.aidl文件,在里面写一个回执的方法,valueChange,代码如下
package android.hytera.wp;
interface ILookCallBack {
void valueChange(String changeValue);
}
代码很简单,就是想监听或者一个值,编写完成之后我们还是打开frameworks/base/Android.mk文件然后添加
LOCAL_SRC_FILES += \
core/java/android/htyera/wp/ILookCallBack .aidl \
(2)修改我们ILookMessage.aidl文件,添加一个注册监听的方法,与一个解除监听的方法,代码如下
// ILookMessage.aidl
package android.hytera.wp;
import android.hytera.wp.ILookCallBack;
interface ILookMessage {
void setValue(String message);
String getValue();
void registerCallBack(in ILookCallBack callback,long num);
void unRegisterCallBack(in ILookCallBack callback,long num);
}
这里面需要注意的地方就是引包,因为aidl文件不像java文件,直接就报错,我们能看到,这个地方一定要把import android.hytera.wp.ILookCallBack;的包引进来,在注册与解除注册的时候我添加了一个long num的参数,这个后面逻辑需要用到。具体在细说。
(3)、修改我们的manager的方法,里面添加两个方法,一个是注册监听的方法,一个是解除注册监听的方法,直接上全一点的代码,具体代码含义看注释。
package android.hytera.wp;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
import android.os.ServiceManager;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class LookMessageManager {
private static String TAG = "hty_wp_LookMessageManager";
private ILookMessage mService;
private static LookMessageManager mInstance = null;
private List<ILookCallBack> listeners = new ArrayList<ILookCallBack>();//避免一个对象重复添加
private HashMap<ILookCallBack,ILookCallBack> listeners2 = new HashMap<>();//保存对象
private CallBack mClassBace;
public LookMessageManager() {
mService = ILookMessage.Stub.asInterface(ServiceManager.getService(Context.LOOK_MESSAGE_WP));
}
public static synchronized LookMessageManager getInstance() {
Log.e(TAG, "get mInstance.");
if (mInstance == null) {
synchronized (LookMessageManager.class) {
if (mInstance == null) {
mInstance = new LookMessageManager();
}
}
}
return mInstance;
}
public void setValue(String message) {
try {
mService.setValue(message);
} catch (RemoteException e) {
Log.e(TAG, "setValue fail.");
}
}
public String getValue() {
try {
return mService.getValue();
} catch (RemoteException e) {
Log.e(TAG, "getValue fail.");
return "";
}
}
public void registerCallBack(ILookCallBack callback) {
try {
Log.e(TAG, "register calss"+callback.hashCode());
if(listeners!=null&&listeners.contains(callback)){
Log.e(TAG, "register is have");//改监听已经被注册,防止同一个监听注册多次
}else{
CallBack callBack1 = new CallBack(callback);
listeners.add(callback);
listeners2.put(callback,callBack1);
mService.registerCallBack(callBack1,callBack1.hashCode());
}
} catch (RemoteException e) {
Log.e(TAG, TAG + "add ILookCallBack " + e.toString());
}
}
public void unRegisterCallBack(ILookCallBack callback) {
try {
if(listeners!=null&&listeners.contains(callback)){
listeners.remove(callback);
//根据保存的hashcode来解除绑定
mService.unRegisterCallBack(listeners2.get(callback),listeners2.get(callback).hashCode());
listeners2.remove(listeners2.get(callback));
}else{
Log.e(TAG, "no have this linister ");
}
} catch (RemoteException e) {
Log.e(TAG, TAG + "add ILookCallBack " + e.toString());
}
}
//回调接口实现类,aidl对应文件必须要这样的实现
private static final class CallBack extends ILookCallBack.Stub {
private Handler mHandler = null;
private ILookCallBack mListeners;
public CallBack(ILookCallBack listeners) {
mHandler = new Handler(Looper.getMainLooper());
this.mListeners = listeners;
}
@Override
public void valueChange(final String packagename) throws RemoteException {
this.mHandler.post(new Runnable() {
@Override
public void run() {
try {
mListeners.valueChange(packagename);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
}
}
因为我们这样通过aidl绑定的service,因此我们这边传过去的callback到service里面接到的callback的不是一个对象,所以我们通过一个hashcode进行存储,方便解除监听的时候使用。
(4)修改service对应的代码,添加注册监听跟解除注册监听的方法,这里面用了一个hashmap进行注册监听的保存,方便应用层多处进行注册,所以在使用解除监听的时候,也需要找到对应的解除监听的对象。
package android.hytera.wp;
import android.os.RemoteException;
import android.provider.Settings;
import android.content.Context;
import android.util.Log;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* this is my SecondService for system
* test aidl file
*/
public class LookMessageService extends ILookMessage.Stub {
private static String TAG = "hty_wp_LookMessageService";
public String value = "I am a value";
private Context mContext;
private HashMap<Long,ILookCallBack> listeners = new HashMap<>();
public LookMessageService(Context mContext){
this.mContext=mContext;
}
@Override
public void setValue(String message) throws RemoteException {
this.value = message;
//因为我们没有什么监听的内容,就把每次传过来的值,监听回调给应用层了,由于可能出现多个地方监听所以遍历一下。
for (ILookCallBack back:listeners.values()) {
back.valueChange(“值已经变化了”+value);
}
}
@Override
public String getValue() throws RemoteException {
int time=0;
try {
time=Settings.System.getInt(mContext.getContentResolver(),
Settings.System.SCREEN_OFF_TIMEOUT);
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
}
return time+"";
}
@Override
public void registerCallBack(ILookCallBack callback,long num) throws RemoteException {
listeners.put(num,callback);
}
@Override
public void unRegisterCallBack(ILookCallBack callback,long num) throws RemoteException {
listeners.remove(num);//由于传过来的callback根本不是对应注册的callback对象所以用一个long的hashcode进行了一下解除
}
}
(5)修改应用层的接口类兵器添加一个监听接口
package android.hytera.wp;
public class LookMessageManager {
private static String TAG = "hty_wp_LookMessageManager";
private static LookMessageManager mInstance = null;
public static synchronized LookMessageManager getInstance() {
throw new RuntimeException("API not supported!");
}
public void setValue(String message) {
throw new RuntimeException("API not supported!");
}
public String getValue() {
throw new RuntimeException("API not supported!");
}
public void registerCallBack(ILookCallBack callback) {
throw new RuntimeException("API not supported!");
}
public void unRegisterCallBack(ILookCallBack callback) {
throw new RuntimeException("API not supported!");
}
}
package android.hytera.wp;
public interface ILookCallBack {
void valueChange(String changeValue);
}
这里的ILookCallBack.java一定要对应framework里面的ILookCallBack.aidl文件;
(6)代码调用
public class MainActivity extends AppCompatActivity {
private Button getValue;
private Button setValue;
private Button setLinister;
private Button cancleLinister;
private Linister linister;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initView();
getValue.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e("hty_wp", LookMessageManager.getInstance().getValue() + "");//获取value
}
});
setValue.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LookMessageManager.getInstance().setValue("我要变化");//设置value
}
});
linister=new Linister();
setLinister.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//注册监听
LookMessageManager.getInstance().registerCallBack(linister);
}
});
cancleLinister.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//解除监听
LookMessageManager.getInstance().unRegisterCallBack(linister);
}
});
}
//监听方法,打印一下返回的值
public class Linister implements ILookCallBack{
@Override
public void valueChange(String changeValue) {
Log.e("hty_wp_listener_change", changeValue);//获取value
}
}
public void initView() {
setContentView(R.layout.activity_main);
getValue = findViewById(R.id.getValue);
setValue = findViewById(R.id.setValue);
setLinister = findViewById(R.id.setLinister);
cancleLinister = findViewById(R.id.cancleLinister);
}
}
我们经常遇到的情况大致都完事了,第一就是我们去调用framework层的方法接口完成,第二就是回调接口也完成,接下来就是看具体项目需要实现一些业务了。
看着文档可能有点蒙圈,运行一下代码,可能就清晰了,无非就是几个类,
调用系统方法的时候需要三个类,一个是接口aidl文件,一个是manager管理类,一个是service实现类,service实现了aidl的方法,然后通过manager透出来外部可以调用的接口。
如果需要回调在加一个回调监听的callback.aidl的文件,最多就这么四个类,基本就实现了,应用层与framework的通信。应用层可以根绝自己需要把这些sdk接口封装一下。