-
Notifications
You must be signed in to change notification settings - Fork 0
/
capture-screenshot-event-on-android.html
510 lines (390 loc) · 44.9 KB
/
capture-screenshot-event-on-android.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
<!DOCTYPE html>
<html>
<head>
<!-- [[! Document Settings ]] -->
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<!-- [[! Page Meta ]] -->
<title>捕获Android截屏事件</title>
<meta name="description" content="与机器,人,神共舞 - 编程,读书,思考,旅行,与机器对话,与人交谈,对神发问,探索,体验人生美丽的风景" />
<meta name="HandheldFriendly" content="True" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" href="/assets/images/favicon.ico" >
<!-- [[! Styles'n'Scripts ]] -->
<link rel="stylesheet" type="text/css" href="/assets/css/screen.css" />
<link rel="stylesheet" type="text/css"
href="//fonts.googleapis.com/css?family=Merriweather:300,700,700italic,300italic|Open+Sans:700,400" />
<link rel="stylesheet" type="text/css" href="/assets/css/syntax.css" />
<!-- [[! Ghost outputs important style and meta data with this tag ]] -->
<link rel="canonical" href="/" />
<meta name="referrer" content="origin" />
<link rel="next" href="/page2/" />
<meta property="og:site_name" content="与机器,人,神共舞" />
<meta property="og:type" content="website" />
<meta property="og:title" content="与机器,人,神共舞" />
<meta property="og:description" content="编程,读书,思考,旅行,与机器对话,与人交谈,对神发问,探索,体验人生美丽的风景" />
<meta property="og:url" content="/" />
<meta property="og:image" content="/assets/images/cover1.jpg" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="与机器,人,神共舞" />
<meta name="twitter:description" content="编程,读书,思考,旅行,与机器对话,与人交谈,对神发问,探索,体验人生美丽的风景" />
<meta name="twitter:url" content="/" />
<meta name="twitter:image:src" content="/assets/images/cover1.jpg" />
<script type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "Website",
"publisher": "Tao's Page",
"url": "/",
"image": "/assets/images/cover1.jpg",
"description": "编程,读书,思考,旅行,与机器对话,与人交谈,对神发问,探索,体验人生美丽的风景"
}
</script>
<meta name="generator" content="Jekyll 3.0.0" />
<link rel="alternate" type="application/rss+xml" title="与机器,人,神共舞" href="/rss.xml" />
</head>
<body class="home-template nav-closed">
<div class="nav">
<h3 class="nav-title">Menu</h3>
<a href="#" class="nav-close">
<span class="hidden">Close</span>
</a>
<ul>
<li class="nav-home " role="presentation"><a href="/">Home</a></li>
<li class="nav-about " role="presentation"><a href="/about.html">About</a></li>
<li class="nav-fables " role="presentation"><a href="/tag/machine/">Machine</a></li>
<li class="nav-speeches " role="presentation"><a href="/tag/human/">Human</a></li>
<li class="nav-fiction " role="presentation"><a href="/tag/god/">God</a></li>
<li class="nav-author " role="presentation"><a href="/author/hetao/">Author</a></li>
</ul>
<a class="subscribe-button icon-feed" href="/vocab.html">Apps</a>
</div>
<span class="nav-cover"></span>
<div class="site-wrapper">
<!-- [[! Everything else gets inserted here ]] -->
<!-- default -->
<!-- The comment above "< default" means - insert everything in this file into -->
<!-- the [body] of the default.hbs template, which contains our header/footer. -->
<!-- Everything inside the #post tags pulls data from the post -->
<!-- #post -->
<header class="main-header post-head no-cover">
<nav class="main-nav clearfix">
</nav>
</header>
<main class="content" role="main">
<article class="post tag-machine">
<header class="post-header">
<h1 class="post-title">捕获Android截屏事件</h1>
<section class="post-meta">
<!-- <a href='/'>Tao He</a> -->
<time class="post-date" datetime="2017-08-02">02 Aug 2017</time>
<!-- [[tags prefix=" on "]] -->
on
<a href='/tag/machine'>Machine</a>
</section>
</header>
<section class="post-content">
<p>在Android平台上截屏事件没有对应的一个标准的事件和通知,所以应用App无法通过标准或统一的方式去捕获这个事件来满足自己的要求。
只能通过间接的方式捕获到这个事件,我因为要做一个微信的截屏图片分享的功能,所以对Android截屏事件做了一个调研,并且在开发中
选用了其中的一种方式。 大体上,要解决这个问题,大概有以下几种方法,每种方法的可靠性和灵活性都不同。</p>
<h4 id="通过按键监听捕获截屏事件">通过按键监听捕获截屏事件</h4>
<p>这种方式最简单粗暴,但是存在两个巨大的麻烦,不易克服:</p>
<ul>
<li>
<p>Android机器厂商众多,ROM众多,多截屏按键的组合没有统一的标准,如果适配所有机型,几乎是无法完成的任务</p>
</li>
<li>
<p>事件准确捕获后,截屏这个动作完全结束时点需要应用自己去检查和获取</p>
</li>
</ul>
<p>这两件事做起来都不容易,都很容易出错,所以这种方法基本上是四种办法里最不可靠的,基本不推荐这么做。</p>
<h4 id="通过监听系统截屏进程的运行和退出捕获截屏事件">通过监听系统截屏进程的运行和退出捕获截屏事件</h4>
<p>这种方法需要有一个后台线程以一定的频率去检查系统截屏进程是否启动,运行,退出,并作出相应的逻辑,而这个频率其实很难把握,毕竟应用无法预期这个截屏动作,因此这种方法也不推荐,此种方法和上面的那种方法可能只适用于非常特定的场景。</p>
<h4 id="通过fileobserver间接捕获">通过FileObserver间接捕获</h4>
<p>这种方法其实是比较可靠和可控的,就是有一个问题, 一个FileObserver初始化的时候就得决定observe哪个目录,所以适配不同机型的过程就变成了适配所以可能的目录,这个是非常麻烦的事情,不过FileObserver总体来看是可以解决这个问题的,唯一比较难的就是要适配所有可能的机型对应的目录。最开始做这个功能的时候我实现了一版使用FileObserver的实现:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">ScreenshotObserver</span> <span class="kd">extends</span> <span class="nc">FileObserver</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">String</span> <span class="no">TAG</span> <span class="o">=</span> <span class="nc">ScreenshotObserver</span><span class="o">.</span><span class="na">class</span><span class="o">.</span><span class="na">getSimpleName</span><span class="o">();</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">String</span> <span class="no">PATH</span> <span class="o">=</span> <span class="nc">Environment</span><span class="o">.</span><span class="na">getExternalStorageDirectory</span><span class="o">().</span><span class="na">toString</span><span class="o">()</span> <span class="o">+</span> <span class="s">"/Pictures/Screenshots/"</span><span class="o">;</span>
<span class="kd">private</span> <span class="nc">OnScreenshotTakenListener</span> <span class="n">mListener</span><span class="o">;</span>
<span class="kd">private</span> <span class="nc">String</span> <span class="n">mLastTakenPath</span><span class="o">;</span>
<span class="kd">public</span> <span class="nf">ScreenshotObserver</span><span class="o">(</span><span class="nc">OnScreenshotTakenListener</span> <span class="n">listener</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">super</span><span class="o">(</span><span class="no">PATH</span><span class="o">,</span> <span class="nc">FileObserver</span><span class="o">.</span><span class="na">CLOSE_WRITE</span><span class="o">);</span>
<span class="n">mListener</span> <span class="o">=</span> <span class="n">listener</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onEvent</span><span class="o">(</span><span class="kt">int</span> <span class="n">event</span><span class="o">,</span> <span class="nc">String</span> <span class="n">path</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">path</span><span class="o">==</span><span class="kc">null</span> <span class="o">||</span> <span class="n">event</span><span class="o">!=</span><span class="nc">FileObserver</span><span class="o">.</span><span class="na">CLOSE_WRITE</span><span class="o">)</span>
<span class="nc">Log</span><span class="o">.</span><span class="na">d</span><span class="o">(</span><span class="no">TAG</span><span class="o">,</span> <span class="s">"Don't care."</span><span class="o">);</span>
<span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">mLastTakenPath</span><span class="o">!=</span><span class="kc">null</span> <span class="o">&&</span> <span class="n">path</span><span class="o">.</span><span class="na">equalsIgnoreCase</span><span class="o">(</span><span class="n">mLastTakenPath</span><span class="o">))</span>
<span class="nc">Log</span><span class="o">.</span><span class="na">d</span><span class="o">(</span><span class="no">TAG</span><span class="o">,</span> <span class="s">"This event has been observed before."</span><span class="o">);</span>
<span class="k">else</span> <span class="o">{</span>
<span class="n">mLastTakenPath</span> <span class="o">=</span> <span class="n">path</span><span class="o">;</span>
<span class="nc">File</span> <span class="n">file</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">File</span><span class="o">(</span><span class="no">PATH</span><span class="o">+</span><span class="n">path</span><span class="o">);</span>
<span class="n">mListener</span><span class="o">.</span><span class="na">onScreenshotTaken</span><span class="o">(</span><span class="nc">Uri</span><span class="o">.</span><span class="na">fromFile</span><span class="o">(</span><span class="n">file</span><span class="o">));</span>
<span class="nc">Log</span><span class="o">.</span><span class="na">d</span><span class="o">(</span><span class="no">TAG</span><span class="o">,</span> <span class="s">"Send event to listener."</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<h4 id="通过contentobserver间接捕获">通过ContentObserver间接捕获</h4>
<p>这种方式算是目前最可靠,灵活性最好的方式了。实现起来先对其他几种方式要做的事也先对多一点,一下是我的实现,这个实现针对国内的一些手机做了适配,覆盖到了一些比较极端的情况:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">ScreenshotManager</span> <span class="o">{</span>
<span class="kd">private</span> <span class="nc">OnScreenshotTakenListener</span> <span class="n">mListener</span><span class="o">;</span>
<span class="kd">private</span> <span class="nc">String</span> <span class="n">mLastTakenPath</span><span class="o">;</span>
<span class="kd">private</span> <span class="nc">Context</span> <span class="n">mContext</span><span class="o">;</span>
<span class="kd">private</span> <span class="nc">Timer</span> <span class="n">mCheckImageTimer</span><span class="o">;</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">mCount</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
<span class="cm">/**
* Internal storage observer
*/</span>
<span class="kd">private</span> <span class="nc">ScreenshotObserver</span> <span class="n">mInternalObserver</span><span class="o">;</span>
<span class="cm">/**
* External storage observer
*/</span>
<span class="kd">private</span> <span class="nc">ScreenshotObserver</span> <span class="n">mExternalObserver</span><span class="o">;</span>
<span class="kd">private</span> <span class="nc">HandlerThread</span> <span class="n">mHandlerThread</span><span class="o">;</span>
<span class="kd">private</span> <span class="nc">Handler</span> <span class="n">mContenHandler</span><span class="o">;</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">String</span><span class="o">[]</span> <span class="no">MEDIA_PROJECTIONS</span> <span class="o">=</span> <span class="o">{</span>
<span class="nc">MediaStore</span><span class="o">.</span><span class="na">Images</span><span class="o">.</span><span class="na">ImageColumns</span><span class="o">.</span><span class="na">DATA</span><span class="o">,</span>
<span class="nc">MediaStore</span><span class="o">.</span><span class="na">Images</span><span class="o">.</span><span class="na">ImageColumns</span><span class="o">.</span><span class="na">DATE_TAKEN</span><span class="o">,</span>
<span class="o">};</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">String</span><span class="o">[]</span> <span class="no">KEYWORDS</span> <span class="o">=</span> <span class="o">{</span>
<span class="s">"screenshot"</span><span class="o">,</span> <span class="s">"screen_shot"</span><span class="o">,</span> <span class="s">"screen-shot"</span><span class="o">,</span> <span class="s">"screen shot"</span><span class="o">,</span>
<span class="s">"screencapture"</span><span class="o">,</span> <span class="s">"screen_capture"</span><span class="o">,</span> <span class="s">"screen-capture"</span><span class="o">,</span> <span class="s">"screen capture"</span><span class="o">,</span>
<span class="s">"screencap"</span><span class="o">,</span> <span class="s">"screen_cap"</span><span class="o">,</span> <span class="s">"screen-cap"</span><span class="o">,</span> <span class="s">"screen cap"</span><span class="o">,</span> <span class="s">"截屏"</span>
<span class="o">};</span>
<span class="kd">public</span> <span class="nf">ScreenshotManager</span><span class="o">(</span><span class="nc">Context</span> <span class="n">context</span><span class="o">,</span> <span class="nc">OnScreenshotTakenListener</span> <span class="n">listener</span><span class="o">)</span> <span class="o">{</span>
<span class="n">mContext</span> <span class="o">=</span> <span class="n">context</span><span class="o">;</span>
<span class="n">mListener</span> <span class="o">=</span> <span class="n">listener</span><span class="o">;</span>
<span class="n">mLastTakenPath</span> <span class="o">=</span> <span class="n">getLastTakenPath</span><span class="o">();</span>
<span class="n">mHandlerThread</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">HandlerThread</span><span class="o">(</span><span class="s">"Screenshot_Observer"</span><span class="o">);</span>
<span class="n">mHandlerThread</span><span class="o">.</span><span class="na">start</span><span class="o">();</span>
<span class="n">mContenHandler</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Handler</span><span class="o">(</span><span class="n">mHandlerThread</span><span class="o">.</span><span class="na">getLooper</span><span class="o">());</span>
<span class="n">mInternalObserver</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ScreenshotObserver</span><span class="o">(</span><span class="n">mContenHandler</span><span class="o">,</span> <span class="nc">MediaStore</span><span class="o">.</span><span class="na">Images</span><span class="o">.</span><span class="na">Media</span><span class="o">.</span><span class="na">INTERNAL_CONTENT_URI</span><span class="o">);</span>
<span class="n">mExternalObserver</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ScreenshotObserver</span><span class="o">(</span><span class="n">mContenHandler</span><span class="o">,</span> <span class="nc">MediaStore</span><span class="o">.</span><span class="na">Images</span><span class="o">.</span><span class="na">Media</span><span class="o">.</span><span class="na">EXTERNAL_CONTENT_URI</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">startScreenshotObserver</span><span class="o">()</span> <span class="o">{</span>
<span class="n">mContext</span><span class="o">.</span><span class="na">getContentResolver</span><span class="o">().</span><span class="na">registerContentObserver</span><span class="o">(</span>
<span class="nc">MediaStore</span><span class="o">.</span><span class="na">Images</span><span class="o">.</span><span class="na">Media</span><span class="o">.</span><span class="na">INTERNAL_CONTENT_URI</span><span class="o">,</span>
<span class="kc">false</span><span class="o">,</span>
<span class="n">mInternalObserver</span>
<span class="o">);</span>
<span class="n">mContext</span><span class="o">.</span><span class="na">getContentResolver</span><span class="o">().</span><span class="na">registerContentObserver</span><span class="o">(</span>
<span class="nc">MediaStore</span><span class="o">.</span><span class="na">Images</span><span class="o">.</span><span class="na">Media</span><span class="o">.</span><span class="na">EXTERNAL_CONTENT_URI</span><span class="o">,</span>
<span class="kc">false</span><span class="o">,</span>
<span class="n">mExternalObserver</span>
<span class="o">);</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">stopScreenshotObserver</span><span class="o">()</span> <span class="o">{</span>
<span class="n">mContext</span><span class="o">.</span><span class="na">getContentResolver</span><span class="o">().</span><span class="na">unregisterContentObserver</span><span class="o">(</span><span class="n">mInternalObserver</span><span class="o">);</span>
<span class="n">mContext</span><span class="o">.</span><span class="na">getContentResolver</span><span class="o">().</span><span class="na">unregisterContentObserver</span><span class="o">(</span><span class="n">mExternalObserver</span><span class="o">);</span>
<span class="n">releaseTimer</span><span class="o">();</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">handleMediaContentChange</span><span class="o">(</span><span class="nc">Uri</span> <span class="n">contentUri</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">Cursor</span> <span class="n">cursor</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="k">try</span> <span class="o">{</span>
<span class="c1">// 数据改变时查询数据库中最后加入的一条数据</span>
<span class="n">cursor</span> <span class="o">=</span> <span class="n">mContext</span><span class="o">.</span><span class="na">getContentResolver</span><span class="o">().</span><span class="na">query</span><span class="o">(</span>
<span class="n">contentUri</span><span class="o">,</span>
<span class="no">MEDIA_PROJECTIONS</span><span class="o">,</span>
<span class="kc">null</span><span class="o">,</span>
<span class="kc">null</span><span class="o">,</span>
<span class="nc">MediaStore</span><span class="o">.</span><span class="na">Images</span><span class="o">.</span><span class="na">ImageColumns</span><span class="o">.</span><span class="na">DATE_ADDED</span> <span class="o">+</span> <span class="s">" desc limit 1"</span>
<span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">cursor</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">cursor</span><span class="o">.</span><span class="na">moveToFirst</span><span class="o">())</span> <span class="o">{</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">// 获取各列的索引</span>
<span class="kt">int</span> <span class="n">dataIndex</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="na">getColumnIndex</span><span class="o">(</span><span class="nc">MediaStore</span><span class="o">.</span><span class="na">Images</span><span class="o">.</span><span class="na">ImageColumns</span><span class="o">.</span><span class="na">DATA</span><span class="o">);</span>
<span class="kt">int</span> <span class="n">dateTakenIndex</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="na">getColumnIndex</span><span class="o">(</span><span class="nc">MediaStore</span><span class="o">.</span><span class="na">Images</span><span class="o">.</span><span class="na">ImageColumns</span><span class="o">.</span><span class="na">DATE_TAKEN</span><span class="o">);</span>
<span class="c1">// 获取行数据</span>
<span class="nc">String</span> <span class="n">data</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="na">getString</span><span class="o">(</span><span class="n">dataIndex</span><span class="o">);</span>
<span class="kt">long</span> <span class="n">dateTaken</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="na">getLong</span><span class="o">(</span><span class="n">dateTakenIndex</span><span class="o">);</span>
<span class="c1">// 处理获取到的第一行数据</span>
<span class="n">handleMediaRowData</span><span class="o">(</span><span class="n">data</span><span class="o">,</span> <span class="n">dateTaken</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">Exception</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">cursor</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&&</span> <span class="o">!</span><span class="n">cursor</span><span class="o">.</span><span class="na">isClosed</span><span class="o">())</span> <span class="o">{</span>
<span class="n">cursor</span><span class="o">.</span><span class="na">close</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">handleMediaRowData</span><span class="o">(</span><span class="nc">String</span> <span class="n">data</span><span class="o">,</span> <span class="kt">long</span> <span class="n">dateTaken</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="nc">TextUtils</span><span class="o">.</span><span class="na">isEmpty</span><span class="o">(</span><span class="n">data</span><span class="o">))</span>
<span class="k">return</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">checkScreenShot</span><span class="o">(</span><span class="n">data</span><span class="o">,</span> <span class="n">dateTaken</span><span class="o">))</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">data</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">mLastTakenPath</span><span class="o">))</span> <span class="o">{</span>
<span class="n">mLastTakenPath</span> <span class="o">=</span> <span class="n">data</span><span class="o">;</span>
<span class="kd">final</span> <span class="nc">File</span> <span class="n">file</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">File</span><span class="o">(</span><span class="n">data</span><span class="o">);</span>
<span class="k">if</span><span class="o">(</span><span class="kc">null</span> <span class="o">==</span> <span class="nc">BitmapFactory</span><span class="o">.</span><span class="na">decodeFile</span><span class="o">(</span><span class="n">file</span><span class="o">.</span><span class="na">getPath</span><span class="o">()))</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">mCheckImageTimer</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">mCheckImageTimer</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Timer</span><span class="o">();</span>
<span class="o">}</span>
<span class="n">mCheckImageTimer</span><span class="o">.</span><span class="na">schedule</span><span class="o">(</span><span class="k">new</span> <span class="nc">TimerTask</span><span class="o">()</span> <span class="o">{</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">run</span><span class="o">()</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">mCount</span> <span class="o">></span> <span class="mi">10</span><span class="o">)</span> <span class="o">{</span>
<span class="n">mCheckImageTimer</span><span class="o">.</span><span class="na">cancel</span><span class="o">();</span>
<span class="n">mCheckImageTimer</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span>
<span class="nc">Bitmap</span> <span class="n">image</span> <span class="o">=</span> <span class="nc">BitmapFactory</span><span class="o">.</span><span class="na">decodeFile</span><span class="o">(</span><span class="n">mLastTakenPath</span><span class="o">);</span>
<span class="k">if</span><span class="o">(</span><span class="n">image</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">mListener</span><span class="o">.</span><span class="na">onScreenshotTaken</span><span class="o">(</span><span class="n">mLastTakenPath</span><span class="o">);</span>
<span class="n">mCheckImageTimer</span><span class="o">.</span><span class="na">cancel</span><span class="o">();</span>
<span class="n">mCheckImageTimer</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="n">mCount</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">mCount</span><span class="o">++;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">},</span> <span class="mi">0</span><span class="o">,</span> <span class="mi">1000</span><span class="o">);</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">mListener</span><span class="o">.</span><span class="na">onScreenshotTaken</span><span class="o">(</span><span class="n">mLastTakenPath</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="n">mLastTakenPath</span> <span class="o">=</span> <span class="n">data</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">boolean</span> <span class="nf">checkScreenShot</span><span class="o">(</span><span class="nc">String</span> <span class="n">data</span><span class="o">,</span> <span class="kt">long</span> <span class="n">dateTaken</span><span class="o">)</span> <span class="o">{</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="na">toLowerCase</span><span class="o">();</span>
<span class="c1">// 判断图片路径是否含有指定的关键字之一, 如果有, 则认为当前截屏了</span>
<span class="k">for</span> <span class="o">(</span><span class="nc">String</span> <span class="n">keyWork</span> <span class="o">:</span> <span class="no">KEYWORDS</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">data</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="n">keyWork</span><span class="o">))</span> <span class="o">{</span>
<span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="nc">String</span> <span class="nf">getLastTakenPath</span><span class="o">()</span> <span class="o">{</span>
<span class="nc">Cursor</span> <span class="n">cursor</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="nc">String</span> <span class="n">path</span> <span class="o">=</span> <span class="s">""</span><span class="o">;</span>
<span class="k">try</span> <span class="o">{</span>
<span class="c1">// 数据改变时查询数据库中最后加入的一条数据</span>
<span class="n">cursor</span> <span class="o">=</span> <span class="n">mContext</span><span class="o">.</span><span class="na">getContentResolver</span><span class="o">().</span><span class="na">query</span><span class="o">(</span>
<span class="nc">MediaStore</span><span class="o">.</span><span class="na">Images</span><span class="o">.</span><span class="na">Media</span><span class="o">.</span><span class="na">INTERNAL_CONTENT_URI</span><span class="o">,</span>
<span class="no">MEDIA_PROJECTIONS</span><span class="o">,</span>
<span class="kc">null</span><span class="o">,</span>
<span class="kc">null</span><span class="o">,</span>
<span class="nc">MediaStore</span><span class="o">.</span><span class="na">Images</span><span class="o">.</span><span class="na">ImageColumns</span><span class="o">.</span><span class="na">DATE_ADDED</span> <span class="o">+</span> <span class="s">" desc limit 1"</span>
<span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">cursor</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="s">""</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">cursor</span><span class="o">.</span><span class="na">moveToFirst</span><span class="o">())</span> <span class="o">{</span>
<span class="k">return</span> <span class="s">""</span><span class="o">;</span>
<span class="o">}</span>
<span class="kt">int</span> <span class="n">dataIndex</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="na">getColumnIndex</span><span class="o">(</span><span class="nc">MediaStore</span><span class="o">.</span><span class="na">Images</span><span class="o">.</span><span class="na">ImageColumns</span><span class="o">.</span><span class="na">DATA</span><span class="o">);</span>
<span class="kt">int</span> <span class="n">dateTakenIndex</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="na">getColumnIndex</span><span class="o">(</span><span class="nc">MediaStore</span><span class="o">.</span><span class="na">Images</span><span class="o">.</span><span class="na">ImageColumns</span><span class="o">.</span><span class="na">DATE_TAKEN</span><span class="o">);</span>
<span class="n">path</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="na">getString</span><span class="o">(</span><span class="n">dataIndex</span><span class="o">);</span>
<span class="n">cursor</span> <span class="o">=</span> <span class="n">mContext</span><span class="o">.</span><span class="na">getContentResolver</span><span class="o">().</span><span class="na">query</span><span class="o">(</span>
<span class="nc">MediaStore</span><span class="o">.</span><span class="na">Images</span><span class="o">.</span><span class="na">Media</span><span class="o">.</span><span class="na">EXTERNAL_CONTENT_URI</span><span class="o">,</span>
<span class="no">MEDIA_PROJECTIONS</span><span class="o">,</span>
<span class="kc">null</span><span class="o">,</span>
<span class="kc">null</span><span class="o">,</span>
<span class="nc">MediaStore</span><span class="o">.</span><span class="na">Images</span><span class="o">.</span><span class="na">ImageColumns</span><span class="o">.</span><span class="na">DATE_ADDED</span> <span class="o">+</span> <span class="s">" desc limit 1"</span>
<span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">cursor</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="s">""</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">cursor</span><span class="o">.</span><span class="na">moveToFirst</span><span class="o">())</span> <span class="o">{</span>
<span class="k">return</span> <span class="s">""</span><span class="o">;</span>
<span class="o">}</span>
<span class="n">dataIndex</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="na">getColumnIndex</span><span class="o">(</span><span class="nc">MediaStore</span><span class="o">.</span><span class="na">Images</span><span class="o">.</span><span class="na">ImageColumns</span><span class="o">.</span><span class="na">DATA</span><span class="o">);</span>
<span class="kt">int</span> <span class="n">index</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="na">getColumnIndex</span><span class="o">(</span><span class="nc">MediaStore</span><span class="o">.</span><span class="na">Images</span><span class="o">.</span><span class="na">ImageColumns</span><span class="o">.</span><span class="na">DATE_TAKEN</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">index</span> <span class="o">></span> <span class="n">dateTakenIndex</span><span class="o">)</span> <span class="o">{</span>
<span class="n">path</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="na">getString</span><span class="o">(</span><span class="n">dataIndex</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">Exception</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">cursor</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&&</span> <span class="o">!</span><span class="n">cursor</span><span class="o">.</span><span class="na">isClosed</span><span class="o">())</span> <span class="o">{</span>
<span class="n">cursor</span><span class="o">.</span><span class="na">close</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="k">return</span> <span class="n">path</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">releaseTimer</span><span class="o">()</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">mCheckImageTimer</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">mCheckImageTimer</span><span class="o">.</span><span class="na">cancel</span><span class="o">();</span>
<span class="n">mCheckImageTimer</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">interface</span> <span class="nc">OnScreenshotTakenListener</span> <span class="o">{</span>
<span class="kt">void</span> <span class="nf">onScreenshotTaken</span><span class="o">(</span><span class="nc">String</span> <span class="n">path</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kd">class</span> <span class="nc">ScreenshotObserver</span> <span class="kd">extends</span> <span class="nc">ContentObserver</span> <span class="o">{</span>
<span class="kd">private</span> <span class="nc">Uri</span> <span class="n">mContentUri</span><span class="o">;</span>
<span class="kd">public</span> <span class="nf">ScreenshotObserver</span><span class="o">(</span><span class="nc">Handler</span> <span class="n">handler</span><span class="o">,</span> <span class="nc">Uri</span> <span class="n">contentUri</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">super</span><span class="o">(</span><span class="n">handler</span><span class="o">);</span>
<span class="n">mContentUri</span> <span class="o">=</span> <span class="n">contentUri</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onChange</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">selfChange</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">super</span><span class="o">.</span><span class="na">onChange</span><span class="o">(</span><span class="n">selfChange</span><span class="o">);</span>
<span class="n">handleMediaContentChange</span><span class="o">(</span><span class="n">mContentUri</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>这种方式比起FileObserver有一个明显的不同,就是FileObserver得在截屏之前就得知道哪些目录需要监听,而ContentObserver则是在文件系统发生变化的时候去查特定的目录和存储位置,适配起来就相对灵活,只要枚举出这些目录即可。综上,ContentObserver应该是最优的一种实现方式。</p>
</section>
<footer class="post-footer">
<!-- Everything inside the #author tags pulls data from the author -->
<!-- #author-->
<!-- Add Disqus Comments -->
</footer>
</article>
</main>
<aside class="read-next">
<!-- [[! next_post ]] -->
<a class="read-next-story no-cover" href="/select-qrc-code-library-in-andord">
<section class="post">
<h2>Android开发中二维码库的选用</h2>
<p>在现今的移动App开发中,二维码的使用场景变得越来越普遍,最近我要开发的一个需求就必须生成二维码,自然就面临二维码库选用的问题,因为大名鼎鼎的ZXing的存在,这也本不是什么特别需要考虑的问题。但是因为ZXing的大而全,要在一款只是将二维码作为一个特定使用场景下的一个功能的App,完全引入ZXing就有点过了,所以就面临了ZXing库的裁剪问题。但是裁剪这样一个大而全的多平台支持的库也不是什么简单的事情,所以我也顺便调研了其他的二维码库作为参考:
* OnBarCode http://www.onbarcode.com/products/android_barcode/barcodes/qrcode.html#intro
* Barcode4j http://barcode4j.sourceforge.net/
* QRGenerator
* https://github.com/androidmads/QRGenerator
* https://androidmads.blogspot.com/2016/07/qr-code-generator-library.html
当然了,这些库实现我的需求都是没有问题的,但是最终我还是在我的项目中选用了ZXing,一来是因为它在业界的广泛使用得到了充分的验证,二来是因为我们项目组其他的同事也会在未来的需求中使用到,所以必须选用一个长期的可靠的的解决方案。当然了,我是选用了一版裁剪后的ZXing库。至于这个库的使用其实没有什么好说的,因为使用起来非常简单,简单的几个事例就能明白如何应用。
</p>
</section>
</a>
<!-- [[! /next_post ]] -->
<!-- [[! prev_post ]] -->
<a class="read-next-story prev no-cover" href="/install-emacs-on-ubuntu">
<section class="post">
<h2>Intall Emacs on Ubuntu</h2>
<p>Install Emacs 25 on Ubuntu from source is very easy, follow these steps below could...</p>
</section>
</a>
<!-- [[! /prev_post ]] -->
</aside>
<!-- /post -->
<footer class="site-footer clearfix">
<section class="copyright"><a href="/">与机器,人,神共舞</a> © 2024</section>
</footer>
</div>
<!-- [[! Ghost outputs important scripts and data with this tag ]] -->
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<!-- [[! The main JavaScript file for Casper ]] -->
<script type="text/javascript" src="/assets/js/jquery.fitvids.js"></script>
<script type="text/javascript" src="/assets/js/index.js"></script>
<!-- Add Google Analytics -->
<!-- Google Analytics Tracking code -->
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-78960009-1', 'auto');
ga('send', 'pageview');
</script>
</body>
</html>