成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

android中對截圖事件進行監(jiān)聽的原理是什么-創(chuàng)新互聯(lián)

這篇文章給大家介紹android中對截圖事件進行監(jiān)聽的原理是什么,內(nèi)容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

十年建站經(jīng)驗, 網(wǎng)站設(shè)計、成都網(wǎng)站制作客戶的見證與正確選擇。創(chuàng)新互聯(lián)提供完善的營銷型網(wǎng)頁建站明細報價表。后期開發(fā)更加便捷高效,我們致力于追求更美、更快、更規(guī)范。

1.監(jiān)聽截屏圖片所在目錄變化(FileObserver)

2.監(jiān)聽媒體庫的變化(ContentObserver)

上面兩種方法均不是萬能的,需要結(jié)合使用才能達到良好的效果,首先看看如何監(jiān)控目錄

在android中,我們可以通過FileObserver來監(jiān)聽目錄變化,先來看看如何使用

private static final File DIRECTORY_PICTURES = new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_PICTURES); 
private static final File DIRECTORY_DCIM = new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_DCIM); 
 
if (manufacturer.equalsIgnoreCase("xiaomi")) { 
  DIRECTORY_SCREENSHOT = new File(DIRECTORY_DCIM, "Screenshots"); 
} else { 
  DIRECTORY_SCREENSHOT = new File(DIRECTORY_PICTURES, "Screenshots"); 
} 
 
FILE_OBSERVER = new FileObserver(DIRECTORY_SCREENSHOT.getPath(), FileObserver.ALL_EVENTS) { 
  @Override 
  public void onEvent(int event, String path) { 
    if (event == FileObserver.CREATE) { 
      String newPath = new File(DIRECTORY_SCREENSHOT, path).getAbsolutePath(); 
      Log.d(TAG, "path: " + newPath); 
    } 
  } 
};

我們對指定目錄的指定事件監(jiān)聽即可,當事件被觸發(fā)時onEvent會回調(diào)。這里我們只關(guān)心目錄中有沒有新的文件生成。

坑1:在實踐中發(fā)現(xiàn),并不是所有手機都允許如此監(jiān)聽或者說都能收到回調(diào)。有的手機上面無法收到CREATE事件,但是可以收到其他事件。

我還發(fā)現(xiàn),有的時候收到的事件并沒有在FileObserver中定義,比如32768!下面是Linux中相應(yīng)event對應(yīng)的含義,32768=IN_IGNORED,但是為什么會ignore,并不清楚。

http://rswiki.csie.org/lxr/http/source/include/linux/inotify.h?a=m68k#L45

還遇到過1073741856(1073741856 = 0x40000000 | 0x20,即IN_OPEN | IN_ISDIR)和1073741840(1073741840 = 0x40000000 | 0x10,即IN_CLOSE_NOWRITE | IN_ISDIR)。

坑2:不同手機,監(jiān)聽的目錄并不一致。小米需要監(jiān)聽Environment.DIRECTORY_DCIM,其他監(jiān)聽Environment.DIRECTORY_PICTURES即可。

關(guān)于FileObserver這里再多說兩句,F(xiàn)ileObserver無法進行遞歸監(jiān)聽,也就是說,我們監(jiān)聽的文件夾中如果有子文件夾,并且我們想知道其中變化,這種方式是不可行的。需要手動對子文件進行操作。

另外,當我們監(jiān)聽的目錄/文件被刪除后又重新建立了一個同名的目錄/文件,之前的FileObserver不會繼續(xù)工作,需要重新設(shè)置監(jiān)聽才行。

還要注意,F(xiàn)ileObserver回調(diào)并不在主線程中,而是在FileObserver線程中。

鑒于上述原因,我們還要使用方法2,監(jiān)聽媒體庫變化。這個方法使用ContentObserver即可。

private static final ContentObserver CONTENT_OBSERVER = new ContentObserver(HANDLER) { 
  @Override 
  public void onChange(boolean selfChange, Uri uri) { 
    //記得先檢查讀文件的權(quán)限 
    ContentResolver resolver = GeneralInfoHelper.getContext().getContentResolver(); 
    if (uri.toString().matches(MediaStore.Images.Media.EXTERNAL_CONTENT_URI + "(/\\d+)?")) { 
      Cursor cursor = resolver.query(uri, PROJECTION, null, null, MediaStore.MediaColumns.DATE_ADDED + " DESC"); 
      if (cursor != null && cursor.moveToFirst()) { 
        //完整路徑 
        String newPath = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DATA)); 
        File file = new File(newPath); 
        //file.exists() 判斷文件是否存在 
      } 
      if (cursor != null) { 
        cursor.close(); 
      } 
    } 
  } 
}; 
 
