详解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.总结
目前这是在网上搜索到的关于截屏监听方法的总结,如果大家还有什么比较好的监听方法,欢迎分享。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。