美文网首页
Android 应用监听截屏操作

Android 应用监听截屏操作

作者: 普通的程序员 | 来源:发表于2018-05-13 12:22 被阅读0次

    最近要求做一个app内监听截屏,然后调用自己的分享功能。

    网上有很多方案。这里我采用的是内容监听方案。
    参考
    https://www.jianshu.com/p/d7aba5a03b0f

    结合我的业务实际,以下是完整代码。

    0.局部变量

    private String data;//截图图片路径
    private Handler mUiHandler;
    private MediaContentObserver mInternalObserver;
    private MediaContentObserver mExternalObserver;
    
    private static final String[] MEDIA_PROJECTIONS = {
    //            MediaStore.Images.ImageColumns.WIDTH,
    //            MediaStore.Images.ImageColumns.HEIGHT,
                MediaStore.Images.ImageColumns.DATA,
                MediaStore.Images.ImageColumns.DATE_TAKEN
    };
    
    private static final String[] KEYWORDS = {
                "screenshot", "screen_shot", "screen-shot", "screen shot", "截屏",
                "screencapture", "screen_capture", "screen-capture", "screen capture",
                "screencap", "screen_cap", "screen-cap", "screen cap"
    };//国内机器截图路径有中文,有可能还得做国际化适配
    
    
    1. 自定义媒体内容观察者内部类(观察媒体数据库的改变)
    private class MediaContentObserver extends ContentObserver {
            private Uri mediaContentUri;       // 需要观察的Uri
    
            public MediaContentObserver(Uri contentUri, Handler handler) {
                super(handler);
                mediaContentUri = contentUri;
            }
    
            @Override
            public void onChange(boolean selfChange) {
                super.onChange(selfChange);
                // 处理媒体数据库反馈的数据变化
                handleMediaContentChange(mediaContentUri);
            }
        }
    

    2.注册监听

    private void initMediaContentObserver() {
            // 运行在 UI 线程的 Handler, 用于运行监听器回调
            mUiHandler = new Handler(Looper.getMainLooper());
            // 创建内容观察者,包括内部存储和外部存储
            mInternalObserver = new MediaContentObserver(MediaStore.Images.Media.INTERNAL_CONTENT_URI, mUiHandler);
            mExternalObserver = new MediaContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, mUiHandler);
            // 注册内容观察者
            getContentResolver().registerContentObserver(
                    MediaStore.Images.Media.INTERNAL_CONTENT_URI, false, mInternalObserver);
            getContentResolver().registerContentObserver(
                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI, false, mExternalObserver);
        }
    

    3.处理数据

        private void handleMediaContentChange(Uri contentUri) {
            Cursor cursor = null;
            try {
                // 数据改变时查询数据库中最后加入的一条数据
                cursor = getContentResolver().query(contentUri,
                        MEDIA_PROJECTIONS,
                        null, null, MediaStore.Images.ImageColumns.DATE_ADDED + " desc limit 1");
    
                if (cursor == null) return;
                if (!cursor.moveToFirst()) return;
    
                // cursor.getColumnIndex获取数据库列索引
                int dateTakenIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATE_TAKEN);
                long dateTaken = cursor.getLong(dateTakenIndex);  // 图片生成时间
    
    //因为该监听也会监听到删除截图的操作,所以判断最后一张图的时间和现在时间,如果相差8s内,则认为是刚截图
    //国内部分机器刚截的图并不是马上就写进去,而是放在内存了,8s是一个经验值
                if (System.currentTimeMillis() - dateTaken > 8000) return;
    
                int dataIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
                data = cursor.getString(dataIndex);        // 图片存储地址
    
    //            int width = 0;
    //            int height = 0;
    //            int widthIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.WIDTH);
    //            int heightIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.HEIGHT);
    //            width = cursor.getInt(widthIndex);    // 获取图片高度
    //            height = cursor.getInt(heightIndex);  // 获取图片宽度
    
                // 处理获取到的第一行数据
                handleMediaRowData(data);
    
            } catch (AndroidRuntimeException e) {
                //1.Android7.0以下机器要求用FLAG_ACTIVITY_NEW_TASK启动
                //2.部分机器写入截图实在是太慢,给个800ms延迟
                mUiHandler.postDelayed(() ->
                        startActivity(ShareCapturePicActivity.newIntent(this, data,
                                Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP)), 800);
                e.printStackTrace();
            } finally {
                if (cursor != null && !cursor.isClosed()) {
                    cursor.close();
                }
            }
        }
    
      //处理监听到的资源
        private void handleMediaRowData(String data) {
            if (checkScreenShot(data)) {
                startActivity(ShareCapturePicActivity.newIntent(this, data, Intent.FLAG_ACTIVITY_SINGLE_TOP));
            }
        }
    
        //判断是否是截屏
        private boolean checkScreenShot(String data) {
            data = data.toLowerCase();
            // 判断图片路径是否含有指定的关键字之一, 如果有, 则认为当前截屏了
            for (String keyWork : KEYWORDS) {
                if (data.contains(keyWork)) {
                    return true;
                }
            }
            return false;
        }
    

    至于FLAG_ACTIVITY_NEW_TASK的问题,我在这篇文章有说。
    非activity环境启动activity还需要FLAG_ACTIVITY_NEW_TASK吗?

    顺带提一下
    onNewIntent的周期
    第一次singleTop启动,正常onCreate--start--resume
    后续就是 onNewIntent---start--resume

    相关文章

      网友评论

          本文标题:Android 应用监听截屏操作

          本文链接:https://www.haomeiwen.com/subject/wgfldftx.html