详解Android截屏事件监听
1.前言
Android系统没有直接对截屏事件监听的接口,也没有广播,只能自己动手来丰衣足食,一般有三种方法。
- 利用FileObserver监听某个目录中资源变化情况
- 利用ContentObserver监听全部资源的变化
- 监听截屏快捷按键
由于厂商自定义Android系统的多样性,再加上快捷键的不同以及第三方应用,监听截屏快捷键这事基本不靠谱,可以直接忽略。
本文使用的测试手机,一加2(OnePlus2)。
2.FileObserver
添加权限:
<uses-permissionandroid:name="android.permission.READ_EXTERNAL_STORAGE"/>
代码示例:
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);
//监听到事件,做一些过滤去重处理操作
}
}
}
打印的日志:
一加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
三星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
可以通过指定构造函数中的mask,监听某一个事件。
几点注意事项:
- 每一次截屏,有多个事件回调
- 每一次截屏,不同的手机,事件回调可能有些不同,参考上述日志
- 不同的手机,默认截屏图片储存的文件夹可能不同
- FileObserver只能监听文件夹中子文件和子文件夹的变化情况,不能监听子文件夹内部的资源变化
- 需要<uses-permissionandroid:name="android.permission.READ_EXTERNAL_STORAGE"/>权限,否则可能收不到事件
基于第三点和第四点,这种方法并不能适用于所有的机型。
注意:如果自己写Demo没有收到事件,检查一下权限和监听的目录
3.ContentObserver
ContentObserver用来监听指定uri的所有资源变化,我们可以用它来监听图片资源变化情况,然后做过滤。
添加权限
<uses-permissionandroid:name="MediaStore.Images.Media.INTERNAL_CONTENT_URI"/> <uses-permissionandroid:name="MediaStore.Images.Media.EXTERNAL_CONTENT_URI"/>
代码示例:
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");
mHandlerThread.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);
//处理获取到的第一行数据
handleMediaRowData(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);
}
}
}
日志:
D/Screenshot:content://media/external/images/media D/Screenshot:/storage/emulated/0/Pictures/Screenshots/Screenshot_2016-12-19-11-24-02.png1482117842287
注意事项:
- ContentObserver会监听到所有图片资源的变化情况,要做好去重过滤工作
- 根据uri去读取ContentProvider内容时候,记得关闭cursor,防止内存泄漏
- 关键字可扩展,大大增加的监听的范围,比FileObserver好用多了,但是去重过滤会比FileObserver复杂一些。
4.总结
目前这是在网上搜索到的关于截屏监听方法的总结,如果大家还有什么比较好的监听方法,欢迎分享。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。