详解Android截屏事件监听
程序员文章站
2024-02-25 22:01:27
1. 前言
android系统没有直接对截屏事件监听的接口,也没有广播,只能自己动手来丰衣足食,一般有三种方法。
利用fileobserver监听某个目录中资源...
1. 前言
android系统没有直接对截屏事件监听的接口,也没有广播,只能自己动手来丰衣足食,一般有三种方法。
- 利用fileobserver监听某个目录中资源变化情况
- 利用contentobserver监听全部资源的变化
- 监听截屏快捷按键
由于厂商自定义android系统的多样性,再加上快捷键的不同以及第三方应用,监听截屏快捷键这事基本不靠谱,可以直接忽略。
本文使用的测试手机,一加2(one plus 2)。
2. fileobserver
添加权限:
<uses-permission android:name="android.permission.read_external_storage"/>
代码示例:
public class screenshotactivity extends appcompatactivity { private final string tag = "screenshot"; private static final string path = environment.getexternalstoragedirectory() + file.separator + environment.directory_pictures + file.separator + "screenshots" + file.separator; protected void oncreate(@nullable bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_screenshot); mfileobserver = new customfileobserver(path); } @override protected void onresume() { super.onresume(); mfileobserver.startwatching(); log.d(tag, path); } @override protected void onstop() { super.onstop(); mfileobserver.stopwatching(); } /** * 目录监听器 */ private class customfileobserver extends fileobserver { private string mpath; public customfileobserver(string path) { super(path); this.mpath = path; } public customfileobserver(string path, int mask) { super(path, mask); this.mpath = path; } @override public void onevent(int event, string path) { log.d(tag, path + " " + event); // 监听到事件,做一些过滤去重处理操作 } } }
打印的日志:
一加2
d/screenshot: screenshot_2016-12-16-17-49-18.png 256 d/screenshot: screenshot_2016-12-16-17-49-18.png 32 d/screenshot: screenshot_2016-12-16-17-49-18.png 2 d/screenshot: screenshot_2016-12-16-17-49-18.png 2 d/screenshot: screenshot_2016-12-16-17-49-18.png 2 d/screenshot: screenshot_2016-12-16-17-49-18.png 2 d/screenshot: screenshot_2016-12-16-17-49-18.png 2 d/screenshot: screenshot_2016-12-16-17-49-18.png 2 d/screenshot: screenshot_2016-12-16-17-49-18.png 2 d/screenshot: screenshot_2016-12-16-17-49-18.png 2 d/screenshot: screenshot_2016-12-16-17-49-18.png 2 d/screenshot: screenshot_2016-12-16-17-49-18.png 2 d/screenshot: screenshot_2016-12-16-17-49-18.png 2 d/screenshot: screenshot_2016-12-16-17-49-18.png 2 d/screenshot: screenshot_2016-12-16-17-49-18.png 2 d/screenshot: screenshot_2016-12-16-17-49-18.png 2 d/screenshot: screenshot_2016-12-16-17-49-18.png 2 d/screenshot: screenshot_2016-12-16-17-49-18.png 8
三星 s4
d/screenshot: screenshot_2016-12-16-19-01-08.png 256 d/screenshot: screenshot_2016-12-16-19-01-08.png 32 d/screenshot: screenshot_2016-12-16-19-01-08.png 2 d/screenshot: screenshot_2016-12-16-19-01-08.png 2 d/screenshot: screenshot_2016-12-16-19-01-08.png 2 d/screenshot: screenshot_2016-12-16-19-01-08.png 2 d/screenshot: screenshot_2016-12-16-19-01-08.png 2 d/screenshot: screenshot_2016-12-16-19-01-08.png 2 d/screenshot: screenshot_2016-12-16-19-01-08.png 2 d/screenshot: screenshot_2016-12-16-19-01-08.png 2 d/screenshot: screenshot_2016-12-16-19-01-08.png 2 d/screenshot: screenshot_2016-12-16-19-01-08.png 2 d/screenshot: screenshot_2016-12-16-19-01-08.png 2 d/screenshot: screenshot_2016-12-16-19-01-08.png 2 d/screenshot: screenshot_2016-12-16-19-01-08.png 2 d/screenshot: screenshot_2016-12-16-19-01-08.png 2 d/screenshot: screenshot_2016-12-16-19-01-08.png 2 d/screenshot: screenshot_2016-12-16-19-01-08.png 2 d/screenshot: screenshot_2016-12-16-19-01-08.png 2 d/screenshot: screenshot_2016-12-16-19-01-08.png 2 d/screenshot: screenshot_2016-12-16-19-01-08.png 2 d/screenshot: screenshot_2016-12-16-19-01-08.png 8 d/screenshot: screenshot_2016-12-16-19-01-08.png 32 d/screenshot: screenshot_2016-12-16-19-01-08.png 16
可以通过指定构造函数中的mask,监听某一个事件。
类型 | int值 | 说明 |
---|---|---|
fileobserver.access | 1 | 读取某个文件 |
fileobserver.modify | 2 | 向某个文件写入数据 |
fileobserver.attrib | 4 | 文件的属性被修改(权限/日期/拥有者) |
fileobserver.close_write | 8 | 写入数据后关闭 |
fileobserver.close_nowrite | 16 | 只读模式打开文件后关闭 |
fileobserver.open | 32 | 打开某个文件 |
fileobserver.moved_from | 64 | 有文件或者文件夹从被监听的文件夹中移走 |
fileobserver.moved_to | 128 | 有文件或者文件夹移动到被监听的文件夹 |
fileobserver.create | 256 | 文件或者文件夹被创建 |
fileobserver.delete | 512 | 文件被删除 |
fileobserver.delete_self | 1024 | 被监听的文件或者目录被删除 |
fileobserver.move_self | 2048 | 被监听的文件或者目录被移走 |
几点注意事项:
- 每一次截屏,有多个事件回调
- 每一次截屏,不同的手机,事件回调可能有些不同,参考上述日志
- 不同的手机,默认截屏图片储存的文件夹可能不同
- fileobserver只能监听文件夹中子文件和子文件夹的变化情况,不能监听子文件夹内部的资源变化
- 需要<uses-permission android:name="android.permission.read_external_storage"/>权限,否则可能收不到事件
基于第三点和第四点,这种方法并不能适用于所有的机型。
注意:如果自己写demo没有收到事件,检查一下权限和监听的目录
3. contentobserver
contentobserver用来监听指定uri的所有资源变化,我们可以用它来监听图片资源变化情况,然后做过滤。
添加权限
<uses-permission android:name="mediastore.images.media.internal_content_uri"/> <uses-permission android:name="mediastore.images.media.external_content_uri"/>
代码示例:
public class screenshotactivity extends appcompatactivity { 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" }; /** 读取媒体数据库时需要读取的列 */ private static final string[] media_projections = { mediastore.images.imagecolumns.data, mediastore.images.imagecolumns.date_taken, }; /** 内部存储器内容观察者 */ private contentobserver minternalobserver; /** 外部存储器内容观察者 */ private contentobserver mexternalobserver; private handlerthread mhandlerthread; private handler mhandler; protected void oncreate(@nullable bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_screenshot); mhandlerthread = new handlerthread("screenshot_observer"); mhandlerthread.start(); mhandler = new handler(mhandlerthread.getlooper()); // 初始化 minternalobserver = new mediacontentobserver(mediastore.images.media.internal_content_uri, mhandler); mexternalobserver = new mediacontentobserver(mediastore.images.media.external_content_uri, mhandler); // 添加监听 this.getcontentresolver().registercontentobserver( mediastore.images.media.internal_content_uri, false, minternalobserver ); this.getcontentresolver().registercontentobserver( mediastore.images.media.external_content_uri, false, mexternalobserver ); } protected void ondestroy() { super.ondestroy(); // 注销监听 this.getcontentresolver().unregistercontentobserver(minternalobserver); this.getcontentresolver().unregistercontentobserver(mexternalobserver); } private void handlemediacontentchange(uri contenturi) { cursor cursor = null; try { // 数据改变时查询数据库中最后加入的一条数据 cursor = this.getcontentresolver().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); // 获取行数据 string data = cursor.getstring(dataindex); long datetaken = cursor.getlong(datetakenindex); // 处理获取到的第一行数据 handlemediarowdata(data, datetaken); } catch (exception e) { e.printstacktrace(); } finally { if (cursor != null && !cursor.isclosed()) { cursor.close(); } } } /** * 处理监听到的资源 */ private void handlemediarowdata(string data, long datetaken) { if (checkscreenshot(data, datetaken)) { log.d(tag, data + " " + datetaken); } else { log.d(tag, "not screenshot event"); } } /** * 判断是否是截屏 */ private boolean checkscreenshot(string data, long datetaken) { data = data.tolowercase(); // 判断图片路径是否含有指定的关键字之一, 如果有, 则认为当前截屏了 for (string keywork : keywords) { if (data.contains(keywork)) { return true; } } return false; } /** * 媒体内容观察者(观察媒体数据库的改变) */ private class mediacontentobserver extends contentobserver { private uri mcontenturi; public mediacontentobserver(uri contenturi, handler handler) { super(handler); mcontenturi = contenturi; } @override public void onchange(boolean selfchange) { super.onchange(selfchange); log.d(tag, mcontenturi.tostring()); handlemediacontentchange(mcontenturi); } } }
日志:
d/screenshot: content://media/external/images/media d/screenshot: /storage/emulated/0/pictures/screenshots/screenshot_2016-12-19-11-24-02.png 1482117842287
注意事项:
- contentobserver会监听到所有图片资源的变化情况,要做好去重过滤工作
- 根据uri去读取contentprovider内容时候,记得关闭cursor,防止内存泄漏
- 关键字可扩展,大大增加的监听的范围,比fileobserver好用多了,但是去重过滤会比fileobserver复杂一些。
4. 总结
目前这是在网上搜索到的关于截屏监听方法的总结,如果大家还有什么比较好的监听方法,欢迎分享。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。