Android監測截圖
阿新 • • 發佈:2018-11-05
Android監測截圖
版權宣告:本文為博主原創文章,轉載請註明。
原理分析
Android系統並沒有提供截圖通知相關的API,需要我們自己對Android系統媒體資料庫進行監測,因為使用系統截圖擷取一張圖片都會把這張圖片的詳細資訊加入到這個媒體資料庫,併發出內容改變通知,因此監聽媒體資料庫的變化,就可以得到一個截圖通知然後判斷該圖片符合特定的規則,符合則認為被截圖了。然後利用RxJava訂閱事件的變化,就比較方便了。
第一步:定義監聽物件,確定觸發監聽條件
直接上程式碼說
```
final ContentObserver contentObserver = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange, Uri uri) {
Log.d(TAG, "onChange: " + selfChange + ", " + uri.toString());
if (uri.toString().startsWith(EXTERNAL_CONTENT_URI_MATCHER)) {
Cursor cursor = null;
try {
cursor = mContentResolver.query(uri, PROJECTION, null, null,
SORT_ORDER);
if (cursor != null && cursor.moveToFirst()) {
String path = cursor.getString(
cursor.getColumnIndex(MediaStore.Images.Media.DATA));
long dateAdded = cursor.getLong(cursor.getColumnIndex(
MediaStore.Images.Media.DATE_ADDED));
long currentTime = System.currentTimeMillis() / 1000;
Log.d(TAG, "path: " + path + ", dateAdded: " + dateAdded +
", currentTime: " + currentTime);
if (matchPath(path) && matchTime(currentTime, dateAdded)) {
if(mOnChangeListener!=null){
mOnChangeListener.onChange(path);
}
}
}
} catch (Exception e) {
Log.d(TAG, "open cursor fail");
} finally {
if (cursor != null) {
cursor.close();
}
}
}
super.onChange(selfChange, uri);
}
};
第二步:設定註冊和監聽介面
public void setOnChangeListener(OnChangeListener listener){
mContentResolver.registerContentObserver(//註冊監聽物件,作為被觀察者
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true, contentObserver);
mOnChangeListener = listener;
}
```
public void cancelListener(){//登出監聽物件 mContentResolver.unregisterContentObserver(contentObserver);
mOnChangeListener = null;
}
第三步:確定被觀察者
//被觀察者
Observable.OnSubscribe<String> integerOnSubscribe = new Observable.OnSubscribe<String>() {
@Override
public void call(final Subscriber<? super String> subscriber) {
try {
Log.d(TAG, "subscriber.isUnsubscribed()="+subscriber.isUnsubscribed());
if (!subscriber.isUnsubscribed()) {
setOnChangeListener(new OnChangeListener() {//設定監聽
@Override
public void onChange(String path) {//回撥變化
Log.d(TAG, "onNext: call");
subscriber.onNext(path);
}
});
subscriber.add(Subscriptions.create(new Action0() {//
@Override
public void call() {//解除繫結訂閱
cancelListener();
Log.d(TAG, "subscriber.add: Action0 call");
}
}));
}
} catch (Exception e) {
Log.d(TAG, "onError: call");
subscriber.onError(e);
}
}
};
第四步:建立被觀察者物件
public Observable startObservable() {
Log.d(TAG, "startObservable: "+integerOnSubscribe);
return Observable.create(integerOnSubscribe);
}
第五步:連線繫結觀察者和被觀察者,訂閱
這一步就是使用了,值得注意的是,在使用的時候需要申請Manifest.permission.WRITE_EXTERNAL_STORAGE許可權,
這裡使用了RxPermissions來動態申請許可權,在onResume的時候訂閱截圖監聽,當頁面退到後臺的時候利用了.compose(this.bindUntilEvent(ActivityEvent.PAUSE))解綁訂閱,防止記憶體洩漏,也需求的需要吧!
@Override
protected void onResume() {
super.onResume();
RxPermissions.getInstance(this)
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
.subscribe(granted -> {
if (granted) {
// All requested permissions are granted
Log.d(TAG, "permissions are granted");
RxScreenShot.getInstance(this).startObservable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(this.bindUntilEvent(ActivityEvent.PAUSE))
.subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {
System.out.println("RxScreenshot-onCompleted");
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(String path) {
Log.d(TAG, "觀察者: call,截圖路徑:"+path);
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText(""+path);
Glide.with(MainActivity.this).load(path).into(imageView);
}
});
}
});
} else {
// At least one permission is denied
Log.d(TAG, "permissions are not granted");
}
});
}