getContentResolver().registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true, CONTENT_OBSERVER);

坑3:實踐中發(fā)現(xiàn),并不是所有手機都是監(jiān)聽相同的Uri,有的帶數(shù)字,有的不帶。

坑4:查詢數(shù)據(jù)庫時記得按MediaStore.MediaColumns.DATE_ADDED字段排序,注意,這個時間單位是秒,不是毫秒

坑5:即使排了序,你拿到的仍然有可能不是正確的,在魅族E2上面出現(xiàn)了這個問題。但是當我刪除了魅族E2截圖文件夾之后,一切又恢復(fù)正常了……這里我做了一個簡單的判斷,如何DATE_ADDED和當前時間相差兩秒以內(nèi),那么從數(shù)據(jù)庫查出的這條數(shù)據(jù)我視為有效

坑6:當用戶刪除了截圖文件夾的時候,媒體庫此時會更新,所以此時onChange會收到大量回調(diào),所以這里需要判斷判斷文件是否存在。

可能有人會問,為什么不直接用第二種方法?

原因有2,首先從坑5可以看出第二種方法也并非100%有效,其次,這種方法速度很慢,通常會有2-3秒的延遲。而第一種方法如果有效,通常都會比后者快很多。

好了,障礙基本掃清,下面開始融合兩種方法

首先使用成員變量記錄截圖文件路徑

private static String sScreenshotPath;

當方法1或者方法2收到結(jié)果時,用收到的結(jié)果與sScreenshotPath對比,如果是同一個文件,那么就無需再次通知了,否則則進行通知。

邏輯太簡單,代碼就不寫了。但是實際情況是不會這么樂觀的。

坑7:在實踐中發(fā)現(xiàn),有的系統(tǒng)不直接保存截圖,而是先生成一個隱藏文件,比如叫.截圖.jpg,然后再修改文件名(去掉“.”)。這種情況下,我們可能就會收到兩次用戶截圖事件的回調(diào)(方法1和方法2都可能收到回調(diào)),但實際用戶只截了一次。

這里我做了一個特殊處理,在判斷是否是同一個文件時,只判斷文件名,而不去管文件的完整路徑也不管文件是否隱藏(也就是不比較文件名前面的“.”)

//僅靠文件名而不是全路徑判斷是否為同一個截圖文件,因為有些系統(tǒng)對截圖有move操作 
private static boolean isSameFile(String newPath) { 
  if (TextUtils.isEmpty(sScreenshotPath)) { 
    return false; 
  } 
 
  return TextUtils.equals(removePrefixDot(new File(sScreenshotPath).getName()), removePrefixDot(new File(newPath).getName())); 
} 
 
private static String removePrefixDot(@NonNull String filename) { 
  if (filename.startsWith(".")) { 
    return filename.substring(1); 
  } 
  return filename; 
}

關(guān)于android中對截圖事件進行監(jiān)聽的原理是什么就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

分享文章:android中對截圖事件進行監(jiān)聽的原理是什么-創(chuàng)新互聯(lián)
瀏覽地址:http://jinyejixie.com/article8/icpip.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信公眾號用戶體驗、手機網(wǎng)站建設(shè)云服務(wù)器、動態(tài)網(wǎng)站網(wǎng)站收錄

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

商城網(wǎng)站建設(shè)
桂平市| 萨迦县| 罗山县| 班戈县| 奇台县| 乌什县| 津市市| 兴隆县| 马公市| 平乐县| 郎溪县| 斗六市| 淮滨县| 宜君县| 盐城市| 景洪市| 天津市| 南昌县| 南漳县| 宣威市| 麦盖提县| 岳池县| 垣曲县| 云和县| 莎车县| 大兴区| 长岭县| 开化县| 无锡市| 海盐县| 绩溪县| 磐安县| 张北县| 开阳县| 安福县| 延吉市| 历史| 澄城县| 安阳市| 永济市| 吐鲁番市|