Android截屏事件监听
1.前言
Android系统没有直接对截屏事件监听的接口,也没有广播,只能自己动手来丰衣足食,一般有三种方法。
利用FileObserver监听某个目录中资源变化情况
利用ContentObserver监听全部资源的变化
监听截屏快捷按键
由于厂商自定义Android系统的多样性,再加上快捷键的不同以及第三方应用,监听截屏快捷键这事基本不靠谱,可以直接忽略。
本文使用的测试手机,一加2(OnePlus2)。
2.FileObserver
添加权限:
1
1
代码示例:
publicclassScreenshotActivityextendsAppCompatActivity{
privatefinalStringTAG="Screenshot";
privatestaticfinalStringPATH=Environment.getExternalStorageDirectory()+File.separator
+Environment.DIRECTORY_PICTURES+File.separator+"Screenshots"+File.separator;
protectedvoidonCreate(@NullableBundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_screenshot);
mFileObserver=newCustomFileObserver(PATH);
}
@Override
protectedvoidonResume(){
super.onResume();
mFileObserver.startWatching();
Log.d(TAG,PATH);
}
@Override
protectedvoidonStop(){
super.onStop();
mFileObserver.stopWatching();
}
/
目录监听器
/
privateclassCustomFileObserverextendsFileObserver{
privateStringmPath;
publicCustomFileObserver(Stringpath){
super(path);
this.mPath=path;
}
publicCustomFileObserver(Stringpath,intmask){
super(path,mask);
this.mPath=path;
}
@Override
publicvoidonEvent(intevent,Stringpath){
Log.d(TAG,path+""+event);
//监听到事件,做一些过滤去重处理操作
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
打印的日志:
一加2
D/Screenshot:Screenshot_2016-12-16-17-49-18.png256
D/Screenshot:Screenshot_2016-12-16-17-49-18.png32
D/Screenshot:Screenshot_2016-12-16-17-49-18.png2
D/Screenshot:Screenshot_2016-12-16-17-49-18.png2
D/Screenshot:Screenshot_2016-12-16-17-49-18.png2
D/Screenshot:Screenshot_2016-12-16-17-49-18.png2
D/Screenshot:Screenshot_2016-12-16-17-49-18.png2
D/Screenshot:Screenshot_2016-12-16-17-49-18.png2
D/Screenshot:Screenshot_2016-12-16-17-49-18.png2
D/Screenshot:Screenshot_2016-12-16-17-49-18.png2
D/Screenshot:Screenshot_2016-12-16-17-49-18.png2
D/Screenshot:Screenshot_2016-12-16-17-49-18.png2
D/Screenshot:Screenshot_2016-12-16-17-49-18.png2
D/Screenshot:Screenshot_2016-12-16-17-49-18.png2
D/Screenshot:Screenshot_2016-12-16-17-49-18.png2
D/Screenshot:Screenshot_2016-12-16-17-49-18.png2
D/Screenshot:Screenshot_2016-12-16-17-49-18.png2
D/Screenshot:Screenshot_2016-12-16-17-49-18.png8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
三星S4
D/Screenshot:Screenshot_2016-12-16-19-01-08.png256
D/Screenshot:Screenshot_2016-12-16-19-01-08.png32
D/Screenshot:Screenshot_2016-12-16-19-01-08.png2
D/Screenshot:Screenshot_2016-12-16-19-01-08.png2
D/Screenshot:Screenshot_2016-12-16-19-01-08.png2
D/Screenshot:Screenshot_2016-12-16-19-01-08.png2
D/Screenshot:Screenshot_2016-12-16-19-01-08.png2
D/Screenshot:Screenshot_2016-12-16-19-01-08.png2
D/Screenshot:Screenshot_2016-12-16-19-01-08.png2
D/Screenshot:Screenshot_2016-12-16-19-01-08.png2
D/Screenshot:Screenshot_2016-12-16-19-01-08.png2
D/Screenshot:Screenshot_2016-12-16-19-01-08.png2
D/Screenshot:Screenshot_2016-12-16-19-01-08.png2
D/Screenshot:Screenshot_2016-12-16-19-01-08.png2
D/Screenshot:Screenshot_2016-12-16-19-01-08.png2
D/Screenshot:Screenshot_2016-12-16-19-01-08.png2
D/Screenshot:Screenshot_2016-12-16-19-01-08.png2
D/Screenshot:Screenshot_2016-12-16-19-01-08.png2
D/Screenshot:Screenshot_2016-12-16-19-01-08.png2
D/Screenshot:Screenshot_2016-12-16-19-01-08.png2
D/Screenshot:Screenshot_2016-12-16-19-01-08.png2
D/Screenshot:Screenshot_2016-12-16-19-01-08.png8
D/Screenshot:Screenshot_2016-12-16-19-01-08.png32
D/Screenshot:Screenshot_2016-12-16-19-01-08.png16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
可以通过指定构造函数中的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只能监听文件夹中子文件和子文件夹的变化情况,不能监听子文件夹内部的资源变化
需要权限,否则可能收不到事件
基于第三点和第四点,这种方法并不能适用于所有的机型。
注意:如果自己写Demo没有收到事件,检查一下权限和监听的目录
3.ContentObserver
ContentObserver用来监听指定uri的所有资源变化,我们可以用它来监听图片资源变化情况,然后做过滤。
添加权限
1
2
1
2
代码示例:
publicclassScreenshotActivityextendsAppCompatActivity{
privatestaticfinalString[]KEYWORDS={
"screenshot","screen_shot","screen-shot","screenshot",
"screencapture","screen_capture","screen-capture","screencapture",
"screencap","screen_cap","screen-cap","screencap"
};
/读取媒体数据库时需要读取的列/
privatestaticfinalString[]MEDIA_PROJECTIONS={
MediaStore.Images.ImageColumns.DATA,
MediaStore.Images.ImageColumns.DATE_TAKEN,
};
/内部存储器内容观察者/
privateContentObservermInternalObserver;
/外部存储器内容观察者/
privateContentObservermExternalObserver;
privateHandlerThreadmHandlerThread;
privateHandlermHandler;
protectedvoidonCreate(@NullableBundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_screenshot);
mHandlerThread=newHandlerThread("Screenshot_Observer");
mHandlerwww.tt951.comThread.start();
mHandler=newHandler(mHandlerThread.getLooper());
//初始化
mInternalObserver=newMediaContentObserver(MediaStore.Images.Media.INTERNAL_CONTENT_URI,mHandler);
mExternalObserver=newMediaContentObserver(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
);
}
protectedvoidonDestroy(){
super.onDestroy();
//注销监听
this.getContentResolver().unregisterContentObserver(mInternalObserver);
this.getContentResolver().unregisterContentObserver(mExternalObserver);
}
privatevoidhandleMediaContentChange(UricontentUri){
Cursorcursor=null;
try{
//数据改变时查询数据库中最后加入的一条数据
cursor=this.getContentResolver().query(
contentUri,
MEDIA_PROJECTIONS,
null,
null,
MediaStore.Images.ImageColumns.DATE_ADDED+"desclimit1"
);
if(cursor==null){
return;
}
if(!cursor.moveToFirst()){
return;
}
//获取各列的索引
intdataIndex=cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
intdateTakenIndex=cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATE_TAKEN);
//获取行数据
Stringdata=cursor.getString(dataIndex);
longdateTaken=cursor.getLong(dateTakenIndex);
//处理获取到的第一行数据
handleMediawww.baiyuewang.netRowData(data,dateTaken);
}catch(Exceptione){
e.printStackTrace();
}finally{
if(cursor!=null&&!cursor.isClosed()){
cursor.close();
}
}
}
/
处理监听到的资源
/
privatevoidhandleMediaRowData(Stringdata,longdateTaken){
if(checkScreenShot(data,dateTaken)){
Log.d(TAG,data+""+dateTaken);
}else{
Log.d(TAG,"Notscreenshotevent");
}
}
/
判断是否是截屏
/
privatebooleancheckScreenShot(Stringdata,longdateTaken){
data=data.toLowerCase();
//判断图片路径是否含有指定的关键字之一,如果有,则认为当前截屏了
for(StringkeyWork:KEYWORDS){
if(data.contains(keyWork)){
returntrue;
}
}
returnfalse;
}
/
媒体内容观察者(观察媒体数据库的改变)
/
privateclassMediaContentObserverextendsContentObserver{
privateUrimContentUri;
publicMediaContentObserver(UricontentUri,Handlerhandler){
super(handler);
mContentUri=contentUri;
}
@Override
publicvoidonChange(booleanselfChange){
super.onChange(selfChange);
Log.d(TAG,mContentUri.toString());
handleMediaContentChange(mContentUri);
}
}
注意事项:
ContentObserver会监听到所有图片资源的变化情况,要做好去重过滤工作
根据uri去读取ContentProvider内容时候,记得关闭cursor,防止内存泄漏
关键字可扩展,大大增加的监听的范围,比FileObserver好用多了,但是去重过滤会比FileObserver复杂一些。
|
|