Android监听截屏 您所在的位置:网站首页 安卓系统怎么样截屏 Android监听截屏

Android监听截屏

2023-12-27 03:52| 来源: 网络整理| 查看: 265

Android系统没有提供默认的截屏事件监听方式,需要开发者自己想办法实现。查看了网上推荐的实现方式,主要是通过内容观察者(ContentObserver)监听媒体数据库的变化,根据内容名称(路径)中是否包含关键字,判断是否为截屏事件。 关键字:

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", "snap", "截屏" };

第一步:对ContentResolver添加内、外存储变化监听;

mInternalObserver = new MediaContentObserver(MediaStore.Images.Media.INTERNAL_CONTENT_URI, MainHandler.get()); mExternalObserver = new MediaContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, MainHandler.get()); mResolver = AppContext.get().getContentResolver(); // 添加监听 mResolver.registerContentObserver( MediaStore.Images.Media.INTERNAL_CONTENT_URI, false, mInternalObserver ); mResolver.registerContentObserver( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, false, mExternalObserver );

第二步:当内容观察者(ContentObserver)监听到变化时,会调用onChange方法,此时,我们使用ContentResolver去查询最新的一条数据; 需要注意的是,查询外部存储一定要有读取存储权限(Manifest.permission.READ_EXTERNAL_STORAGE),否则会在查询的时候报错; 第三步:判断查到到数据是否为截图文件;在这里有一个很难处理到问题,在华为荣耀手机上,截图预览图生成的同时就会通知存储内容变化,而小米则是在截图预览图消失后通知变化; 解决方案:

判断当前文件路径是否与上次有效路径相同,相同执行步骤2,不相同则执行步骤3; 当前路径与上次路径相同,取消回调请求,重新延迟发送回调请求; 当前路径与上次路径不同,判断内容的生成时间(MediaStore.Images.ImageColumns.DATE_TAKEN)和添加时间(MediaStore.Images.ImageColumns.DATE_ADDED)是否相同,相同执行步骤4,不相同则执行步骤5; 内容的生成时间和添加时间相同,认为此时为生成长截图,立刻取消回调请求,执行空回调(用于取消弹窗等操作); 内容的生成时间和添加时间不同,检查是否含有关键字,若判定为截图,更新上次有效路径,取消回调请求,重新延迟发送回调请求; // 获取各列的索引 int dataIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA); int dateTakenIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATE_TAKEN); int dateAddIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATE_ADDED); // 获取行数据 final String data = cursor.getString(dataIndex); long dateTaken = cursor.getLong(dateTakenIndex); long dateAdded = cursor.getLong(dateAddIndex); if (data.length() > 0) { if (TextUtils.equals(lastData, data)) { MainHandler.get().removeCallbacks(shotCallBack); MainHandler.get().postDelayed(shotCallBack, 500); } else if (dateTaken == 0 || dateTaken == dateAdded * 1000) { MainHandler.get().removeCallbacks(shotCallBack); if (listener != null) { listener.onShot(null); } } else if (checkScreenShot(data)) { MainHandler.get().removeCallbacks(shotCallBack); lastData = data; MainHandler.get().postDelayed(shotCallBack, 500); } }

完整代码:(其中AppContext为全局Application单例,MainHandler为全局主线程Handler单例)

public class ScreenShotHelper { 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", "snap", "截屏" }; /** * 读取媒体数据库时需要读取的列 */ private static final String[] MEDIA_PROJECTIONS = { MediaStore.Images.ImageColumns.DATA, MediaStore.Images.ImageColumns.DATE_TAKEN, MediaStore.Images.ImageColumns.DATE_ADDED, }; /** * 内部存储器内容观察者 */ private ContentObserver mInternalObserver; /** * 外部存储器内容观察者 */ private ContentObserver mExternalObserver; private ContentResolver mResolver; private OnScreenShotListener listener; private String lastData; private Runnable shotCallBack = new Runnable() { @Override public void run() { if (listener != null) { final String path = lastData; if (path != null && path.length() > 0) { listener.onShot(path); } } } }; private ScreenShotHelper() { // 初始化 mInternalObserver = new MediaContentObserver(MediaStore.Images.Media.INTERNAL_CONTENT_URI, null); mExternalObserver = new MediaContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null); mResolver = AppContext.get().getContentResolver(); // 添加监听 mResolver.registerContentObserver( MediaStore.Images.Media.INTERNAL_CONTENT_URI, false, mInternalObserver ); mResolver.registerContentObserver( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, false, mExternalObserver ); } private static class Instance { static ScreenShotHelper mInstance = new ScreenShotHelper(); } public static ScreenShotHelper get() { return Instance.mInstance; } public void setScreenShotListener(OnScreenShotListener listener) { this.listener = listener; } public void removeScreenShotListener(OnScreenShotListener listener) { if (this.listener == listener) { synchronized (ScreenShotHelper.class) { if (this.listener == listener) { this.listener = null; } } } } public void stopListener() { mResolver.unregisterContentObserver(mInternalObserver); mResolver.unregisterContentObserver(mExternalObserver); } private void handleMediaContentChange(Uri contentUri) { Cursor cursor = null; try { // 数据改变时查询数据库中最后加入的一条数据 cursor = mResolver.query( contentUri, MEDIA_PROJECTIONS, null, null, MediaStore.Images.ImageColumns.DATE_ADDED + " desc limit 1" ); if (cursor == null) { return; } if (!cursor.moveToFirst()) { return; } // 获取各列的索引 int dataIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA); int dateTakenIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATE_TAKEN); int dateAddIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATE_ADDED); // 获取行数据 final String data = cursor.getString(dataIndex); long dateTaken = cursor.getLong(dateTakenIndex); long dateAdded = cursor.getLong(dateAddIndex); if (data.length() > 0) { if (TextUtils.equals(lastData, data)) { //更改资源文件名也会触发,并且传递过来的是之前的截屏文件,所以只对分钟以内的有效 if (System.currentTimeMillis() - dateTaken < 3 * 3600) { MainHandler.get().removeCallbacks(shotCallBack); MainHandler.get().postDelayed(shotCallBack, 500); } } else if (dateTaken == 0 || dateTaken == dateAdded * 1000) { MainHandler.get().removeCallbacks(shotCallBack); if (listener != null) { listener.onShot(null); } } else if (checkScreenShot(data)) { MainHandler.get().removeCallbacks(shotCallBack); lastData = data; MainHandler.get().postDelayed(shotCallBack, 500); } } } catch (Exception e) { // } finally { if (cursor != null && !cursor.isClosed()) { cursor.close(); } } } /** * 根据包含关键字判断是否是截屏 */ private boolean checkScreenShot(String data) { if (data == null || data.length() < 2) { return false; } data = data.toLowerCase(); for (String keyWork : KEYWORDS) { if (data.contains(keyWork)) { return true; } } return false; } private class MediaContentObserver extends ContentObserver { private Uri mContentUri; MediaContentObserver(Uri contentUri, Handler handler) { super(handler); mContentUri = contentUri; } @Override public void onChange(boolean selfChange) { super.onChange(selfChange); if (listener != null) { handleMediaContentChange(mContentUri); } } } public interface OnScreenShotListener { void onShot(@Nullable String data); } }

总结: 1.必须要有读取内存的权限; 2.内容生成时间为毫秒,内容添加时间为秒,比较时需要注意换算; 3.当内容生成时间等于内容添加时间时,应当取消之前的截屏监听操作(尤其是会遮挡页面视图的部分);



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有