之前看到自己的手机应用突然会弹出一个提示框感到有点神奇,不知道是怎么做到的,后面才了解到是后台服务弹的。后台服务弹Toast框其实跟Activity界面差不多,下面先来看看项目SimpleJarService结构:
├── AndroidManifest.xml
├── Android.mk
├── libs
│ ├── android-support-v4.jar
│ ├── fw.jar
│ └── simple.jar
├── res
│ ├── drawable
│ │ └── common_toast_bg.xml
│ ├── drawable-hdpi
│ │ └── ic_launcher.png
│ ├── drawable-ldpi
│ ├── drawable-mdpi
│ │ └── ic_launcher.png
│ ├── drawable-xhdpi
│ │ └── ic_launcher.png
│ ├── layout
│ │ └── common_toast_custom.xml
│ ├── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ ├── values-v11
│ │ └── styles.xml
│ └── values-v14
│ └── styles.xml
└── src
└── com
└── china
└── service
├── BootReceiverBroadcast.java
├── Logger.java
├── SimpleControl.java
└── SimpleService.java
SimpleJarService项目在《在Android系统中实现AIDL 自定义对象传递》文章中有介绍,现在主要是在SimpleControl.java类实现实现弹Toast框的方法,而SimpleControl.java类是在SimpleService.java中实例化的。如下:
package com.china.service;
import android.content.Context;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.china.jar.VoiceChangedListener;
import com.chinatsp.service.R;
public class SimpleControl {
private static VoiceChangedListener changedListener;
private static Context mContext;
public SimpleControl(VoiceChangedListener voiceChangedListener, Context context){
changedListener = voiceChangedListener;
mContext = context;
}
//获取初始化后的回调实例
public static VoiceChangedListener getVoiceCallBack(){
return changedListener;
}
static long lastshowToastTime = 0;
public static void showToast(String s) {
if(Math.abs(System.currentTimeMillis() - lastshowToastTime)<3000){
return; //如果两次要求弹Toast框的时间间隔小于3秒,就不执行第二次弹框
}
Logger.d("show Toast");
View view = LayoutInflater.from(mContext.getApplicationContext())
.inflate(R.layout.common_toast_custom,
null);
WindowManager wm = (WindowManager) mContext.getApplicationContext()
.getSystemService(Context.WINDOW_SERVICE);
int width = wm.getDefaultDisplay().getWidth();
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
width / 2, ViewGroup.LayoutParams.WRAP_CONTENT);
TextView txt = (TextView) view
.findViewById(R.id.textViewToastMsg);
txt.setText(s);
txt.setLayoutParams(layoutParams);
Toast toast = new Toast(mContext.getApplicationContext());
toast.setView(view);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.setDuration(3000);
toast.show();
lastshowToastTime = System.currentTimeMillis();
}
}
package com.china.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ServiceManager;
import com.china.jar.IVoiceCallBackInterface;
import com.china.jar.IVoiceClientInterface;
import com.china.jar.StudentInfo;
import com.china.jar.VoiceChangedListener;
import com.china.jar.VoiceManager;
public class SimpleService extends Service{
private static VoiceClientInterfaceImpl mBinder;
@Override
public IBinder onBind(Intent intent) {
Logger.d();
return mBinder;//跟客户端绑定
}
@Override
public void onCreate() {
super.onCreate();
Logger.d();
if (null == mBinder){
initService();
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Logger.d();
if (null == mBinder){
initService();
}
return START_STICKY;
}
//实现AIDL的接口
private class VoiceClientInterfaceImpl extends IVoiceClientInterface.Stub{
protected RemoteCallbackList<IVoiceCallBackInterface> mRemoteCallbackList =
new RemoteCallbackList<IVoiceCallBackInterface>();
private SimpleControl control;
public VoiceClientInterfaceImpl(){
control = new SimpleControl(voiceChangedListener, SimpleService.this);//实例化SimpleControl对象
}
@Override
public void face() throws RemoteException {
Logger.d("face----excute!");//客户端调用face方法时这里会执行,会打印face----excute!
}
//注册回调
@Override
public void registerCallBack(IVoiceCallBackInterface arg0)
throws RemoteException {
Logger.d();
mRemoteCallbackList.register(arg0);
}
//注销回调
@Override
public void unRegisterCallBack(IVoiceCallBackInterface arg0)
throws RemoteException {
Logger.d();
mRemoteCallbackList.unregister(arg0);
}
//调用回调方法
private VoiceChangedListener voiceChangedListener = new VoiceChangedListener() {
@Override
public void openAppByVoice(String arg0) {
Logger.d("arg0 = " + arg0);
int len = mRemoteCallbackList.beginBroadcast();
for (int i = 0; i <len; i++) {
try {
mRemoteCallbackList.getBroadcastItem(i).openAppByVoice(arg0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
mRemoteCallbackList.finishBroadcast();
}
};
@Override
public void registerUser(StudentInfo studentInfo) throws RemoteException {
Logger.d("name = " + studentInfo.getName() + " ,age = " + studentInfo.getAge());
}
}
//初始化服务,主要是向系统注册服务
private void initService(){
Logger.d();
if (null == mBinder){
synchronized (SimpleService.class) {
if (null == mBinder){
try {
mBinder = new VoiceClientInterfaceImpl();
ServiceManager.addService(VoiceManager.NAME, mBinder);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
可以看到SimpleControl实例化放到了SimpleService类中的内部类VoiceClientInterfaceImpl中实例化,其实也可以放到onCreate()方法中实例化,由于该项目之前是用于aidl的功能实现,所以会放到VoiceClientInterfaceImpl类中实例化。
common_toast_custom.xml是自定义一个布局,用于规范Toast的大小及风格,具体如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dialogAera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/common_toast_bg"
android:clickable="true"
android:gravity="center"
android:minHeight="285.0px"
android:minWidth="871.0px"
android:orientation="horizontal">
<TextView
android:id="@+id/textViewToastMsg"
style="@style/shadowStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:singleLine="true"
android:textColor="@color/common_text_dark"
android:textSize="28sp" />
</LinearLayout>
通过发送接收广播的方式来测试showToast(String s)方法的功能。具体实现如下:
package com.china.service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class BootReceiverBroadcast extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Logger.d();
Intent service = new Intent(context, SimpleService.class);//开机启动会拉起服务SimpleService
context.startService(service);
if(intent.getAction().equals("android.intent.gunder.SimpleJar")){
//android.intent.gunder.SimpleJar属于自定义action
Logger.d(intent.getAction());
SimpleControl.getVoiceCallBack().openAppByVoice("nihao");//这里模拟调用penAppByVoice方法
SimpleControl.showToast("你好,我是Service里面的Toast!");//这里模拟调用showToast方法
}
}
}
测试结果如下:
代码参考:https://github.com/gunder1129/android-tool/tree/master/AIDLdemo/SimpleJarService