在几个月前有接到项目老大这样一个需求:实时获取用户当前app的操作界面 ~
在早期的时候有记录过一篇关于截图的Blog,有需求也可以去扩展
因为近俩年主要做的是售货机业务,所以长连接使用的是mqtt,这里主要讲接收到消息后,我们去动态获取用户操作界面时的实现方式,即实时截屏+本地保存 ~
局部实现
提要:这里主要实现了单个界面截屏的实现方式,也是较为常见的一种实现方式,不是说不能通过这种方式实现全局截屏,而是使用这种方式后,太多繁琐,所以该方式并不完全适用于全局,但是可以当作借鉴与基础
根据以下操作后,亲测已实现需求功能,但是因售货机版本大多在5.0之前,所以在手机开发时要记得适配 6.0动态权限,7.0文件临时授权
在长连接中收到消息后,我采用eventbus传递消息,进行app当前界面截屏+图片保存
look here:当执行完以选操作时,我们可以去查看本地是否已经保存好我们需要的用户操作界面图 ~
case Constant.EventBus.SCREEN_SHOT:
Bitmap bitmap = BitmapTool.convertCanvasViewToBitmap(mScreenParent);
if (bitmap != null) {
BitmapTool.saveImage(bitmap, Constant.LocalPath.BASIC_PATH);
}
break;
mScreenParent控件id,处于layout的最外层  convertCanvasViewToBitmap - 截图
public static Bitmap convertCanvasViewToBitmap(View tempView) {
Bitmap bitmap = Bitmap.createBitmap(tempView.getWidth(),
tempView.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
tempView.draw(canvas);
return bitmap;
}
saveImage - 保存图片
public static void saveImage(Bitmap bitmap, String path) {
File file = new File(path);
if (!file.exists()) {
file.mkdir();
}
try {
String tmpImgPath = path + "/" + "screenShot" + System.currentTimeMillis() + ".png";
FileOutputStream fileOutputStream = new FileOutputStream(tmpImgPath);
int bmSize = bitmap.getByteCount();
int kb = bmSize / 1024;
int mb = kb / 1024;
kb = kb % 1024;
Log.d("Bitmap", "bitmap size = " + mb + "MB " + kb + "KB");
Bitmap bitmap1 = compressImage(bitmap);
bitmap1.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
bmSize = bitmap1.getByteCount();
kb = bmSize / 1024;
mb = kb / 1024;
kb = kb % 1024;
Log.d("Bitmap", "bitmap size = " + mb + "MB " + kb + "KB");
fileOutputStream.close();
} catch (Exception e) {
LogTool.e(e.getMessage());
}
}
compressImage - 图片压缩
public static Bitmap compressImage(Bitmap image) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
int options = 90;
while (baos.toByteArray().length / 1024 > 100) {
baos.reset();
image.compress(Bitmap.CompressFormat.JPEG, options, baos);
options -= 10;
if (options < 0) {
break;
}
}
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);
return bitmap;
}
全局实现
提要:意如其名,通过以下方式,我们可以全局捕获用户的一个实时操作状态,相比上方的话,思维需要更扩展一些
实现思想: 因为需要通过activity的维度,进行屏幕截取,所以我们需要一个能实时获取当前activity的管制类,然后在接收到截屏消息后我们将当前activity的实例传入截屏方法中,从而实现全局截屏的功能
根据以下操作后,亲测已实现需求功能,但是因售货机版本大多在5.0之前,所以在手机开发时要记得适配 6.0动态权限,7.0文件临时授权
注意:关于图片最终保存效果,其一取决于手机实际分辨率,其二取决于图片质量压缩时的一个比例
ActivityCollector - activity管理类
package com.nk.machine.base;
import android.app.Activity;
import java.util.ArrayList;
import java.util.List;
public class ActivityCollector {
public static List<Activity> activities = new ArrayList<>();
public static void addActivity(Activity activity) {
activities.add(activity);
}
public static void removeActivity(Activity activity) {
activities.remove(activity);
}
public static List<Activity> activityList(){
return activities;
}
public static void finishAll() {
for (Activity activity : activities) {
if (!activity.isFinishing()) {
activity.finish();
}
}
}
}
BaseActivity - 需要截屏的activity均继承于BaseActivity,同时配置activity管理类
package com.nk.machine.base;
import android.Manifest;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.view.Window;
import android.view.WindowManager;
public abstract class BaseActivity extends RxAppCompatActivity {
private TextView mTitle;
private ImageView mBack;
private NkApplication application;
private ScreenCountTimer screenCountTimer;
private String className;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityCollector.addActivity(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
ActivityCollector.removeActivity(this);
}
}
收到截屏消息后,获取当前activity名称,同时从acitivity管理类中,获取当前activity的实例,然后进行屏幕截取与截图保存
LogTool.e("当前Activity:" + BitmapTool.getRunningActivityName());
List<Activity> activities = ActivityCollector.activityList();
String runningActivityName = BitmapTool.getRunningActivityName();
if (activities.size() > 0) {
int tmpPosition = 0;
out: for (int i = 0; i < activities.size(); i++) {
in: if (runningActivityName.contains(activities.get(i).getLocalClassName())) {
tmpPosition = i;
break out;
}
}
Activity activity = activities.get(tmpPosition);
Bitmap bitmap = BitmapTool.captureNow(activity);
if (bitmap != null) {
BitmapTool.saveImage(bitmap, Constant.LocalPath.BASIC_PATH);
}
}
getRunningActivityName - 获取当前activity名称
public static String getRunningActivityName() {
ActivityManager activityManager = (ActivityManager) NkApplication.getAppContext().getSystemService(Context.ACTIVITY_SERVICE);
String runningActivity = activityManager.getRunningTasks(1).get(0).topActivity.getClassName();
return runningActivity;
}
captureNow - 截取当前activity的屏幕状态
public static Bitmap captureNow(Activity activity) {
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());
if (bitmap != null) {
return bitmap;
}
return null;
}
saveImage - 保存图片
public static void saveImage(Bitmap bitmap, String path) {
File file = new File(path);
if (!file.exists()) {
file.mkdir();
}
try {
String tmpImgPath = path + "/" + "screenShot" + System.currentTimeMillis() + ".png";
FileOutputStream fileOutputStream = new FileOutputStream(tmpImgPath);
int bmSize = bitmap.getByteCount();
int kb = bmSize / 1024;
int mb = kb / 1024;
kb = kb % 1024;
Log.d("Bitmap", "bitmap size = " + mb + "MB " + kb + "KB");
Bitmap bitmap1 = compressImage(bitmap);
bitmap1.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
bmSize = bitmap1.getByteCount();
kb = bmSize / 1024;
mb = kb / 1024;
kb = kb % 1024;
Log.d("Bitmap", "bitmap size = " + mb + "MB " + kb + "KB");
fileOutputStream.close();
} catch (Exception e) {
LogTool.e(e.getMessage());
}
}
|