在几个月前有接到PM这样一个需求:实时获取用户当前app的操作界面,也就是动态获取用户当前操作界面~

因为近俩年主要做的是售货机业务,所以长连接使用的是mqtt,这里主要讲接收到消息后,我们去动态获取用户操作界面时的实现方式,即实时截屏+本地保存 ~


  • 局部实现
  • 全局实现


局部实现

提要:这里主要实现了单个界面截屏的实现方式,也是较为常见的一种实现方式,不是说不能通过这种方式实现全局截屏,而是使用这种方式后,太多繁琐,所以该方式并不完全适用于全局,但是可以当作借鉴与基础

根据以下操作后,亲测已实现需求功能,但是因售货机版本大多在5.0之前,所以在手机开发时要记得适配 6.0动态权限,7.0文件临时授权

在长连接中收到消息后,我采用eventbus传递消息,进行app当前界面截屏+图片保存

look here:当执行完以选操作时,我们可以去查看本地是否已经保存好我们需要的用户操作界面图 ~

case Constant.EventBus.SCREEN_SHOT:
    	//截图,mScreenParent为所截图区域的最外层布局控件
        Bitmap bitmap = BitmapTool.convertCanvasViewToBitmap(mScreenParent);
        //图片保存
        if (bitmap != null) {
        	//Constant.LocalPath.BASIC_PATH:Environment.getExternalStorageDirectory().getPath();
            BitmapTool.saveImage(bitmap, Constant.LocalPath.BASIC_PATH);
        }
        break;

mScreenParent控件id,处于layout的最外层

android获取density Android获取屏幕实时画面_截屏


convertCanvasViewToBitmap - 截图

/**
     * 创建一个bitmap放于画布之上进行绘制 (简直如有神助)
     */
    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);
//            bitmap.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");
//            bitmap.recycle();
            fileOutputStream.close();
        } catch (Exception e) {
            LogTool.e(e.getMessage());
        }
    }

compressImage - 图片压缩

/**
     * 质量压缩方法
     *
     * @param image
     * @return
     */
    public static Bitmap compressImage(Bitmap image) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        // 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        int options = 90;
        // 循环判断如果压缩后图片是否大于100kb,大于继续压缩
        while (baos.toByteArray().length / 1024 > 100) {
            // 重置baos即清空baos
            baos.reset();
            // 这里压缩options%,把压缩后的数据存放到baos中
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);
            // 每次都减少10
            options -= 10;
            if (options < 0) {
                break;
            }
        }
        // 把压缩后的数据baos存放到ByteArrayInputStream中
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
        // 把ByteArrayInputStream数据生成图片
        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;

/**
 * @author MrLiu
 * @date 2020/4/8
 * desc
 */
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;

/**
 * @author MrLiu
 * @date 2020/4/9
 * desc Activity基类
 */
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();
//        Bitmap bitmap = convertCanvasViewToBitmap(view);
        view.setDrawingCacheEnabled(true);
        view.buildDrawingCache();
        Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());
//        view.setDrawingCacheEnabled(false);
//        view.destroyDrawingCache();
        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);
//            bitmap.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");
//            bitmap.recycle();
            fileOutputStream.close();
        } catch (Exception e) {
            LogTool.e(e.getMessage());
        }
    }