最近公司在做一个支付组件。持续做了一个月,我做了三个版本,现在项目突然终止,我也无事可做,就想把这个项目中用到的浮动框效果拿出来,晒一晒,巩固知识的同时
也顺便帮帮有需要的人,也不失为一件乐事。
该浮动框其实挺简单,就是一个开机广播启动一个后台Service,不断的从内存中查看商城客户端启动,如果启动,就发送一个广播,运行支付组件;当商城退出时,支付组件
也退出。
先看来效果图:
(注意:该图为私人收藏图,请勿随意转载。)
下面说说过程与核心代码。
一、服务随着开机完成自动启动。
上面代码中的AppService.class是广播接收者启动的服务。
清单文件内的权限和注册。
权限
注册
getAppInfo()中的代码是从内存中获取任务栈第一个任务,然后通过ActivityManager获取到其详细信息中的name,然后判断是否为商城应用,然后再做相应的处理。
(3)、下面是两个自定义广播FloatViewStartReceiver.java 和 FloatViewStopReceiver.java
FloatViewStartReceiver比较简单,就是启动 FloatWeigtService服务
清单文件中注册:
自定义广播接收者FloatViewStopReceiver.java ,接收到广播后会停止 FloatWeigtService
在清单文件注册 FloatViewStopReceiver
(4)、下面是 负责创建浮动框的 FloatWeigtService.java ,该服务会创建和取消浮动框。FloatView
完。
也顺便帮帮有需要的人,也不失为一件乐事。
该浮动框其实挺简单,就是一个开机广播启动一个后台Service,不断的从内存中查看商城客户端启动,如果启动,就发送一个广播,运行支付组件;当商城退出时,支付组件
也退出。
先看来效果图:
(注意:该图为私人收藏图,请勿随意转载。)
下面说说过程与核心代码。
一、服务随着开机完成自动启动。
(1)、开机广播接收者代码。BootCompleteReceiver.java
public class BootCompleteReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.i("BootCompleteReceiver", "接到开机广播");
Intent iAppServiceIntent = new Intent(context, AppService.class);
context.startService(iAppServiceIntent);
}
}
上面代码中的AppService.class是广播接收者启动的服务。
清单文件内的权限和注册。
权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
注册
<receiver android:name=".receiver.BootCompleteReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
(2)、开机后启动的服务AppService.java
public class AppService extends Service {
private String TAG = "AppService";
private RunningTaskInfo info;
private static WindowManager wm;
private ActivityManager am;
private PackageManager pm;
private String actionStart = "com.handaer.receiver.FLOAT_VIEW_START_ACTION"; //自定义action名字,
private String actionStop = "com.handaer.receiver.FLOAT_VIEW_STOP_ACTION"; //自定义action名字
Handler handler = new Handler();
Timer timer = null;
TimerTask task = new TimerTask() {
public void run() {
handler.post(new Runnable() {
@Override
public void run() {
getAppInfo();
}
});
};
};
public int onStartCommand(Intent intent, int flags, int startId) {
if (timer == null) {
timer = new Timer();
timer.scheduleAtFixedRate(task, 0, 500);
}
return super.onStartCommand(intent, flags, startId);
};
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void getAppInfo() {
am = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);
pm = this.getPackageManager();
ApplicationInfo actInfo;
List<RunningTaskInfo> list = am.getRunningTasks(1);
info = list.get(0);
ComponentName cn = info.topActivity;
String name = cn.getPackageName();
try {
actInfo = pm.getApplicationInfo(name, PackageManager.GET_META_DATA);
Bundle metaData = actInfo.metaData;
Log.i(TAG, "AppService正在运行");
if (metaData != null) {
String metaValue = metaData.getString("com.handaer.newhbddemo");
if ("com.handaer.around".equals(metaValue)
|| "com.handaer.pay".equals(metaValue)) {
// 发送自定义广播 com.handaer.receiver.FLOAT_VIEW_START_ACTION
Intent intent = new Intent();
intent.setAction(actionStart);
sendBroadcast(intent);
}
} else {
// 发送自定义广播 com.handaer.receiver.FLOAT_VIEW_STOP_ACTION
Intent intent = new Intent();
intent.setAction(actionStop);
Bundle bundle = new Bundle();
sendBroadcast(intent);
}
} catch (NameNotFoundException e) {
e.printStackTrace();
}
}
}
getAppInfo()中的代码是从内存中获取任务栈第一个任务,然后通过ActivityManager获取到其详细信息中的name,然后判断是否为商城应用,然后再做相应的处理。
(3)、下面是两个自定义广播FloatViewStartReceiver.java 和 FloatViewStopReceiver.java
FloatViewStartReceiver比较简单,就是启动 FloatWeigtService服务
public class FloatViewStartReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.i("FloatViewStartReceiver", "收到启动广播");
Intent intentStart = new Intent(context, FloatWeigtService.class);
try {
context.startService(intentStart);
} catch (Exception e) {
e.printStackTrace();
}
}
}
清单文件中注册:
<receiver android:name=".receiver.FloatViewStartReceiver" >
<intent-filter>
<action android:name="com.handaer.receiver.FLOAT_VIEW_START_ACTION" />
</intent-filter>
</receiver>
自定义广播接收者FloatViewStopReceiver.java ,接收到广播后会停止 FloatWeigtService
public class FloatViewStopReceiver extends BroadcastReceiver {
private RunningServiceInfo runningServiceInfo;
private String serviceName = "com.handaer.hbdpay.service.FloatWeigtService";
@Override
public void onReceive(Context context, Intent intent) {
ActivityManager am = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
PackageManager pm = context.getPackageManager();
List<ActivityManager.RunningServiceInfo> serviceList = am
.getRunningServices(Integer.MAX_VALUE);
if (serviceList.size() == 0) {
return;
}
for (int i = 0; i < serviceList.size(); i++) {
runningServiceInfo = serviceList.get(i);
if (runningServiceInfo.service.getClassName().equals(serviceName)) {
ComponentName name = runningServiceInfo.service;
Intent i2 = new Intent();
i2.setComponent(name);
try {
context.stopService(i2);
} catch (Exception e) {
e.printStackTrace();
}
break;
}
}
}
}
在清单文件注册 FloatViewStopReceiver
<receiver android:name=".receiver.FloatViewStopReceiver" >
<intent-filter>
<action android:name="com.handaer.receiver.FLOAT_VIEW_STOP_ACTION" />
</intent-filter>
</receiver>
(4)、下面是 负责创建浮动框的 FloatWeigtService.java ,该服务会创建和取消浮动框。FloatView
public class FloatView extends LinearLayout {
private WindowManager wm;
public static int viewWidth;
public static int viewHeight;
private int screenWidth;
private int width;
private int yDown;
private int xValueInView;
private int yValueInView;
private int xInScreen;
private int yInScreen;
private WindowManager.LayoutParams params;
private ImageView iv_short;
public FloatView(Context context) {
super(context);
wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
screenWidth = wm.getDefaultDisplay().getWidth();
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.float_view, this);
iv_short = (ImageView) view.findViewById(R.id.iv_short);
width = view.getWidth();
LinearLayout deskView = (LinearLayout) view
.findViewById(R.id.ll_base_title_view);
viewWidth = deskView.getLayoutParams().width;
viewHeight = deskView.getLayoutParams().height;
}
public void updataLocation() {
params.x = (int) (xInScreen - xValueInView);
params.y = (int) (yInScreen - yValueInView);
wm.updateViewLayout(this, params);
}
public void setParams(WindowManager.LayoutParams params) {
this.params = params;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//按下浮动框后记录浮动框的位置
xValueInView = (int) event.getX();
yValueInView = (int) event.getY();
yDown = (int) event.getRawY();
xInScreen = (int) event.getRawX();
yInScreen = (int) (event.getRawY());
break;
case MotionEvent.ACTION_MOVE:
//移动浮动框时,不断的更新浮动框updataLocation()
xInScreen = (int) event.getRawX();
yInScreen = (int) (event.getRawY());
//只有浮动框移动位置才会更新。不加这段代码,当按住浮动框时,浮动框会自己弹开一段距离。可能和我桌面有关系。
int abs = Math.abs(yInScreen - yDown);
if (abs != 0) {
updataLocation();
}
break;
case MotionEvent.ACTION_UP:
//抬起时,将浮动框靠屏幕右边显示。
params.x = screenWidth;
params.y = (int) (yInScreen - yValueInView);
wm.updateViewLayout(this, params);
break;
default:
break;
}
return true;
}
}
完。