国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

詳解Android截屏事件監聽

2019-12-12 04:12:33
字體:
來源:轉載
供稿:網友

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 256D/Screenshot: Screenshot_2016-12-16-17-49-18.png 32D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2D/Screenshot: Screenshot_2016-12-16-17-49-18.png 2D/Screenshot: Screenshot_2016-12-16-17-49-18.png 8

三星 S4

D/Screenshot: Screenshot_2016-12-16-19-01-08.png 256D/Screenshot: Screenshot_2016-12-16-19-01-08.png 32D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2D/Screenshot: Screenshot_2016-12-16-19-01-08.png 2D/Screenshot: Screenshot_2016-12-16-19-01-08.png 8D/Screenshot: Screenshot_2016-12-16-19-01-08.png 32D/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/mediaD/Screenshot: /storage/emulated/0/Pictures/Screenshots/Screenshot_2016-12-19-11-24-02.png 1482117842287

注意事項:

  1. ContentObserver會監聽到所有圖片資源的變化情況,要做好去重過濾工作
  2. 根據uri去讀取ContentProvider內容時候,記得關閉cursor,防止內存泄漏
  3. 關鍵字可擴展,大大增加的監聽的范圍,比FileObserver好用多了,但是去重過濾會比FileObserver復雜一些。

4. 總結

目前這是在網上搜索到的關于截屏監聽方法的總結,如果大家還有什么比較好的監聽方法,歡迎分享。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 佛山市| 清徐县| 多伦县| 通山县| 眉山市| 西峡县| 景泰县| 杭州市| 安阳市| 宜兰市| 启东市| 蓬莱市| 惠安县| 东丰县| 阿克陶县| 全州县| 临颍县| 克什克腾旗| 嵩明县| 云和县| 开平市| 威远县| 大港区| 莱阳市| 昭平县| 和政县| 涡阳县| 巴东县| 龙山县| 澄迈县| 林甸县| 探索| 大英县| 交口县| 武城县| 孟连| 特克斯县| 新和县| 朔州市| 大田县| 密云县|