我的编程空间,编程开发者的网络收藏夹
学习永远不晚

详解Android截屏事件监听

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

详解Android截屏事件监听

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. 总结

目前这是在网上搜索到的关于截屏监听方法的总结,如果大家还有什么比较好的监听方法,欢迎分享。

您可能感兴趣的文章:Android截屏保存png图片的实例代码Android实现截屏方式整理(总结)JavaScript截屏功能的实现代码java编程实现屏幕截图(截屏)代码总结android截屏功能实现代码使用python编写android截屏脚本双击运行即可c#根据网址抓取网页截屏生成图片的示例Android 使用Shell脚本截屏并自动传到电脑上asp.net截屏功能实现截取web页面Android实现截屏并保存操作功能Android源码解析之截屏事件流程


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

详解Android截屏事件监听

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

详解Android截屏事件监听

1. 前言 Android系统没有直接对截屏事件监听的接口,也没有广播,只能自己动手来丰衣足食,一般有三种方法。利用FileObserver监听某个目录中资源变化情况利用ContentObserver监听全部资源的变化监听截屏快捷按键 由于
2022-06-06

Android ListView监听滑动事件的方法(详解)

ListView的主要有两种滑动事件监听方法,OnTouchListener和OnScrollListener 1、OnTouchListener OnTouchListener方法来自View中的监听事件,可以在监听三个Action事件发
2022-06-06

JavaScript注册监听事件和清除监听事件方式详解

js中事件监听就是利用addEventListener来绑定一个事件,这个用法在jquery中非常常用并且简单,但在原生js中比较复杂,下面这篇文章主要给大家介绍了关于JavaScript注册监听事件和清除监听事件方式的相关资料,需要的朋友可以参考下
2023-05-19

微信小程序如何监听用户主动截屏事件

这篇文章主要为大家展示了微信小程序如何监听用户主动截屏事件,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带大家一起来研究并学习一下“微信小程序如何监听用户主动截屏事件”这篇文章吧。监听用户主动截屏事件,用户使用系统截屏按键截
2023-06-26

微信小程序中如何监听用户主动截屏事件

这篇“微信小程序中如何监听用户主动截屏事件”除了程序员外大部分人都不太理解,今天小编为了让大家更加理解“微信小程序中如何监听用户主动截屏事件”,给大家总结了以下内容,具有一定借鉴价值,内容详细步骤清晰,细节处理妥当,希望大家通过这篇文章有所
2023-06-26

Flutter事件监听与EventBus事件的应用详解

EventBus的核心是基于Streams。它允许侦听器订阅事件并允许发布者触发事件,使得不同组件的数据不需要一层层传递,可以直接通过EventBus实现跨组件通讯
2023-05-15

Spring事件监听器ApplicationListener源码详解

这篇文章主要介绍了Spring事件监听器ApplicationListener源码详解,ApplicationEvent以及Listener是Spring为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者设计模式,需要的朋友可以参考下
2023-05-20

android中对截图事件进行监听的原理是什么

这篇文章给大家介绍android中对截图事件进行监听的原理是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。1.监听截屏图片所在目录变化(FileObserver)2.监听媒体库的变化(ContentObserver
2023-05-30

jQuery如何监听触摸屏幕事件?

jQuery监听触摸屏幕事件简介jQuery提供了丰富的事件API,可轻松监听和处理触摸屏事件。事件类型touchstart:手指按下屏幕touchmove:手指在屏幕移动touchend:手指抬起屏幕touchcancel:事件被取消使用方法$(selector).on("touchstart",function(event){//处理事件});处理事件事件对象包含事件详情,包括:event.type:事件类型event.target:触发事件的元素event.touches:当前触摸点event.ch
jQuery如何监听触摸屏幕事件?
2024-04-02

Android 监听锁屏、解锁、开屏 功能代码

1、首先定义 ScreenListener package com.app.lib; import android.content.BroadcastReceiver; import android.content.Context; imp
2022-06-06

详解Vue3中Watch监听事件的使用

这篇文章主要为大家详细介绍了Vue3中Watch监听事件的使用的相关资料,文中的示例代码讲解详细,对我们学习Vue3有一定的帮助,需要的可以参考一下
2023-02-10

JavaGUI事件监听机制超详细讲解

Java事件监听器是由事件类和监听接口组成,自定义一个事件前,必须提供一个事件的监听接口以及一个事件类。JAVA中监听接口是继承java.util.EventListener的类,事件类继承java.util.EventObject的类
2023-03-03

Android4.0.x Home键事件拦截监听的方法

本文实例讲述了Android4.0.x Home键事件拦截监听的方法。分享给大家供大家参考,具体如下: 在2.3.x 的主要做法如下,具体实现网上有很多文章@Override public void onAttachedToWindow()
2022-06-06

jQuery如何监听浏览器全屏事件?

jQuery监听浏览器全屏事件使用jQuery的screenfull插件可监听浏览器全屏事件,提供方法和事件。方法包括请求、退出和切换全屏,而事件则在全屏状态更改时触发。该插件支持Chrome、Firefox等主要浏览器。还介绍了替代方案,如document.fullscreenEnabled,以增强跨浏览器兼容性。
jQuery如何监听浏览器全屏事件?
2024-04-07

Android触屏事件和MotionEvent详解

Android屏幕操作屏幕是用户和Android设备交互的主要媒介,屏幕分为触屏和非触屏。Android设备目前有四种类型:Android Phone,Android Tablet,Android Wear和Android TV。Andro
2023-05-30

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录