配色: 字号:
Android截屏事件监听
2016-12-27 | 阅:  转:  |  分享 
  
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复杂一些。

献花(0)
+1
(本文系thedust79首藏)