-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
496 lines (409 loc) · 147 KB
/
atom.xml
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
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>加贝龙</title>
<link href="/atom.xml" rel="self"/>
<link href="http://yoursite.com/"/>
<updated>2017-04-08T07:22:18.000Z</updated>
<id>http://yoursite.com/</id>
<author>
<name>Holo Wang</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>Cordova : 自定义Plugin</title>
<link href="http://yoursite.com/2017/04/08/Cordova_custom_plugin/"/>
<id>http://yoursite.com/2017/04/08/Cordova_custom_plugin/</id>
<published>2017-04-08T07:18:44.000Z</published>
<updated>2017-04-08T07:22:18.000Z</updated>
<content type="html"><![CDATA[<h3 id="Cordova之自定义Plugin"><a href="#Cordova之自定义Plugin" class="headerlink" title="Cordova之自定义Plugin"></a>Cordova之自定义Plugin</h3><p>本文通过自定义一个简单的Toast插件来介绍一下如何从0开始自定义自己的plugin,基于cordova6.2.1版本。在这之前你需要创建一个Cordova项目,如何创建一个Corodva项目可以参考<a href="http://kidloserme.github.io/2016/11/25/Cordova_Plugin_2016-11-25/" target="_blank" rel="external">Cordova:Plugin</a>中的1-5步骤,这里不在赘述。</p>
<h4 id="1-原生插件开发"><a href="#1-原生插件开发" class="headerlink" title="1.原生插件开发"></a>1.原生插件开发</h4><p>首先创建一个<code>ToastPlugin</code>,我把他放在了主工程中,所有自定义的<code>Plugin</code>都是继承自<code>CordovaPlugin</code>,然后重写<code>CordovaPlugin</code>的<code>execute</code>方法来实现插件的功能,<code>CordovaPlugin</code>中定义了三个<code>execute</code>,这里我选择重写方法<code>public boolean execute(String action, JSONArray args, CallbackContext callbackContext)</code>,至于重写哪个好,全凭自己喜欢。下面看下<code>ToastPlugin</code>的代码:</p>
<a id="more"></a>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ToastPlugin</span> <span class="keyword">extends</span> <span class="title">CordovaPlugin</span> </span>{</div><div class="line"></div><div class="line"> <span class="keyword">private</span> String ACTION_TOAST = <span class="string">"toast"</span>;</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * <span class="doctag">@param</span> action 具体要执行的动作,由H5传入</div><div class="line"> * <span class="doctag">@param</span> args 参数列表,H5传入</div><div class="line"> * <span class="doctag">@param</span> callbackContext 回调</div><div class="line"> * <span class="doctag">@return</span> true:有效的action false:无效的action</div><div class="line"> * <span class="doctag">@throws</span> JSONException</div><div class="line"> */</div><div class="line"> <span class="meta">@Override</span></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">execute</span><span class="params">(String action, JSONArray args,</span></span></div><div class="line"> CallbackContext callbackContext) <span class="keyword">throws</span> JSONException {</div><div class="line"> <span class="keyword">if</span> (ACTION_TOAST.equals(action)) {</div><div class="line"> toast(args.getString(<span class="number">0</span>), callbackContext);</div><div class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * 处理toast逻辑</div><div class="line"> *</div><div class="line"> * <span class="doctag">@param</span> content toast弹出的内容</div><div class="line"> * <span class="doctag">@param</span> callbackContext 回调</div><div class="line"> */</div><div class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">toast</span><span class="params">(String content, CallbackContext callbackContext)</span> </span>{</div><div class="line"> Toast.makeText(cordova.getActivity(), content, Toast.LENGTH_LONG).show();</div><div class="line"> PluginResult pluginResult = <span class="keyword">new</span> PluginResult(PluginResult.Status.OK,</div><div class="line"> <span class="string">"this is toast callback content !"</span>);</div><div class="line"> callbackContext.sendPluginResult(pluginResult);</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>上面就是一个简单的插件,<code>execute</code>是入口,接收H5发送过来的请求,根据具体的action来执行不同的逻辑,并根据结果来通过<code>callbackContext</code>发送回调结果。<br><strong>参数理解:</strong><br><strong>action:</strong> 应该很好理解的,比如我们现在写的是一个对话框插件,可能就会有按钮操作,那么需要定义三个action:alert, cancel, confirm。根据不同的action执行不同的逻辑。<br><strong>args:</strong> 参数,是一个数组的形式,H5在调用的时候会把参数封装成一个json数组格式的字符串。<br><strong>callbackContext:</strong> 原生插件通过这个参数来给H5发送反馈,当然这个不是必须的,根据需要来写。发送的数据类型为<code>PluginResult</code>,状态<code>PluginResult.Status.OK</code>表示成功,状态’PluginResult.Status.ERROR’表示失败,当然还是有其他类型的状态,可以查看<code>luginResult.Status</code>的具体定义。</p>
<h4 id="2-注册原生插件"><a href="#2-注册原生插件" class="headerlink" title="2.注册原生插件"></a>2.注册原生插件</h4><p>第1步中创建了一个原生插件,下一步就是注册插件,只有注册了插件,在Cordova初始化的时候才能根据注册信息来获取该插件并实例化,后面调用的时候才能找得到它。配置的地方就是res目录下的xml目录下的config.xml文件。在其中加一个节点:<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><?xml version='1.0' encoding='utf-8'?></div><div class="line"><span class="tag"><<span class="name">widget</span> <span class="attr">id</span>=<span class="string">"com.helong.cordova"</span> <span class="attr">version</span>=<span class="string">"1.0.0"</span> </span></div><div class="line"> <span class="attr">xmlns</span>=<span class="string">"http://www.w3.org/ns/widgets"</span> </div><div class="line"> <span class="attr">xmlns:cdv</span>=<span class="string">"http://cordova.apache.org/ns/1.0"</span>></div><div class="line"> <span class="tag"><<span class="name">feature</span> <span class="attr">name</span>=<span class="string">"Whitelist"</span>></span></div><div class="line"> <span class="tag"><<span class="name">param</span> <span class="attr">name</span>=<span class="string">"android-package"</span> <span class="attr">value</span>=<span class="string">"org.apache.cordova.whitelist.WhitelistPlugin"</span> /></span></div><div class="line"> <span class="tag"><<span class="name">param</span> <span class="attr">name</span>=<span class="string">"onload"</span> <span class="attr">value</span>=<span class="string">"true"</span> /></span></div><div class="line"> <span class="tag"></<span class="name">feature</span>></span></div><div class="line"> <span class="tag"><<span class="name">feature</span> <span class="attr">name</span>=<span class="string">"Toast"</span>></span></div><div class="line"> <span class="tag"><<span class="name">param</span> <span class="attr">name</span>=<span class="string">"android-package"</span> <span class="attr">value</span>=<span class="string">"com.helong.plugin.ToastPlugin"</span> /></span></div><div class="line"> <span class="tag"></<span class="name">feature</span>></span></div><div class="line"> .....此处为节省空间省略</div><div class="line"><span class="tag"></<span class="name">widget</span>></span></div></pre></td></tr></table></figure></p>
<p>一个<code>feature</code>代表一个原生插件,属性<code>name</code>是这个原生插件的名字,<code>param</code>的<code>android-package</code>用来指定这个插件的具体实现类。<br>OK,配置完毕,这样原生部分的工作已经完成了。下面看js方面的工作。</p>
<h4 id="3-js插件开发"><a href="#3-js插件开发" class="headerlink" title="3.js插件开发"></a>3.js插件开发</h4><p>首先在assets目录下的plugins目录下创建一个目录,作为新js插件的目录,目录名cordova-plugin-toast,然后在此目录下创建新的目录,目录名www,最后在www目录下创建我们的js插件toast.js,看图:<br><img src="../../../../images/cordova/createjs.png" alt="Alt text"><br>接下来是具体的实现:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">cordova.define(<span class="string">"cordova-plugin-toast.toast"</span>, <span class="function"><span class="keyword">function</span>(<span class="params">require, exports, module</span>) </span>{</div><div class="line"> <span class="keyword">var</span> exec = <span class="built_in">require</span>(<span class="string">'cordova/exec'</span>);</div><div class="line"> <span class="keyword">var</span> platform = <span class="built_in">require</span>(<span class="string">'cordova/platform'</span>);</div><div class="line"> <span class="built_in">module</span>.exports = {</div><div class="line"> <span class="attr">toast</span>: <span class="function"><span class="keyword">function</span>(<span class="params">message, completeCallback</span>) </span>{</div><div class="line"> <span class="keyword">var</span> _message = (<span class="keyword">typeof</span> message === <span class="string">"string"</span> ? message : <span class="built_in">JSON</span>.stringify(message));</div><div class="line"> <span class="comment">//success, fail, service, action, args</span></div><div class="line"> exec(completeCallback, <span class="literal">null</span>, <span class="string">"Toast"</span>, <span class="string">"toast"</span>, [_message]);</div><div class="line"> },</div><div class="line"> };</div><div class="line">});</div></pre></td></tr></table></figure></p>
<p>代码中define的第一个参数”cordova-plugin-toast.toast”是这个plugin的id,在后面会用到。<br>插件的实现部分在module.exports部分,这里面定义了一个函数名字叫<code>toast</code>,有两个参数分别是要展示的内容以及回调,通过exec执行,将内容以及回调传递给原生插件,也就是步骤1中我们写的原生插件。<br><strong>exec说明:</strong><br>exec就是函数<code>function androidExec(success, fail, service, action, args)</code>,具体实现可以看exec.js,在assets/www/corodva-js-src目下,接收的五个参数具体说一下。</p>
<ul>
<li>success是成功回调,对应步骤1中PluginResult的Status.OK</li>
<li>fail是失败回调,对应PluginResult的Status.ERROR</li>
<li>service就是我们原生插件名称,也就是步骤2中注册原生插件中<code>feature</code>节点的<code>name</code>属性定义的名字。</li>
<li>action就是我们原生插件实现是定义的一系列action,步骤一中也有说明,原生插件接到请求根据service找到插件,然后再根据action执行具体的逻辑。</li>
<li>args就是参数,json数组格式,步骤一中也有说明<br>好了,js插件开发完毕,下一步跟原生一样,注册插件。</li>
</ul>
<h4 id="3-注册js插件"><a href="#3-注册js插件" class="headerlink" title="3.注册js插件"></a>3.注册js插件</h4><p>找到此文件assets/www/cordova_plugins.js,我们的js插件需要在这里进行注册了才能被访问,因为cordova.js在加载的时候会从这里面读取信息。<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line">cordova.define(<span class="string">'cordova/plugin_list'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">require, exports, module</span>) </span>{</div><div class="line"><span class="built_in">module</span>.exports = [</div><div class="line"> {</div><div class="line"> <span class="string">"id"</span>: <span class="string">"cordova-plugin-toast.toast"</span>,</div><div class="line"> <span class="string">"file"</span>: <span class="string">"plugins/plugin-toast/www/toast.js"</span>,</div><div class="line"> <span class="string">"pluginId"</span>: <span class="string">"cordova-plugin-toast"</span>,</div><div class="line"> <span class="string">"clobbers"</span>: [</div><div class="line"> <span class="string">"toast123"</span></div><div class="line"> ]</div><div class="line"> }</div><div class="line">];</div><div class="line"><span class="built_in">module</span>.exports.metadata = </div><div class="line"><span class="comment">// TOP OF METADATA</span></div><div class="line">{</div><div class="line"> <span class="string">"cordova-plugin-whitelist"</span>: <span class="string">"1.3.2"</span>,</div><div class="line"> <span class="string">"cordova-plugin-toast"</span>: <span class="string">"0.0.1"</span></div><div class="line">};</div><div class="line"><span class="comment">// BOTTOM OF METADATA</span></div><div class="line">});</div></pre></td></tr></table></figure></p>
<p>这里的module.exports是一个Json数组,每一项代表一个插件,说一下插件配置每一项的意思:<br><strong>id:</strong> 就是定义js插件define的第一个参数,在步骤3中已经说明。<br><strong>file:</strong> 很好理解,就是我们js插件所在的路径<br><strong>pluginId:</strong> 插件的pluginId,下面在设置版本信息的时候会用到,其他地方有没有用到,暂时没遇到<br><strong>clobbers:</strong> 这个类似于实例,我们在后面用到js插件的时候就是通过这名称来调用插件里面的函数的,是个数组,可以定义成多个名字。还有另外一种方式,就是使用<code>merges</code>定义,代表允许不同的js插件可以取一个相同的实例名称,例如cordova官方的一个demo如下。<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line">{</div><div class="line"> <span class="string">"id"</span>: <span class="string">"cordova-plugin-dialogs.notification"</span>,</div><div class="line"> <span class="string">"file"</span>: <span class="string">"plugins/cordova-plugin-dialogs/www/notification.js"</span>,</div><div class="line"> <span class="string">"pluginId"</span>: <span class="string">"cordova-plugin-dialogs"</span>,</div><div class="line"> <span class="string">"merges"</span>: [</div><div class="line"> <span class="string">"navigator.notification"</span></div><div class="line"> ]</div><div class="line">},</div><div class="line">{</div><div class="line"> <span class="string">"id"</span>: <span class="string">"cordova-plugin-dialogs.notification_android"</span>,</div><div class="line"> <span class="string">"file"</span>: <span class="string">"plugins/cordova-plugin-dialogs/www/android/notification.js"</span>,</div><div class="line"> <span class="string">"pluginId"</span>: <span class="string">"cordova-plugin-dialogs"</span>,</div><div class="line"> <span class="string">"merges"</span>: [</div><div class="line"> <span class="string">"navigator.notification"</span></div><div class="line"> ]</div><div class="line">}</div></pre></td></tr></table></figure></p>
<p>OK ,js插件已经注册完毕,下面就是使用了吧。</p>
<h4 id="4-调用js插件"><a href="#4-调用js插件" class="headerlink" title="4.调用js插件"></a>4.调用js插件</h4><p>这里用一个比较简单的例子,就是在设备准备好的时候执行这个js。我们在assets/www/js目录下新建一个ready.js文件,然后编码<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">success</span>(<span class="params">message</span>) </span>{</div><div class="line"> alert(message);</div><div class="line">}</div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">onDeviceReady</span>(<span class="params"></span>)</span>{</div><div class="line"> toast123.toast(<span class="string">'Hello My Plaugin !'</span>,success);</div><div class="line">}</div><div class="line"><span class="built_in">document</span>.addEventListener(<span class="string">"deviceready"</span>, onDeviceReady, <span class="literal">false</span>);</div></pre></td></tr></table></figure></p>
<p>嗯,就是监听deviceready事件,然后进行响应,捕获到此事件后进行toast,并接收回调。</p>
<h4 id="5-加载js文件"><a href="#5-加载js文件" class="headerlink" title="5.加载js文件"></a>5.加载js文件</h4><p>插件的开发以及调用都已经开发完毕,最后一步就是执行了吧。这里使用assets/www/index.html,app启动时默认加载这个html,我们就再这里调用4中的ready.js文件。在原先的html中加入js引用<code><script type="text/javascript" src="js/ready.js"></script></code>。<br>万事俱备,只差运行了吧。</p>
<h4 id="6-运行"><a href="#6-运行" class="headerlink" title="6.运行"></a>6.运行</h4><p>看效果图,下面是toast的内容,上面的对话框里的内容就是我们原生插件设置callback时 的内容。<br><img src="../../../../images/cordova/run.png" alt="Alt text"></p>
<p>一个简单的插件完成了,算是入门了,剩下的就要靠自己了。</p>
]]></content>
<summary type="html">
<h3 id="Cordova之自定义Plugin"><a href="#Cordova之自定义Plugin" class="headerlink" title="Cordova之自定义Plugin"></a>Cordova之自定义Plugin</h3><p>本文通过自定义一个简单的Toast插件来介绍一下如何从0开始自定义自己的plugin,基于cordova6.2.1版本。在这之前你需要创建一个Cordova项目,如何创建一个Corodva项目可以参考<a href="http://kidloserme.github.io/2016/11/25/Cordova_Plugin_2016-11-25/">Cordova:Plugin</a>中的1-5步骤,这里不在赘述。</p>
<h4 id="1-原生插件开发"><a href="#1-原生插件开发" class="headerlink" title="1.原生插件开发"></a>1.原生插件开发</h4><p>首先创建一个<code>ToastPlugin</code>,我把他放在了主工程中,所有自定义的<code>Plugin</code>都是继承自<code>CordovaPlugin</code>,然后重写<code>CordovaPlugin</code>的<code>execute</code>方法来实现插件的功能,<code>CordovaPlugin</code>中定义了三个<code>execute</code>,这里我选择重写方法<code>public boolean execute(String action, JSONArray args, CallbackContext callbackContext)</code>,至于重写哪个好,全凭自己喜欢。下面看下<code>ToastPlugin</code>的代码:</p>
</summary>
<category term="Cordova" scheme="http://yoursite.com/categories/Cordova/"/>
<category term="Cordova" scheme="http://yoursite.com/tags/Cordova/"/>
</entry>
<entry>
<title>Android项目集成小米、华为、个推</title>
<link href="http://yoursite.com/2016/11/25/JingoalPush_2016-11-25/"/>
<id>http://yoursite.com/2016/11/25/JingoalPush_2016-11-25/</id>
<published>2016-11-25T11:16:33.000Z</published>
<updated>2016-11-25T11:28:42.000Z</updated>
<content type="html"><![CDATA[<p>为了项目中方便使用,首先要把这三家push sdk集成到一个library项目中,并将通过广播接收到的推送消息统一分发到一个广播中,在主项目中直接引用此项目即可。<br>项目地址:<a href="https://github.com/kidloserme/JingoalPushDemo" target="_blank" rel="external">JingoalPushDemo</a><br>集成很简单:</p>
<h3 id="1-添加项目依赖"><a href="#1-添加项目依赖" class="headerlink" title="1.添加项目依赖"></a>1.添加项目依赖</h3><p>项目中导入pushlibrary,在主项目的build.gradle添加对libray项目的依赖:<br><code>compile project(':pushlibrary')</code></p>
<h3 id="2-申请帐号"><a href="#2-申请帐号" class="headerlink" title="2.申请帐号"></a>2.申请帐号</h3><p>在三个平台注册开发者帐号,并创建自己的应用,获取所需要的appid、appkey等信息,华为的需要打包签名文件的SHA256值,这个在新建华为帐号的时候会有说明。<br>小米推送需要信息:APPID , APPKEY<br>个推推送需要信息:APPID , APPKEY,APPSECRET<br>华为推送需要信息:华为推送客户端不需要设置这些参数,只要保证包名以及打包签名文件的SHA256信息跟开发者平台配置的一样即可。</p>
<a id="more"></a>
<h3 id="3-配置个推so库"><a href="#3-配置个推so库" class="headerlink" title="3.配置个推so库"></a>3.配置个推so库</h3><p>下载个推的so库文件,放入主项目的libs目录下,并在主项目的build.gradle项目中添加依赖配置,位于android节点里面:<br><figure class="highlight gradle"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">sourceSets</span> {</div><div class="line"> main {</div><div class="line"> jniLibs.srcDirs = [<span class="string">'libs'</span>]</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure></p>
<h3 id="4-配置小米、个推的APPID、APPKEY信息"><a href="#4-配置小米、个推的APPID、APPKEY信息" class="headerlink" title="4.配置小米、个推的APPID、APPKEY信息"></a>4.配置小米、个推的APPID、APPKEY信息</h3><p>在defaultConfig节点下添加配置信息,下面配置中的*<em>*</em>我是为了隐藏自己的信息的,有一个地方需要注意,小米的APPID和APPKEY都是纯数字,在配置的时候需要在前面加上\\0,切记。<br><figure class="highlight gradle"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line">defaultConfig {</div><div class="line"> ...(省略默认配置)</div><div class="line"> <span class="comment">//第三方推送所需要的APPID、APPKEY的配置</span></div><div class="line"> manifestPlaceholders = [</div><div class="line"> GETUI_APP_ID : <span class="string">"lHv2qKvQNK9FCSlcL****"</span>,</div><div class="line"> GETUI_APP_KEY : <span class="string">"Tcd6DHuozvAu7iQEl****"</span>,</div><div class="line"> GETUI_APP_SECRET: <span class="string">"SaeqLmuJcy5xjNLz****"</span>,</div><div class="line"> <span class="comment">//因为小米的appkey 和 appid 为纯数字,必须要在前面加上\0,</span></div><div class="line"> <span class="comment">//程序中才能正确从meta-data中读取,下面的\\0的第一个\为转义字符</span></div><div class="line"> MI_PUSH_APPID: <span class="string">"\\028823037615175****"</span>,</div><div class="line"> MI_PUSH_APPKEY: <span class="string">"\\0597175232****"</span>,</div><div class="line"> PACKAGE_NAME : applicationId</div><div class="line"> ]</div><div class="line">}</div></pre></td></tr></table></figure></p>
<h3 id="5-设置debug签名文件"><a href="#5-设置debug签名文件" class="headerlink" title="5.设置debug签名文件"></a>5.设置debug签名文件</h3><p>这个是为了方便测试华为推送而设置的,如果你把默认签名文件的SHA256设置到华为推送配置中,就不用设置了。<br>将debug.keystore拷贝到主项目目录下:<br><img src="../../../../images/pushsdk/keystore.png" alt="DebugKeystore"><br>在build.gradle的android节点下添加配置:<br><figure class="highlight gradle"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line">signingConfigs {</div><div class="line"> debug {</div><div class="line"> storeFile <span class="keyword">file</span>(<span class="string">"debug.keystore"</span>)</div><div class="line"> }</div><div class="line">}</div><div class="line"></div><div class="line">buildTypes {</div><div class="line"> debug {</div><div class="line"> minifyEnabled <span class="keyword">false</span></div><div class="line"> signingConfig signingConfigs.debug</div><div class="line"> }</div><div class="line"> release {</div><div class="line"> minifyEnabled <span class="keyword">false</span></div><div class="line"> proguardFiles getDefaultProguardFile(<span class="string">'proguard-android.txt'</span>), <span class="string">'proguard-rules.pro'</span></div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure></p>
<h3 id="6-清单文件中添加权限配置以及广播接收器"><a href="#6-清单文件中添加权限配置以及广播接收器" class="headerlink" title="6.清单文件中添加权限配置以及广播接收器"></a>6.清单文件中添加权限配置以及广播接收器</h3><p>添加以下权限:<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="comment"><!-- 自定义权限 --></span></div><div class="line"><span class="tag"><<span class="name">uses-permission</span> <span class="attr">android:name</span>=<span class="string">"getui.permission.GetuiService.${PACKAGE_NAME}"</span>/></span></div><div class="line"><span class="comment"><!--替换为第三方应用的包名--></span></div><div class="line"><span class="tag"><<span class="name">permission</span></span></div><div class="line"> <span class="attr">android:name</span>=<span class="string">"getui.permission.GetuiService.${PACKAGE_NAME}"</span></div><div class="line"> <span class="attr">android:protectionLevel</span>=<span class="string">"normal"</span>/></div><div class="line"><span class="tag"><<span class="name">permission</span></span></div><div class="line"> <span class="attr">android:name</span>=<span class="string">"${PACKAGE_NAME}.permission.MIPUSH_RECEIVE"</span></div><div class="line"> <span class="attr">android:protectionLevel</span>=<span class="string">"signature"</span>/></div><div class="line"></div><div class="line"><span class="tag"><<span class="name">uses-permission</span> <span class="attr">android:name</span>=<span class="string">"${PACKAGE_NAME}.permission.MIPUSH_RECEIVE"</span>/></span></div><div class="line"><span class="tag"><<span class="name">uses-permission</span> <span class="attr">android:name</span>=<span class="string">"android.permission.VIBRATE"</span>/></span></div></pre></td></tr></table></figure></p>
<p>配置meta属性:<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line"><span class="comment"><!-- 配置的第三方参数属性 --></span></div><div class="line"><span class="comment"><!-- 个推Push配置 --></span></div><div class="line"><span class="tag"><<span class="name">meta-data</span></span></div><div class="line"> <span class="attr">android:name</span>=<span class="string">"PUSH_APPID"</span></div><div class="line"> <span class="attr">android:value</span>=<span class="string">"${GETUI_APP_ID}"</span>/></div><div class="line"><span class="tag"><<span class="name">meta-data</span></span></div><div class="line"> <span class="attr">android:name</span>=<span class="string">"PUSH_APPKEY"</span></div><div class="line"> <span class="attr">android:value</span>=<span class="string">"${GETUI_APP_KEY}"</span>/></div><div class="line"><span class="tag"><<span class="name">meta-data</span></span></div><div class="line"> <span class="attr">android:name</span>=<span class="string">"PUSH_APPSECRET"</span></div><div class="line"> <span class="attr">android:value</span>=<span class="string">"${GETUI_APP_SECRET}"</span>/></div><div class="line"><span class="comment"><!-- 小米Push配置 --></span></div><div class="line"><span class="tag"><<span class="name">meta-data</span></span></div><div class="line"> <span class="attr">android:name</span>=<span class="string">"MI_PUSH_APPID"</span></div><div class="line"> <span class="attr">android:value</span>=<span class="string">"${MI_PUSH_APPID}"</span>/></div><div class="line"><span class="tag"><<span class="name">meta-data</span></span></div><div class="line"> <span class="attr">android:name</span>=<span class="string">"MI_PUSH_APPKEY"</span></div><div class="line"> <span class="attr">android:value</span>=<span class="string">"${MI_PUSH_APPKEY}"</span>/></div></pre></td></tr></table></figure></p>
<p>添加广播接收器:<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="tag"><<span class="name">receiver</span></span></div><div class="line"> <span class="attr">android:name</span>=<span class="string">"com.jingoal.push.receiver.GeTuiReceiver"</span></div><div class="line"> <span class="attr">android:exported</span>=<span class="string">"false"</span>></div><div class="line"> <span class="tag"><<span class="name">intent-filter</span>></span></div><div class="line"> <span class="tag"><<span class="name">action</span> <span class="attr">android:name</span>=<span class="string">"com.igexin.sdk.action.${GETUI_APP_ID}"</span>/></span></div><div class="line"> <span class="tag"></<span class="name">intent-filter</span>></span></div><div class="line"><span class="tag"></<span class="name">receiver</span>></span></div><div class="line"><span class="tag"><<span class="name">provider</span></span></div><div class="line"> <span class="attr">android:name</span>=<span class="string">"com.igexin.download.DownloadProvider"</span></div><div class="line"> <span class="attr">android:authorities</span>=<span class="string">"downloads.${PACKAGE_NAME}"</span></div><div class="line"> <span class="attr">android:exported</span>=<span class="string">"true"</span></div><div class="line"> <span class="attr">android:process</span>=<span class="string">":igepushservice"</span>/></div></pre></td></tr></table></figure></p>
<h3 id="7-接收消息"><a href="#7-接收消息" class="headerlink" title="7.接收消息"></a>7.接收消息</h3><p>以上0-5的配置完毕之后就剩下最后一步了,在项目中创建一个广播接收器用来接收推送消息!<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">import</span> android.content.Context;</div><div class="line"><span class="keyword">import</span> android.util.Log;</div><div class="line"><span class="keyword">import</span> com.jingoal.push.receiver.JingoalReceiver;</div><div class="line"><span class="keyword">import</span> com.jingoal.push.sdk.JingoalPushManager;</div><div class="line"><span class="keyword">import</span> com.jingoal.pushsdk3.MainActivity;</div><div class="line"></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyJingoalReceiver</span> <span class="keyword">extends</span> <span class="title">JingoalReceiver</span> </span>{</div><div class="line"></div><div class="line"> <span class="meta">@Override</span> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onReceivePassThroughMessage</span><span class="params">(Context context, String message)</span> </span>{</div><div class="line"> Log.i(<span class="string">"holo_push"</span>, <span class="string">"========================"</span>);</div><div class="line"> Log.i(<span class="string">"holo_push"</span>, <span class="string">"透传消息: "</span> + message);</div><div class="line"> <span class="keyword">if</span>(MainActivity.getInstance()!=<span class="keyword">null</span>) {</div><div class="line"> MainActivity.getInstance().setRecvPushMessage(message);</div><div class="line"> }</div><div class="line"> Log.i(<span class="string">"holo_push"</span>, <span class="string">"========================"</span>);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="meta">@Override</span> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onNotificationMessageClicked</span><span class="params">(Context context, String message)</span> </span>{</div><div class="line"> Log.i(<span class="string">"holo_push"</span>, <span class="string">"========================"</span>);</div><div class="line"> Log.i(<span class="string">"holo_push"</span>, <span class="string">"小米消息: "</span> + message);</div><div class="line"> <span class="keyword">if</span>(MainActivity.getInstance()!=<span class="keyword">null</span>) {</div><div class="line"> MainActivity.getInstance().setRecvPushMessage(message);</div><div class="line"> }</div><div class="line"> Log.i(<span class="string">"holo_push"</span>, <span class="string">"========================"</span>);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="meta">@Override</span> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onCommandResult</span><span class="params">(Context context, String command, <span class="keyword">boolean</span> success)</span> </span>{</div><div class="line"> Log.i(<span class="string">"holo_push"</span>, <span class="string">"command :"</span> + command);</div><div class="line"> Log.i(<span class="string">"holo_push"</span>, <span class="string">"command Result :"</span> + success);</div><div class="line"> <span class="keyword">if</span>(JingoalReceiver.COMMAND_REGISTER.equals(command)) {</div><div class="line"> Log.i(<span class="string">"holo_push"</span>,</div><div class="line"> <span class="string">"clientType: "</span> + JingoalPushManager.getClientType() + <span class="string">""</span>);</div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure></p>
<p><code>onReceivePassThroughMessage</code>:用来接收华为和个推的透传消息。<br><code>onNotificationMessageClicked</code>:因为小米推送在程序杀掉后无法接收透传消息,只能接收通知栏消息,所以这里集成的是通知栏自定义动作消息,就是在点击通知栏消息时我们客户端才能拿到真正的消息内容。<br><code>onCommandResult</code>:用来接收客户端注册push,设置别名,删除别名等command的结果的回调,因为华为官方给出服务端的API已经不支持标签和别名,所以这个方法对华为无意义。</p>
<p>接收的Receiver也创建完毕,在清单文件中配置一下就OK啦:<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="tag"><<span class="name">receiver</span> <span class="attr">android:name</span>=<span class="string">".receiver.MyJingoalReceiver"</span>></span></div><div class="line"> <span class="tag"><<span class="name">intent-filter</span>></span></div><div class="line"> <span class="tag"><<span class="name">action</span> <span class="attr">android:name</span>=<span class="string">"com.jingoal.push.receiver.jingoalreceiver"</span>/></span></div><div class="line"> <span class="tag"></<span class="name">intent-filter</span>></span></div><div class="line"><span class="tag"></<span class="name">receiver</span>></span></div></pre></td></tr></table></figure></p>
<p>OK,现在运行项目,通过各开发者平台发送消息看能不能接收到吧。<br>注意:华为的开发者平台推送消息时要通过手机的IMEI号来推送,集成到项目中时,服务端要通过token来推送。</p>
]]></content>
<summary type="html">
<p>为了项目中方便使用,首先要把这三家push sdk集成到一个library项目中,并将通过广播接收到的推送消息统一分发到一个广播中,在主项目中直接引用此项目即可。<br>项目地址:<a href="https://github.com/kidloserme/JingoalPushDemo">JingoalPushDemo</a><br>集成很简单:</p>
<h3 id="1-添加项目依赖"><a href="#1-添加项目依赖" class="headerlink" title="1.添加项目依赖"></a>1.添加项目依赖</h3><p>项目中导入pushlibrary,在主项目的build.gradle添加对libray项目的依赖:<br><code>compile project(&#39;:pushlibrary&#39;)</code></p>
<h3 id="2-申请帐号"><a href="#2-申请帐号" class="headerlink" title="2.申请帐号"></a>2.申请帐号</h3><p>在三个平台注册开发者帐号,并创建自己的应用,获取所需要的appid、appkey等信息,华为的需要打包签名文件的SHA256值,这个在新建华为帐号的时候会有说明。<br>小米推送需要信息:APPID , APPKEY<br>个推推送需要信息:APPID , APPKEY,APPSECRET<br>华为推送需要信息:华为推送客户端不需要设置这些参数,只要保证包名以及打包签名文件的SHA256信息跟开发者平台配置的一样即可。</p>
</summary>
<category term="Push" scheme="http://yoursite.com/categories/Push/"/>
</entry>
<entry>
<title>Cordova:Plugin</title>
<link href="http://yoursite.com/2016/11/25/Cordova_Plugin_2016-11-25/"/>
<id>http://yoursite.com/2016/11/25/Cordova_Plugin_2016-11-25/</id>
<published>2016-11-25T06:37:51.000Z</published>
<updated>2016-11-25T07:09:51.000Z</updated>
<content type="html"><![CDATA[<p>跟着<a href="http://kidloserme.github.io/2016/11/22/Cordova_Helloword_2016-11-22/" target="_blank" rel="external">Cordova:HelloWord</a>搞定了怎么创建一个Android项目之后,看看怎么使用Cordova的Plugin吧。<br>因为使用命令行创建的项目导图AS时报错,有问题,所以这里直接创建一个项目,然后将需要的文件拷贝到项目中去即可。</p>
<blockquote>
<p>1.添加插件</p>
</blockquote>
<p>首先要通过cordova命令添加所需要的插件,此次测试一个比较简单的插件dialog,添加的命令<code>cordova plugin add cordova-plugin-dialogs</code>,看下图:<br><img src="../../../../images/cordova/add_plugin.png" width="70%" align="center"><br>OK,添加成功了,从上图中可以看到进入到android/assets/www/plugins目录中已经有我们刚才添加的插件了,下面开始看怎么使用他吧。</p>
<a id="more"></a>
<blockquote>
<p>2.创建新工程</p>
</blockquote>
<p>下面是心创建的一个全新的项目HelloCordova<br><img src="../../../../images/cordova/create_hello_cordova.png" width="70%" align="center"></p>
<blockquote>
<p>3.引入CordovaLib库</p>
</blockquote>
<h5 id="3-1首先创建一个Library"><a href="#3-1首先创建一个Library" class="headerlink" title="3.1首先创建一个Library"></a>3.1首先创建一个Library</h5><p><img src="../../../../images/cordova/new_lib_module.png" width="70%" align="center"></p>
<p><img src="../../../../images/cordova/cordovalib.png" width="70%" align="center"></p>
<h5 id="3-2拷贝CordovaLib源文件"><a href="#3-2拷贝CordovaLib源文件" class="headerlink" title="3.2拷贝CordovaLib源文件"></a>3.2拷贝CordovaLib源文件</h5><p>Library创建完成后将我们需要的代码拷贝进来,要拷贝的代码在此目录下:<br><img src="../../../../images/cordova/lib_src.png" width="70%" align="center"><br>直接拷贝到项目中:<br><img src="../../../../images/cordova/copySrcToLib.png" width="70%" align="center"></p>
<h5 id="3-3拷贝Plugin源代码"><a href="#3-3拷贝Plugin源代码" class="headerlink" title="3.3拷贝Plugin源代码"></a>3.3拷贝Plugin源代码</h5><p>Plugin的源代码在android/src目录下:<br><img src="../../../../images/cordova/pluginSrc.png" width="70%" align="center"><br>拷贝后:<br><img src="../../../../images/cordova/copyPluginSrcToLib.png" width="70%" align="center"><br>Device是创建项目的时候就有的,dialogs就是我们刚才添加的。</p>
<h5 id="3-4拷贝Cordova配置文件"><a href="#3-4拷贝Cordova配置文件" class="headerlink" title="3.4拷贝Cordova配置文件"></a>3.4拷贝Cordova配置文件</h5><p>下面要拷贝的是res目录下的config文件,同样是拷贝到cordovalib的res目录下:<br><img src="../../../../images/cordova/configfile.png" width="70%" align="center"></p>
<p><img src="../../../../images/cordova/copyConfigToLib.png" width="70%" align="center"><br>config.xml的内容感兴趣的可以自己搜一下,里面主要是配置一些插件信息以及项目信息</p>
<blockquote>
<p>4.拷贝H5资源</p>
</blockquote>
<p>H5资源位于android/assets目录下:<br><img src="../../../../images/cordova/H5Resource.png" width="70%" align="center"></p>
<p>H5资源拷贝到主工程同样的位置:<br><img src="../../../../images/cordova/CopyH5Resource.png" width="70%" align="center"></p>
<blockquote>
<p>5.Activity加载</p>
</blockquote>
<p>首先要在主工程的build.gradle中添加对cordovalib的依赖:<br><img src="../../../../images/cordova/addCompileLib.png" width="70%" align="center"></p>
<p>直接使用android/src下的MainActivity:<br><img src="../../../../images/cordova/main.png" width="70%" align="center"><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line">public class MainActivity extends CordovaActivity {</div><div class="line"> @Override</div><div class="line"> public void onCreate(Bundle savedInstanceState) {</div><div class="line"> super.onCreate(savedInstanceState);</div><div class="line"></div><div class="line"> // enable Cordova apps to be started in the background</div><div class="line"> Bundle extras = getIntent().getExtras();</div><div class="line"> if (extras != null && extras.getBoolean("cdvStartInBackground", false)) {</div><div class="line"> moveTaskToBack(true);</div><div class="line"> }</div><div class="line"></div><div class="line"> Log.e("holo_cordova", "launchUrl: " + launchUrl);</div><div class="line"> // Set by <content src="index.html" /> in config.xml</div><div class="line"> loadUrl(launchUrl);</div><div class="line"></div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure></p>
<p>看注释<code>loadUrl(launchUrl);</code>中的launchUrl是在res/xml/config.xml中配置的,对应的是assets/www/index.html.<br>OK,基本搞定了80%,下面就是对index.html改造,引入我们刚才添加的Plugin dialogs.</p>
<blockquote>
<p>6.在js文件中使用dialogs Plugin</p>
</blockquote>
<p>首先我们在assets/js目录下创建一个js文件,就叫dialogsplugin.js,然后开始编码:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">onConfirm</span>(<span class="params">buttonIndex</span>) </span>{</div><div class="line"> <span class="built_in">console</span>.log(<span class="string">'confirm dialog cancel ..........'</span>);</div><div class="line"> navigator.notification.alert(<span class="string">'You selected button '</span> + buttonIndex);</div><div class="line"> <span class="built_in">console</span>.log(<span class="string">'confirm dialog cancel __________'</span>);</div><div class="line">}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">onDeviceReady</span>(<span class="params"></span>)</span>{</div><div class="line"> <span class="built_in">console</span>.log(<span class="string">'will alert confirm dialog'</span>);</div><div class="line"> navigator.notification.confirm(</div><div class="line"> <span class="string">'You are the winner xx!'</span>, <span class="comment">// message</span></div><div class="line"> onConfirm, <span class="comment">// callback to invoke with index of button pressed</span></div><div class="line"> <span class="string">'Game Over'</span>, <span class="comment">// title</span></div><div class="line"> [<span class="string">'Restart'</span>,<span class="string">'Exit'</span>] <span class="comment">// buttonLabels</span></div><div class="line"> );</div><div class="line"> <span class="built_in">console</span>.log(<span class="string">'confirm dialog alert end'</span>);</div><div class="line">}</div><div class="line"></div><div class="line"><span class="built_in">document</span>.addEventListener(<span class="string">"deviceready"</span>, onDeviceReady, <span class="literal">false</span>);</div></pre></td></tr></table></figure></p>
<p>js编码完成,在html中引入就大功告成了<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><script type="text/javascript" src="js/dialogsplugin.js"></script></div></pre></td></tr></table></figure></p>
<p>然后运行项目,看效果图:<br><img src="../../../../images/cordova/urwinner.png" width="70%" align="center"></p>
]]></content>
<summary type="html">
<p>跟着<a href="http://kidloserme.github.io/2016/11/22/Cordova_Helloword_2016-11-22/">Cordova:HelloWord</a>搞定了怎么创建一个Android项目之后,看看怎么使用Cordova的Plugin吧。<br>因为使用命令行创建的项目导图AS时报错,有问题,所以这里直接创建一个项目,然后将需要的文件拷贝到项目中去即可。</p>
<blockquote>
<p>1.添加插件</p>
</blockquote>
<p>首先要通过cordova命令添加所需要的插件,此次测试一个比较简单的插件dialog,添加的命令<code>cordova plugin add cordova-plugin-dialogs</code>,看下图:<br><img src="../../../../images/cordova/add_plugin.png" width = "70%" align=center /><br>OK,添加成功了,从上图中可以看到进入到android/assets/www/plugins目录中已经有我们刚才添加的插件了,下面开始看怎么使用他吧。</p>
</summary>
<category term="Cordova" scheme="http://yoursite.com/categories/Cordova/"/>
<category term="Cordova" scheme="http://yoursite.com/tags/Cordova/"/>
</entry>
<entry>
<title>Cordova : HelloWord</title>
<link href="http://yoursite.com/2016/11/22/Cordova_Helloword_2016-11-22/"/>
<id>http://yoursite.com/2016/11/22/Cordova_Helloword_2016-11-22/</id>
<published>2016-11-22T10:50:33.000Z</published>
<updated>2016-11-22T11:06:31.000Z</updated>
<content type="html"><![CDATA[<p>开发环境Mac OS,另外Android的开发环境也需要提前搭建好。</p>
<blockquote>
<p>1.安装Node.js</p>
</blockquote>
<p>官网下载最新的<a href="http://nodejs.cn/download/安装包,并安装,安装成功后命令行执行npm" target="_blank" rel="external">http://nodejs.cn/download/安装包,并安装,安装成功后命令行执行npm</a> -version会打印出当前Node的版本号。</p>
<blockquote>
<p>2.安装Cordova</p>
</blockquote>
<p>到Cordova官网,也有安装的步骤:<a href="http://cordova.apache.org/#getstarted" target="_blank" rel="external">http://cordova.apache.org/#getstarted</a><br><code>sudo npm install -g cordova</code>,这一步可能会比较慢,耐心等待。<br>安装完成后命令行执行<code>cordova -v</code>会打印当前Cordova的版本信息。</p>
<blockquote>
<p>3.创建项目</p>
</blockquote>
<p>上面的两个步骤安装完成就可以通过cordova命令创建一个Cordova项目,看一下怎么创建,执行命令:<code>cordova create --help</code>查看帮助信息。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div></pre></td><td class="code"><pre><div class="line">➜ Cordova cordova create --help </div><div class="line">Synopsis</div><div class="line"></div><div class="line"> cordova create <PATH> [ID [NAME [CONFIG]]] [options]</div><div class="line"></div><div class="line">Create a Cordova project</div><div class="line"></div><div class="line"> PATH ......................... Where to create the project</div><div class="line"> ID ........................... Reverse-domain-style package name - used in <widget id></div><div class="line"> NAME ......................... Human readable name</div><div class="line"> CONFIG ....................... json string whose key/values will be included in</div><div class="line"> [PATH]/.cordova/config.json</div><div class="line"></div><div class="line">Options</div><div class="line"></div><div class="line"> --template=<PATH|NPM PACKAGE|GIT URL> ... use a custom template located locally, in NPM, or GitHub.</div><div class="line"> --copy-from|src=<PATH> .................. deprecated, use --template instead.</div><div class="line"> --link-to=<PATH> ........................ symlink to custom www assets without creating a copy.</div><div class="line"> </div><div class="line">Example</div><div class="line"> cordova create myapp com.mycompany.myteam.myapp MyApp</div></pre></td></tr></table></figure></p>
<p>根据最后Example我来创建一个HelloWord的项目:<br><code>cordova create helloword com.holo.helloword HelloWord</code><br>控制台信息:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">➜ Cordova cordova create helloword com.holo.helloword HelloWord</div><div class="line">Using detached cordova-create</div><div class="line">Creating a new cordova project.</div><div class="line">➜ Cordova</div></pre></td></tr></table></figure></p>
<p>说明创建成功了,进入到项目目录下,并看一下helloword有哪些目录<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">➜ Cordova ls</div><div class="line">asApps helloword myApp3 pluginDemos</div><div class="line">➜ Cordova cd helloword </div><div class="line">➜ helloword ls</div><div class="line">config.xml hooks platforms plugins www</div><div class="line">➜ helloword</div></pre></td></tr></table></figure></p>
<p>这时候只是创建了一些基本信息,还不算一个项目,因为要创建的是一个Android项目,所以需要添加android平台,执行<code>cordova platform add android</code>,执行之前看一下platforms目录,是空的。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">➜ helloword cd platforms</div><div class="line">➜ platforms ls</div><div class="line">➜ platforms</div></pre></td></tr></table></figure></p>
<p>执行<code>cordova platform add android</code>:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div></pre></td><td class="code"><pre><div class="line">➜ platforms ls</div><div class="line">➜ platforms cd ..</div><div class="line">➜ helloword cordova platform add android </div><div class="line">Adding android project...</div><div class="line">Creating Cordova project for the Android platform:</div><div class="line"> Path: platforms/android</div><div class="line"> Package: com.holo.helloword</div><div class="line"> Name: HelloWord</div><div class="line"> Activity: MainActivity</div><div class="line"> Android target: android-24</div><div class="line">Subproject Path: CordovaLib</div><div class="line">Android project created with [email protected]</div><div class="line">Discovered plugin "cordova-plugin-whitelist" in config.xml. Adding it to the project</div><div class="line">Fetching plugin "cordova-plugin-whitelist@1" via npm</div><div class="line">Installing "cordova-plugin-whitelist" for android</div><div class="line">ANDROID_HOME=/Users/a1/Library/Android/sdk</div><div class="line">JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home</div><div class="line">Subproject Path: CordovaLib</div><div class="line">Starting a new Gradle Daemon for this build (subsequent builds will be faster).</div><div class="line">Incremental java compilation is an incubating feature.</div><div class="line">:clean</div><div class="line">:CordovaLib:clean</div><div class="line"></div><div class="line">BUILD SUCCESSFUL</div><div class="line"></div><div class="line">Total time: 8.353 secs</div><div class="line"></div><div class="line"> This plugin is only applicable for versions of cordova-android greater than 4.0. If you have a previous platform version, you do *not* need this plugin since the whitelist will be built in.</div><div class="line"> </div><div class="line">➜ helloword</div></pre></td></tr></table></figure></p>
<p>OK ,android项目创建成功了,如果中间遇到什么问题,请根据控制台中输出的错误信息修正就行了,我刚开始的时候是没安装Android sdk platfrom 24 就报错了。再次进入platforms文件夹:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">➜ helloword cd platforms</div><div class="line">➜ platforms ls</div><div class="line">android platforms.json</div><div class="line">➜ platforms</div></pre></td></tr></table></figure></p>
<p>会有一个android目录,这个就是一个继承了Cordova的安卓项目了。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">➜ android ls </div><div class="line">AndroidManifest.xml android.json build.gradle gradle libs project.properties settings.gradle</div><div class="line">CordovaLib assets cordova gradlew platform_www res src</div><div class="line">➜ android</div></pre></td></tr></table></figure></p>
<p>下面编译一下:<code>android cordova build android --info</code>.编译成功后进入下面的目录:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">➜ android cd build/outputs/apk </div><div class="line">➜ apk ls</div><div class="line">android-debug.apk</div><div class="line">➜ apk</div></pre></td></tr></table></figure></p>
<p>会有一个android-debug.apk文件,安装到手机上之后是下面这个样子:<br><img src="../../../../images/cordova_hello.png" width="40%" align="center"><br>既然显示的是HTML文件,那这个是哪个呢?<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">➜ android cd assets/www/ </div><div class="line">➜ www ls</div><div class="line">cordova-js-src cordova.js cordova_plugins.js css img index.html js</div><div class="line">➜ www</div></pre></td></tr></table></figure></p>
<p>就是assets/www目录下的index.html,这个是在res/xml/config.xml中配置的。<br>OK,第一步走的很艰难啊,看似简单,但是从0开始到运行一个HelloWord还是经过了很多心血的,不过第一步成功了,后面就好办多了^_^。</p>
<p>参考:<a href="http://www.cnblogs.com/zhoujg/p/4560998.html" target="_blank" rel="external">http://www.cnblogs.com/zhoujg/p/4560998.html</a></p>
]]></content>
<summary type="html">
如何搭建Cordova所需的环境以及创建第一个Cordova HelloWord项目
</summary>
<category term="Cordova" scheme="http://yoursite.com/categories/Cordova/"/>
<category term="Cordova" scheme="http://yoursite.com/tags/Cordova/"/>
</entry>
<entry>
<title>操作符Create</title>
<link href="http://yoursite.com/2016/09/24/RxJava_Create_2016-09-24/"/>
<id>http://yoursite.com/2016/09/24/RxJava_Create_2016-09-24/</id>
<published>2016-09-24T08:22:49.000Z</published>
<updated>2016-09-24T08:22:49.000Z</updated>
<content type="html"><![CDATA[<h3 id="1-Observables"><a href="#1-Observables" class="headerlink" title="1.Observables"></a>1.Observables</h3><p> 先认识几个重要的概念 </p>
<ul>
<li><strong>Observable</strong>:一个可观察对象或者被观察者</li>
<li><strong>Observer</strong>:观察者(订阅者)</li>
<li><strong>Subscribe</strong>:Observer的子类,比Observer多了onStart和unsubscribe两个方法</li>
</ul>
<p>在RxJava中,一个实现了Observer接口的对象可以订阅(subscribe)一个Observable 类的实例。订阅者(subscriber)对Observable发射(emit)的任何数据或数据序列作出响应。</p>
<a id="more"></a>
<h3 id="2-操作符Create"><a href="#2-操作符Create" class="headerlink" title="2.操作符Create"></a>2.操作符Create</h3><blockquote>
<p><strong>2.1 概要步骤:</strong></p>
</blockquote>
<ol>
<li>创建被观察者 <font style="color:red">Observable observable = new Observable();</font></li>
<li>创建观察者 <font color="green">Observer observer = new Observer();</font></li>
<li>观察者订阅被观察者 <font style="color:red">observable</font>.subscribe(<font color="green">observer</font>);</li>
</ol>
<blockquote>
<p><strong>2.2 实际使用:</strong></p>
</blockquote>
<pre style="background:#23241f;padding:7px 0px 0px 20px"><code style="background:#23241f;color:red;">
<span style="color:white">1.创建被观察者</span>
Observable<<span>String</span>> observable = Observable.create(<span>new</span> Observable.OnSubscribe<<span>String</span>>(){<br> <span>@Override</span> public <span>void</span> call(Subscriber<? <span>super</span> <span>String</span>> subscriber) {<br> <span style="color:gray">// TODO(HeLong.W): todo somthing</span><br> }<br>});<br>
</code></pre>
<pre style="background:#23241f;padding:7px 0px 0px 20px"><code style="background:#23241f;color:green;">
<span style="color:white">2.创建观察者</span>
Observer<String> observer = new Observer<String>() {
@Override public void onCompleted() {
}
@Override public void onError(Throwable e) {
}
@Override public void onNext(String o) {
}
};
<br></code></pre>
<pre style="color:white;background:#23241f;padding:7px 0px 0px 20px"><code style="background:#23241f;">
<span>3.观察者订阅被观察者</span><br><font style="color:red;">observable</font>.subscribe(<font style="color:green;">observer</font>);
</code>
</pre>
<pre style="color:white;background:#23241f;padding:7px 0px 0px 20px"><code style="background:#23241f;">
综合1、2、3来写:
<span style="color:red">Observable.create(new Observable.OnSubscribe<String>() {
@Override public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("Hello");
subscriber.onCompleted();
}
})</span>.subscribe(<span style="color:green">new Subscriber<String>() {
@Override public void onCompleted() {
System.out.println("onCompleted exe");
}
@Override public void onError(Throwable e) {
}
@Override public void onNext(String s) {
System.out.println(s);
}
}</span>);<br>
</code></pre>
<blockquote>
<p><strong>2.3 源码分析</strong></p>
</blockquote>
<p>先看一下<code>Observable.create()</code>了什么</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/*Observable.class*/</span></div><div class="line"><span class="keyword">public</span> <span class="keyword">static</span> <T> <span class="function">Observable<T> <span class="title">create</span><span class="params">(OnSubscribe<T> f)</span> </span>{</div><div class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Observable<T>(hook.onCreate(f));</div><div class="line">}</div></pre></td></tr></table></figure>
<p>create方法很简单,就是调用了默认的构造器,并且传入一个构造器需要的参数,参数值由<code>hook.onCreate(f)</code>返回,先看看这个<code>hook.onCreate(f)</code>是什么鬼:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/*Observable.class 中定义的hookd变量*/</span></div><div class="line">RxJavaObservableExecutionHook hook = RxJavaPlugins.getInstance().getObservableExecutionHook();</div><div class="line"></div><div class="line"><span class="comment">/*RxJavaObservableExecutionHook.class*/</span></div><div class="line"><span class="keyword">public</span> <T> <span class="function">OnSubscribe<T> <span class="title">onCreate</span><span class="params">(OnSubscribe<T> f)</span> </span>{</div><div class="line"> <span class="keyword">return</span> f;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>从上面的代码可以看到<code>hook.onCreate(f)</code>什么也没做,就是直接返回f,接下来看看默认的构造器干什么了:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">protected</span> <span class="title">Observable</span><span class="params">(OnSubscribe<T> f)</span> </span>{</div><div class="line"> <span class="keyword">this</span>.onSubscribe = f;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>也是很简单的给自己的成员变量<code>onSubscribe</code>赋值而已。那么接下来看看这个<code>OnSubscribe</code>是什么呢?从上面的代码看OnSubscribe是<code>Observable</code>的一个内部类:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">OnSubscribe</span><<span class="title">T</span>> <span class="keyword">extends</span> <span class="title">Action1</span><<span class="title">Subscriber</span><? <span class="title">super</span> <span class="title">T</span>>> </span>{</div><div class="line"> <span class="comment">// cover for generics insanity</span></div><div class="line">}</div></pre></td></tr></table></figure>
<p>额,原来是一个接口,看他的超类定义:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * A one-argument action.</div><div class="line"> * <span class="doctag">@param</span> <T> the first argument type</div><div class="line"> */</div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Action1</span><<span class="title">T</span>> <span class="keyword">extends</span> <span class="title">Action</span> </span>{</div><div class="line"> <span class="function"><span class="keyword">void</span> <span class="title">call</span><span class="params">(T t)</span></span>;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>也很简洁,就是一个带有一个泛型参数的接口,那么上面的子类<code>OnSubscribe</code>就是指定了这个泛型的类型为<code>Subscriber</code>类型的,而指定的这个<code>Subscriber</code>就是后面要说的观察者。</p>
<p>看完了被观察者,再来看看观察者,一个接口类,提供了三个接口:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Observer</span><<span class="title">T</span>> </span>{</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">void</span> <span class="title">onCompleted</span><span class="params">()</span></span>;</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">void</span> <span class="title">onError</span><span class="params">(Throwable e)</span></span>;</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">void</span> <span class="title">onNext</span><span class="params">(T t)</span></span>;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>我们上面设置观察者的时候使用的是<code>Subscriber</code>,那么<code>Subscriber</code>跟<code>Observer</code>的关系是什么?</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">Subscriber</span><<span class="title">T</span>> <span class="keyword">implements</span> <span class="title">Observer</span><<span class="title">T</span>>, <span class="title">Subscription</span></span>{</div><div class="line"> <span class="meta">@Override</span></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">unsubscribe</span><span class="params">()</span> </span>{</div><div class="line"> subscriptions.unsubscribe();</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="meta">@Override</span></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">isUnsubscribed</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">return</span> subscriptions.isUnsubscribed();</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onStart</span><span class="params">()</span> </span>{</div><div class="line"> <span class="comment">// do nothing by default</span></div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>看上去有点复杂,多了几个方法,<code>onStart , unsubscribe , isUnsubscribed</code>.不多做说明,后面会说到,只需要知道<code>Subscriber</code>和<code>Observer</code>是继承关系即可,都可以作为观察者。<br>接下来看最关键的一部分了,观察者与被观察者关联的过程:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/*Observable.class*/</span></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> Subscription <span class="title">subscribe</span><span class="params">(<span class="keyword">final</span> Observer<? <span class="keyword">super</span> T> observer)</span> </span>{</div><div class="line"> <span class="keyword">if</span> (observer <span class="keyword">instanceof</span> Subscriber) {</div><div class="line"> <span class="keyword">return</span> subscribe((Subscriber<? <span class="keyword">super</span> T>)observer);</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> subscribe(<span class="keyword">new</span> ObserverSubscriber<T>(observer));</div><div class="line"> }</div></pre></td></tr></table></figure>
<p>虽然有个if判断,但是两个分支最后走的是同一个方法,所以直接看这个<code>Subscription subscribe(Subscriber<? super T> subscriber)</code>实现:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/*Observable.class*/</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> Subscription <span class="title">subscribe</span><span class="params">(Subscriber<? <span class="keyword">super</span> T> subscriber)</span> </span>{</div><div class="line"> <span class="keyword">return</span> Observable.subscribe(subscriber, <span class="keyword">this</span>);</div><div class="line">}</div></pre></td></tr></table></figure>
<p>额,还没走到真正处理的地方,继续跟,一大波代码来临,终于看见了曙光:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">static</span> <T> <span class="function">Subscription <span class="title">subscribe</span><span class="params">(Subscriber<? <span class="keyword">super</span> T> subscriber, Observable<T> observable)</span> </span>{</div><div class="line"> <span class="keyword">if</span> (subscriber == <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"subscriber can not be null"</span>);</div><div class="line"> }</div><div class="line"> <span class="keyword">if</span> (observable.onSubscribe == <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(<span class="string">"onSubscribe function can not be null."</span>);</div><div class="line"> }</div><div class="line"> subscriber.onStart();</div><div class="line"> <span class="keyword">if</span> (!(subscriber <span class="keyword">instanceof</span> SafeSubscriber)) {</div><div class="line"> subscriber = <span class="keyword">new</span> SafeSubscriber<T>(subscriber);</div><div class="line"> }</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> hook.onSubscribeStart(observable, observable.onSubscribe).call(subscriber);</div><div class="line"> <span class="keyword">return</span> hook.onSubscribeReturn(subscriber);</div><div class="line"> } <span class="keyword">catch</span> (Throwable e) {</div><div class="line"> <span class="comment">//异常处理....</span></div><div class="line"> <span class="keyword">return</span> Subscriptions.unsubscribed();</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>又碰到了<code>hook</code>,看看<code>hook.onSubscribeStart(observable, observable.onSubscribe)</code>这个干嘛的:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <T> <span class="function">OnSubscribe<T> <span class="title">onSubscribeStart</span><span class="params">(Observable<? extends T> observableInstance, <span class="keyword">final</span> OnSubscribe<T> onSubscribe)</span> </span>{</div><div class="line"> <span class="comment">// pass through by default</span></div><div class="line"> <span class="keyword">return</span> onSubscribe;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>依然什么也没做,直接返回了第二个参数<code>onSubscribe</code>,那<code>hook.onSubscribeStart(observable, observable.onSubscribe).call(subscriber);</code>可以替换成<code>observable.onSubscribe.call(subscriber);</code>,接下来关键就看这个<code>call()</code>做了什么?先看看调用这个<code>call</code>的是谁?是<code>observable.onSubscribe</code>,那这个<code>observable.onSubscribe</code>又是谁?他就是我们第一步<code>create</code>时设置的<code>onSubscribe</code>!所以这里的<code>call</code>做了什么,取决于我们!一般我们就在<code>call</code>里面先处理数据,然后调用<code>onNext</code>方法即可。<br>最后看一下还有一个<code>return hook.onSubscribeReturn(subscriber)</code>,看一下内部实现:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <T> <span class="function">Subscription <span class="title">onSubscribeReturn</span><span class="params">(Subscription subscription)</span> </span>{</div><div class="line"> <span class="comment">// pass through by default</span></div><div class="line"> <span class="keyword">return</span> subscription;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>依然什么也没做,把参数直接返回了。那么返回的这个Subscription是干嘛用的,我们来看看:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Subscription</span> </span>{</div><div class="line"> <span class="function"><span class="keyword">void</span> <span class="title">unsubscribe</span><span class="params">()</span></span>;</div><div class="line"> <span class="function"><span class="keyword">boolean</span> <span class="title">isUnsubscribed</span><span class="params">()</span></span>;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>原来是用来取消订阅观察的,如果调用了<code>unsubscribe()</code>后,这个观察者就不再起作用了。</p>
]]></content>
<summary type="html">
<h3 id="1-Observables"><a href="#1-Observables" class="headerlink" title="1.Observables"></a>1.Observables</h3><p> 先认识几个重要的概念 </p>
<ul>
<li><strong>Observable</strong>:一个可观察对象或者被观察者</li>
<li><strong>Observer</strong>:观察者(订阅者)</li>
<li><strong>Subscribe</strong>:Observer的子类,比Observer多了onStart和unsubscribe两个方法</li>
</ul>
<p>在RxJava中,一个实现了Observer接口的对象可以订阅(subscribe)一个Observable 类的实例。订阅者(subscriber)对Observable发射(emit)的任何数据或数据序列作出响应。</p>
</summary>
<category term="RxJava" scheme="http://yoursite.com/categories/RxJava/"/>
<category term="Rxjava_Create" scheme="http://yoursite.com/tags/Rxjava-Create/"/>
</entry>
<entry>
<title>Android MediaCodec 硬编码H264格式</title>
<link href="http://yoursite.com/2016/09/24/2016-03-09-mediacodec/"/>
<id>http://yoursite.com/2016/09/24/2016-03-09-mediacodec/</id>
<published>2016-09-23T16:56:16.000Z</published>
<updated>2016-09-24T08:09:23.000Z</updated>
<content type="html"><![CDATA[<p>最近在研究EasyDarwin的Push库EasyPuhser,EasyPuhser可以推送H264视频到Easydarwin服务器,终端可以通过rtsp协议访问该实时流,达到手机直播的功能,延迟基本在2秒以内。<br>EasyDarwinQQ群:496258327<br>本文主要记录一下最近研究的关于Android手机如何获取实时画面,并将数据编码为H264的格式的视频流,编码使用的是Android自带的MediaCodec,也就是硬解。<br>本demo的下载地址:<a href="https://github.com/kidloserme/MediaCodecDemo" target="_blank" rel="external">MediaCodecDemo</a></p>
<a id="more"></a>
<p>MediaCodec是Android在4.1中加入的新的API,目前也有很多文章介绍MediaCodec的用法,但是很多时候很多手机都失败,主要问题出现在调用dequeueOutputBuffer的时候总是返回-1,让你以为No buffer available !这里介绍一个开源项目<a href="https://github.com/fyhertz/libstreaming" target="_blank" rel="external">libstreaming</a>,我们借助此项目中封装的一个工具类<a href="https://github.com/fyhertz/libstreaming/tree/master/src/net/majorkernelpanic/streaming/hw" target="_blank" rel="external">EncoderDebugger</a>,来初始化MediaCodec会很好的解决此问题,目前为止测试了几个手机都可以成功,包括小米华为Moto。<br>看一下怎么使用的</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">EncoderDebugger debugger = EncoderDebugger.debug(getApplicationContext(), width, height);</div><div class="line">MediaCodec mMediaCodec = MediaCodec.createByCodecName(debugger.getEncoderName());</div></pre></td></tr></table></figure>
<p>嗯,就这样。当然了,后面还是要根据需要对mMediaCodec设置其他参数的,看一下本demo中设置参数的过程吧</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">initMediaCodec</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">int</span> dgree = getDgree();</div><div class="line"> framerate = <span class="number">15</span>;</div><div class="line"> bitrate = <span class="number">2</span> * width * height * framerate / <span class="number">20</span>;</div><div class="line"> EncoderDebugger debugger = EncoderDebugger.debug(getApplicationContext(), width, height);</div><div class="line"> mConvertor = debugger.getNV21Convertor();</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> mMediaCodec = MediaCodec.createByCodecName(debugger.getEncoderName());</div><div class="line"> MediaFormat mediaFormat;</div><div class="line"> <span class="keyword">if</span> (dgree == <span class="number">0</span>) {</div><div class="line"> <span class="comment">//dree==0的时候,需要将画面旋转90度,所以这里编码的时候需要将宽和高颠倒,</span></div><div class="line"> <span class="comment">//否则编码后的会面会出现四重画面并且花屏</span></div><div class="line"> mediaFormat = MediaFormat.createVideoFormat(<span class="string">"video/avc"</span>, height, width);</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> mediaFormat = MediaFormat.createVideoFormat(<span class="string">"video/avc"</span>, width, height);</div><div class="line"> }</div><div class="line"> mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);</div><div class="line"> mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, framerate);</div><div class="line"> mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,</div><div class="line"> debugger.getEncoderColorFormat());</div><div class="line"> mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, <span class="number">1</span>);</div><div class="line"> mMediaCodec.configure(mediaFormat, <span class="keyword">null</span>, <span class="keyword">null</span>, MediaCodec.CONFIGURE_FLAG_ENCODE);</div><div class="line"> mMediaCodec.start();</div><div class="line"> } <span class="keyword">catch</span> (IOException e) {</div><div class="line"> e.printStackTrace();</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>编码之前先看一下要编码的数据怎么获取吧,这个当然是来自Camera。<br>首先是创建SurfaceView用于预览视频画面,并设置回调,来监控生命周期。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">surfaceView = (SurfaceView) findViewById(R.id.sv_surfaceview);</div><div class="line">surfaceView.getHolder().addCallback(<span class="keyword">this</span>);</div><div class="line">surfaceView.getHolder().setFixedSize(getResources().getDisplayMetrics().widthPixels,</div><div class="line">getResources().getDisplayMetrics().heightPixels);</div></pre></td></tr></table></figure>
<p>然后是创建Camera的方法:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">boolean</span> <span class="title">ctreateCamera</span><span class="params">(SurfaceHolder surfaceHolder)</span> </span>{</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> <span class="comment">//mCameraId=Camera.CameraInfo.CAMERA_FACING_BACK</span></div><div class="line"> mCamera = Camera.open(mCameraId);</div><div class="line"> Camera.Parameters parameters = mCamera.getParameters();</div><div class="line"> Camera.CameraInfo camInfo = <span class="keyword">new</span> Camera.CameraInfo();</div><div class="line"> Camera.getCameraInfo(mCameraId, camInfo);</div><div class="line"> <span class="keyword">int</span> cameraRotationOffset = camInfo.orientation;</div><div class="line"> <span class="comment">//设置预览格式NV21,他属于YUV420SP</span></div><div class="line"> parameters.setPreviewFormat(ImageFormat.NV21);</div><div class="line"> parameters.setPreviewSize(width, height);</div><div class="line"> mCamera.setParameters(parameters);</div><div class="line"> mCamera.autoFocus(<span class="keyword">null</span>);</div><div class="line"> <span class="comment">//计算preview画面需要旋转的角度。目前木有做横竖屏切换的时候无缝旋转画面,后面再搞。</span></div><div class="line"> <span class="keyword">int</span> displayRotation = (cameraRotationOffset - getDgree() + <span class="number">360</span>) % <span class="number">360</span>;</div><div class="line"> mCamera.setDisplayOrientation(displayRotation);</div><div class="line"> mCamera.setPreviewDisplay(surfaceHolder);</div><div class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</div><div class="line"> } <span class="keyword">catch</span> (Exception e) {</div><div class="line"> destroyCamera();</div><div class="line"> e.printStackTrace();</div><div class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</div><div class="line"> }</div><div class="line">}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">int</span> <span class="title">getDgree</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">int</span> rotation = getWindowManager().getDefaultDisplay().getRotation();</div><div class="line"> <span class="keyword">int</span> degrees = <span class="number">0</span>;</div><div class="line"> <span class="keyword">switch</span> (rotation) {</div><div class="line"> <span class="keyword">case</span> Surface.ROTATION_0:</div><div class="line"> degrees = <span class="number">0</span>;</div><div class="line"> <span class="keyword">break</span>; <span class="comment">// Natural orientation</span></div><div class="line"> <span class="keyword">case</span> Surface.ROTATION_90:</div><div class="line"> degrees = <span class="number">90</span>;</div><div class="line"> <span class="keyword">break</span>; <span class="comment">// Landscape left</span></div><div class="line"> <span class="keyword">case</span> Surface.ROTATION_180:</div><div class="line"> degrees = <span class="number">180</span>;</div><div class="line"> <span class="keyword">break</span>;<span class="comment">// Upside down</span></div><div class="line"> <span class="keyword">case</span> Surface.ROTATION_270:</div><div class="line"> degrees = <span class="number">270</span>;</div><div class="line"> <span class="keyword">break</span>;<span class="comment">// Landscape right</span></div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> degrees;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>摄像头创建完毕,就是开启预览</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * 开启预览</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">startPreview</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">if</span> (mCamera != <span class="keyword">null</span> && !started) {</div><div class="line"> mCamera.startPreview();</div><div class="line"> <span class="keyword">int</span> previewFormat = mCamera.getParameters().getPreviewFormat();</div><div class="line"> Camera.Size previewSize = mCamera.getParameters().getPreviewSize();</div><div class="line"> <span class="keyword">int</span> size = previewSize.width * previewSize.height</div><div class="line"> * ImageFormat.getBitsPerPixel(previewFormat)</div><div class="line"> / <span class="number">8</span>;</div><div class="line"> mCamera.addCallbackBuffer(<span class="keyword">new</span> <span class="keyword">byte</span>[size]);</div><div class="line"> mCamera.setPreviewCallbackWithBuffer(previewCallback);</div><div class="line"> started = <span class="keyword">true</span>;</div><div class="line"> btnSwitch.setText(<span class="string">"停止"</span>);</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>上面就是设置了预览回调的方式,回调中将预览画面一帧一帧的返回给我们,给我们的数据就是NV21格式的,根据需要决定是否需要对数据进行旋转,旋转之后,就是转换,将NV21数据转为YUV420P格式的数据,然后就可以编码为H264数据了。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div></pre></td><td class="code"><pre><div class="line">Camera.PreviewCallback previewCallback = <span class="keyword">new</span> Camera.PreviewCallback() {</div><div class="line"> <span class="comment">//mSpsPps用来存储sps pps数据,后面遇到关键帧(I帧),必须将spspps数据加到I帧前面</span></div><div class="line"> <span class="keyword">byte</span>[] mSpsPps = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">0</span>];</div><div class="line"> <span class="meta">@Override</span></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onPreviewFrame</span><span class="params">(<span class="keyword">byte</span>[] data, Camera camera)</span> </span>{</div><div class="line"> <span class="keyword">if</span> (data == <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">return</span>;</div><div class="line"> }</div><div class="line"> ByteBuffer[] inputBuffers = mMediaCodec.getInputBuffers();</div><div class="line"> ByteBuffer[] outputBuffers = mMediaCodec.getOutputBuffers();</div><div class="line"> <span class="keyword">byte</span>[] dst = <span class="keyword">new</span> <span class="keyword">byte</span>[data.length];</div><div class="line"> Camera.Size previewSize = mCamera.getParameters().getPreviewSize();</div><div class="line"> <span class="keyword">if</span> (getDgree() == <span class="number">0</span>) {</div><div class="line"> <span class="comment">//手机竖屏的时候要将获取的数据顺时针旋转90度,否则画面不是正着的,而是逆时针90度</span></div><div class="line"> dst = Util.rotateNV21Degree90(data, previewSize.width, previewSize.height);</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> dst = data;</div><div class="line"> }</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> <span class="keyword">int</span> bufferIndex = mMediaCodec.dequeueInputBuffer(<span class="number">5000000</span>);</div><div class="line"> <span class="keyword">if</span> (bufferIndex >= <span class="number">0</span>) {</div><div class="line"> inputBuffers[bufferIndex].clear();</div><div class="line"> <span class="comment">//将YUV420SP数据转换成YUV420P的格式,并将结果存入inputBuffers[bufferIndex]</span></div><div class="line"> mConvertor.convert(dst, inputBuffers[bufferIndex]);</div><div class="line"> mMediaCodec.queueInputBuffer(bufferIndex, <span class="number">0</span>,</div><div class="line"> inputBuffers[bufferIndex].position(),</div><div class="line"> System.nanoTime() / <span class="number">1000</span>, <span class="number">0</span>);</div><div class="line"> MediaCodec.BufferInfo bufferInfo = <span class="keyword">new</span> MediaCodec.BufferInfo();</div><div class="line"> <span class="keyword">int</span> outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, <span class="number">0</span>);</div><div class="line"> <span class="keyword">while</span> (outputBufferIndex >= <span class="number">0</span>) {</div><div class="line"> ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];</div><div class="line"> <span class="keyword">byte</span>[] outData = <span class="keyword">new</span> <span class="keyword">byte</span>[bufferInfo.size];</div><div class="line"> <span class="comment">//从buff中读取数据到outData中</span></div><div class="line"> outputBuffer.get(outData);</div><div class="line"> <span class="comment">//记录pps和sps,pps和sps数据开头是0x00 0x00 0x00 0x01 0x67,</span></div><div class="line"> <span class="comment">// 0x67对应十进制103</span></div><div class="line"> <span class="keyword">if</span> (outData[<span class="number">0</span>] == <span class="number">0</span> && outData[<span class="number">1</span>] == <span class="number">0</span> && outData[<span class="number">2</span>] == <span class="number">0</span> </div><div class="line"> && outData[<span class="number">3</span>] == <span class="number">1</span> && outData[<span class="number">4</span>] == <span class="number">103</span>) {</div><div class="line"> mSpsPps = outData;</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (outData[<span class="number">0</span>] == <span class="number">0</span> && outData[<span class="number">1</span>] == <span class="number">0</span> && outData[<span class="number">2</span>] == <span class="number">0</span> </div><div class="line"> && outData[<span class="number">3</span>] == <span class="number">1</span> && outData[<span class="number">4</span>] == <span class="number">101</span>) {</div><div class="line"> <span class="comment">//关键帧开始规则是0x00 0x00 0x00 0x01 0x65,0x65对应十进制101</span></div><div class="line"> <span class="comment">//在关键帧前面加上pps和sps数据</span></div><div class="line"> <span class="keyword">byte</span>[] iframeData = <span class="keyword">new</span> <span class="keyword">byte</span>[mSpsPps.length + outData.length];</div><div class="line"> System.arraycopy(mSpsPps, <span class="number">0</span>, iframeData, <span class="number">0</span>, mSpsPps.length);</div><div class="line"> System.arraycopy(outData, <span class="number">0</span>, iframeData, mSpsPps.length, outData.length);</div><div class="line"> outData = iframeData;</div><div class="line"> }</div><div class="line"> <span class="comment">//至此,这一帧的数据已经经过MediaCodec编码完毕,这个outData就是我们需要的数据了,</span></div><div class="line"> <span class="comment">//因为EasyDarwin可以自动将H264打包为RTP,</span></div><div class="line"> <span class="comment">//所以EasyPusher只需要负责将outData推给EasyDarwin就OK了</span></div><div class="line"> <span class="comment">//保存H264数据到本地文件easy.h264</span></div><div class="line"> Util.save(outData, <span class="number">0</span>, outData.length, path, <span class="keyword">true</span>);</div><div class="line"> mMediaCodec.releaseOutputBuffer(outputBufferIndex, <span class="keyword">false</span>);</div><div class="line"> outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, <span class="number">0</span>);</div><div class="line"> }</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> Log.e(<span class="string">"easypusher"</span>, <span class="string">"No buffer available !"</span>);</div><div class="line"> }</div><div class="line"> } <span class="keyword">catch</span> (Exception e) {</div><div class="line"> StringWriter sw = <span class="keyword">new</span> StringWriter();</div><div class="line"> PrintWriter pw = <span class="keyword">new</span> PrintWriter(sw);</div><div class="line"> e.printStackTrace(pw);</div><div class="line"> String stack = sw.toString();</div><div class="line"> Log.e(<span class="string">"save_log"</span>, stack);</div><div class="line"> e.printStackTrace();</div><div class="line"> } <span class="keyword">finally</span> {</div><div class="line"> mCamera.addCallbackBuffer(dst);</div><div class="line"> }</div><div class="line"> }</div><div class="line">};</div></pre></td></tr></table></figure>
<p>保存之后的文件easy.h264我用VLC播放器打开,截屏如下:<br></p>
<p><img src="http://img.blog.csdn.net/20160309132221153" alt="easy264截屏"></p>
<p><br>OK,基本上完毕了,该注意的地方都写在代码中了<br></p>
<p>需要Demo的请到这里<a href="https://github.com/kidloserme/MediaCodecDemo" target="_blank" rel="external">https://github.com/kidloserme/MediaCodecDemo</a></p>
]]></content>
<summary type="html">
<p>最近在研究EasyDarwin的Push库EasyPuhser,EasyPuhser可以推送H264视频到Easydarwin服务器,终端可以通过rtsp协议访问该实时流,达到手机直播的功能,延迟基本在2秒以内。<br>EasyDarwinQQ群:496258327<br>本文主要记录一下最近研究的关于Android手机如何获取实时画面,并将数据编码为H264的格式的视频流,编码使用的是Android自带的MediaCodec,也就是硬解。<br>本demo的下载地址:<a href="https://github.com/kidloserme/MediaCodecDemo">MediaCodecDemo</a></p>
</summary>
<category term="DEFAULT" scheme="http://yoursite.com/categories/DEFAULT/"/>
<category term="MediaCodec" scheme="http://yoursite.com/tags/MediaCodec/"/>
</entry>
<entry>
<title>EventBus源码阅读之事件的注册</title>
<link href="http://yoursite.com/2016/09/24/2016-03-17-EventBus/"/>
<id>http://yoursite.com/2016/09/24/2016-03-17-EventBus/</id>
<published>2016-09-23T16:56:16.000Z</published>
<updated>2016-09-24T08:09:41.000Z</updated>
<content type="html"><![CDATA[<p>之前看过EventBus的源码,不是很深入,导致有些模糊,此次仔细阅读了一下,记录笔记,方便以后熟悉。<br>本篇主要说一下register的过程:<br></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">register</span><span class="params">(Object subscriber, <span class="keyword">boolean</span> sticky, <span class="keyword">int</span> priority)</span> </span>{</div><div class="line"> <span class="comment">//查找subscriber(执行register的类)中注册事件的方法,onEvent开头,参数只允许一个,超过一个将被忽略</span></div><div class="line"> List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());</div><div class="line"> <span class="keyword">for</span> (SubscriberMethod subscriberMethod : subscriberMethods) {</div><div class="line"> <span class="comment">//根据事件类型以及订阅类进行数据处理</span></div><div class="line"> subscribe(subscriber, subscriberMethod, sticky, priority);</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<a id="more"></a>
<p>findSubscriberMethods这个方法很长,大致要做的事情就是查找出该类以及其父类中声明的所有方法,根据规则(只能public修饰onEvent开头且只有一个参数)筛选出订阅方法,一起看一下吧,具体就在代码中写说明了,删除了部分代码限制篇幅:<br></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div></pre></td><td class="code"><pre><div class="line"><span class="function">List<SubscriberMethod> <span class="title">findSubscriberMethods</span><span class="params">(Class<?> subscriberClass)</span> </span>{</div><div class="line"> <span class="comment">//省略部分代码</span></div><div class="line"> subscriberMethods = <span class="keyword">new</span> ArrayList<SubscriberMethod>();</div><div class="line"> Class<?> clazz = subscriberClass;</div><div class="line"> HashSet<String> eventTypesFound = <span class="keyword">new</span> HashSet<String>();</div><div class="line"> StringBuilder methodKeyBuilder = <span class="keyword">new</span> StringBuilder();</div><div class="line"> <span class="keyword">while</span> (clazz != <span class="keyword">null</span>) {</div><div class="line"> String name = clazz.getName();</div><div class="line"> <span class="comment">//忽略系统类</span></div><div class="line"> <span class="keyword">if</span> (name.startsWith(<span class="string">"java."</span>) || name.startsWith(<span class="string">"javax."</span>) || name.startsWith(<span class="string">"android."</span>)) {</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> }</div><div class="line"> <span class="comment">//获取该类中声明的所有方法</span></div><div class="line"> Method[] methods = clazz.getDeclaredMethods();</div><div class="line"> <span class="keyword">for</span> (Method method : methods) {</div><div class="line"> String methodName = method.getName();</div><div class="line"> <span class="comment">//是否以onEvent开头</span></div><div class="line"> <span class="keyword">if</span> (methodName.startsWith(ON_EVENT_METHOD_NAME)) {</div><div class="line"> <span class="keyword">int</span> modifiers = method.getModifiers();</div><div class="line"> <span class="comment">//修饰符只能以public开头</span></div><div class="line"> <span class="keyword">if</span> ((modifiers & Modifier.PUBLIC) != <span class="number">0</span> && (modifiers & MODIFIERS_IGNORE) == <span class="number">0</span>) {</div><div class="line"> Class<?>[] parameterTypes = method.getParameterTypes();</div><div class="line"> <span class="comment">//只能有一个参数</span></div><div class="line"> <span class="keyword">if</span> (parameterTypes.length == <span class="number">1</span>) {</div><div class="line"> String modifierString = methodName.substring(ON_EVENT_METHOD_NAME.length());</div><div class="line"> ThreadMode threadMode;</div><div class="line"> <span class="comment">//获取线程执行方式</span></div><div class="line"> <span class="keyword">if</span> (modifierString.length() == <span class="number">0</span>) {</div><div class="line"> threadMode = ThreadMode.PostThread;</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (modifierString.equals(<span class="string">"MainThread"</span>)) {</div><div class="line"> threadMode = ThreadMode.MainThread;</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (modifierString.equals(<span class="string">"BackgroundThread"</span>)) {</div><div class="line"> threadMode = ThreadMode.BackgroundThread;</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (modifierString.equals(<span class="string">"Async"</span>)) {</div><div class="line"> threadMode = ThreadMode.Async;</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="comment">//省略部分代码</span></div><div class="line"> }</div><div class="line"> Class<?> eventType = parameterTypes[<span class="number">0</span>];</div><div class="line"> methodKeyBuilder.setLength(<span class="number">0</span>);</div><div class="line"> methodKeyBuilder.append(methodName).append(<span class="string">'>'</span>).append(eventType.getName());</div><div class="line"> String methodKey = methodKeyBuilder.toString();</div><div class="line"> <span class="comment">//检查是否已经添加过</span></div><div class="line"> <span class="keyword">if</span> (eventTypesFound.add(methodKey)) {</div><div class="line"> <span class="comment">// Only add if not already found in a sub class</span></div><div class="line"> <span class="comment">//添加到列表中</span></div><div class="line"> subscriberMethods.add(<span class="keyword">new</span> SubscriberMethod(method, threadMode, eventType));</div><div class="line"> }</div><div class="line"> }</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (!skipMethodVerificationForClasses.containsKey(clazz)) {</div><div class="line"> Log.d(EventBus.TAG, <span class="string">"Skipping method (not public, static or abstract): "</span> + clazz + <span class="string">"."</span></div><div class="line"> + methodName);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line"> <span class="comment">//获取父类并且继续查找父类中的订阅方法</span></div><div class="line"> clazz = clazz.getSuperclass();</div><div class="line"> }</div><div class="line"> <span class="comment">//省略部分代码</span></div><div class="line">}</div></pre></td></tr></table></figure>
<p>接下来看subscribe(subscriber, subscriberMethod, sticky, priority);这个方法是干啥的,总结来说就是把所有事件类型为eventType的订阅者放入List列表中,并放入Map集合中。然后再根据订阅事件的类构造一个订阅事件列表,用来判断某个类是否已经注册过事件,看一下代码:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">subscribe</span><span class="params">(Object subscriber, SubscriberMethod subscriberMethod, <span class="keyword">boolean</span> sticky, <span class="keyword">int</span> priority)</span> </span>{</div><div class="line"> <span class="comment">//获取订阅事件中的时间类型</span></div><div class="line"> Class<?> eventType = subscriberMethod.eventType;</div><div class="line"> <span class="comment">//根据事件类型查找对应的所有订阅者(由类、方法、优先级组成)</span></div><div class="line"> CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);</div><div class="line"> <span class="comment">//创建一个新的订阅者</span></div><div class="line"> Subscription newSubscription = <span class="keyword">new</span> Subscription(subscriber, subscriberMethod, priority);</div><div class="line"> <span class="keyword">if</span> (subscriptions == <span class="keyword">null</span>) {</div><div class="line"> subscriptions = <span class="keyword">new</span> CopyOnWriteArrayList<Subscription>();</div><div class="line"> <span class="comment">//将订阅者列表放入Map中,后面post的时候会会根据这个eventType来获取该订阅者列表,然后来触发事件</span></div><div class="line"> subscriptionsByEventType.put(eventType, subscriptions);</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="comment">//不允许重复注册</span></div><div class="line"> <span class="keyword">if</span> (subscriptions.contains(newSubscription)) {</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> EventBusException(<span class="string">"Subscriber "</span> + subscriber.getClass() + <span class="string">" already registered to event "</span></div><div class="line"> + eventType);</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)</span></div><div class="line"> <span class="comment">// subscriberMethod.method.setAccessible(true);</span></div><div class="line"> <span class="comment">//根据优先级将新的订阅者插入到已有的订阅者列表中</span></div><div class="line"> <span class="keyword">int</span> size = subscriptions.size();</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i <= size; i++) {</div><div class="line"> <span class="keyword">if</span> (i == size || newSubscription.priority > subscriptions.get(i).priority) {</div><div class="line"> subscriptions.add(i, newSubscription);</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">//根据订阅类查找该订阅类中订阅事件类型,isRegister方法会用到此Map,判断是否已经注册过事件</span></div><div class="line"> List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);</div><div class="line"> <span class="keyword">if</span> (subscribedEvents == <span class="keyword">null</span>) {</div><div class="line"> subscribedEvents = <span class="keyword">new</span> ArrayList<Class<?>>();</div><div class="line"> typesBySubscriber.put(subscriber, subscribedEvents);</div><div class="line"> }</div><div class="line"> subscribedEvents.add(eventType);</div><div class="line"></div><div class="line"> <span class="comment">//粘性事件</span></div><div class="line"> <span class="keyword">if</span> (sticky) {</div><div class="line"> <span class="comment">//指定粘性事件是否只触发订阅了当前事件类型的子类的订阅者</span></div><div class="line"> <span class="keyword">if</span> (eventInheritance) {</div><div class="line"> <span class="comment">//stickyEvents中key为事件类名,value为事件类的实例</span></div><div class="line"> Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();</div><div class="line"> <span class="keyword">for</span> (Map.Entry<Class<?>, Object> entry : entries) {</div><div class="line"> Class<?> candidateEventType = entry.getKey();</div><div class="line"> <span class="comment">//eventType类是否是candidateEventType类的父类</span></div><div class="line"> <span class="keyword">if</span> (eventType.isAssignableFrom(candidateEventType)) {</div><div class="line"> Object stickyEvent = entry.getValue();</div><div class="line"> <span class="comment">//触发事件</span></div><div class="line"> checkPostStickyEventToSubscription(newSubscription, stickyEvent);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="comment">//获取所有黏性事件并触发</span></div><div class="line"> Object stickyEvent = stickyEvents.get(eventType);</div><div class="line"> checkPostStickyEventToSubscription(newSubscription, stickyEvent);</div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>post有两种,一种是在UI线程中,一种是子线程中执行,需要注意的是如果你post的事件类型为A,那么所有订阅过A的超类的事件也同样会被触发,时间原因,源码不分析,后续有时间接着写,记此笔记,方便自己查阅!</p>
]]></content>
<summary type="html">
<p>之前看过EventBus的源码,不是很深入,导致有些模糊,此次仔细阅读了一下,记录笔记,方便以后熟悉。<br>本篇主要说一下register的过程:<br></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">register</span><span class="params">(Object subscriber, <span class="keyword">boolean</span> sticky, <span class="keyword">int</span> priority)</span> </span>&#123;</div><div class="line"> <span class="comment">//查找subscriber(执行register的类)中注册事件的方法,onEvent开头,参数只允许一个,超过一个将被忽略</span></div><div class="line"> List&lt;SubscriberMethod&gt; subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());</div><div class="line"> <span class="keyword">for</span> (SubscriberMethod subscriberMethod : subscriberMethods) &#123;</div><div class="line"> <span class="comment">//根据事件类型以及订阅类进行数据处理</span></div><div class="line"> subscribe(subscriber, subscriberMethod, sticky, priority);</div><div class="line"> &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
</summary>
<category term="DEFAULT" scheme="http://yoursite.com/categories/DEFAULT/"/>
<category term="EventBus" scheme="http://yoursite.com/tags/EventBus/"/>
</entry>
<entry>
<title>知识点总结</title>
<link href="http://yoursite.com/2016/09/24/2016-03-17-Points/"/>
<id>http://yoursite.com/2016/09/24/2016-03-17-Points/</id>
<published>2016-09-23T16:56:16.000Z</published>
<updated>2016-09-24T08:09:51.000Z</updated>
<content type="html"><![CDATA[<h3 id="HaspMap原理"><a href="#HaspMap原理" class="headerlink" title="HaspMap原理"></a>HaspMap原理</h3><p>根据key的hashCode与Enty[]长度取模获取index来决定放入Enty中的位置,index重复则使用Entry.next在同一个index中放入多个值<br>具体可看:<a href="http://www.cnblogs.com/xwdreamer/archive/2012/05/14/2499339.html" target="_blank" rel="external">http://www.cnblogs.com/xwdreamer/archive/2012/05/14/2499339.html</a> 介绍</p>
<h3 id="HashMap和HashTable的区别"><a href="#HashMap和HashTable的区别" class="headerlink" title="HashMap和HashTable的区别"></a>HashMap和HashTable的区别</h3><p>HaspMap继承AbstractMap ,HashTable继承Dictionary<br>HashMap的方法不是同步的,HashTable的方法是同步的<br>HashMap允许key和value为Null,HashTable不允许key和value为null<br>详见:<a href="http://blog.csdn.net/shohokuf/article/details/3932967" target="_blank" rel="external">http://blog.csdn.net/shohokuf/article/details/3932967</a></p>
<a id="more"></a>
<h3 id="HashMap-TreeMap-LinkedHashMap-元素顺序"><a href="#HashMap-TreeMap-LinkedHashMap-元素顺序" class="headerlink" title="HashMap TreeMap LinkedHashMap 元素顺序"></a>HashMap TreeMap LinkedHashMap 元素顺序</h3><p>HashMap不保证元素的插入顺序,TreeMap默认会按照key的升序排序TreeMap支持自定义排序,LinkedHashMap按照插入顺序排序</p>
<h3 id="List子类ArrayList-LinkedList-Vector"><a href="#List子类ArrayList-LinkedList-Vector" class="headerlink" title="List子类ArrayList LinkedList Vector"></a>List子类ArrayList LinkedList Vector</h3><p>LinkedList在 add和remove 上更快,而在get上更慢.<br>List接口下一共实现了三个类:ArrayList,Vector,LinkedList。LinkedList就不多说了,它一般主要用在保持数据的插入顺序的时候。<br>ArrayList和Vector都是用数组实现的,主要有这么三个区别:</p>
<ul>
<li>1、Vector是多线程安全的,而ArrayList不是,这个可以从源码中看出,Vector类中的方法很多有synchronized进行修饰,这样就导致了Vector在效率上无法与ArrayList相比;</li>
<li>2、两个都是采用的线性连续空间存储元素,但是当空间不足的时候,两个类的增加方式是不同的,很多网友说Vector增加原来空间的一倍,ArrayList增加原来空间的50%,其实也差不多是这个意思,不过还有一点点问题可以从源码中看出,一会儿从源码中分析。</li>
<li>3、Vector可以设置增长因子,而ArrayList不可以,最开始看这个的时候,我没理解什么是增量因子,不过通过对比一下两个源码理解了这个,先看看两个类的构造方法:</li>
</ul>
<h3 id="HashSet"><a href="#HashSet" class="headerlink" title="HashSet"></a>HashSet</h3><p>HashSet内部实际上是一个HashMap,看代码</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">transient</span> HashMap<E, HashSet<E>> backingMap;</div><div class="line">看添加代码:</div><div class="line"><span class="meta">@Override</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">add</span><span class="params">(E object)</span> </span>{</div><div class="line"> <span class="keyword">return</span> backingMap.put(object, <span class="keyword">this</span>) == <span class="keyword">null</span>;</div><div class="line">}</div><div class="line"><span class="comment">//所以Set几何不允许重复的元素存在</span></div></pre></td></tr></table></figure>
<h3 id="Map-List-Set"><a href="#Map-List-Set" class="headerlink" title="Map List Set"></a>Map List Set</h3><ul>
<li>Map内部是一个Entry数组;</li>
<li>List内部是一个Object数组;</li>
<li>Set内部是一个Map集合,map的key集合就是Set的Value集合</li>
</ul>
<h3 id="关键字transient:"><a href="#关键字transient:" class="headerlink" title="关键字transient:"></a>关键字transient:</h3><ul>
<li>1)一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。</li>
<li>2)transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口。</li>
<li>3)被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化。</li>
</ul>
<h3 id="一个关于线程的问题"><a href="#一个关于线程的问题" class="headerlink" title="一个关于线程的问题"></a>一个关于线程的问题</h3><p>假如有Thread1、Thread2、Thread3、Thread4四条线程分别统计C、D、E、F四个盘的大小,所有线程都统计完毕交给Thread5线程去做汇总,应当如何实现?<br>可以使用并发包下的CountDownLatch实现<br><a href="http://www.cnblogs.com/dolphin0520/p/3920397.html" target="_blank" rel="external">http://www.cnblogs.com/dolphin0520/p/3920397.html</a></p>
<h3 id="wait和notify:"><a href="#wait和notify:" class="headerlink" title="wait和notify:"></a>wait和notify:</h3><p>执行wait、notify必须在同步块内部,这两个动作都是针对某一个对象的,比如对象A在线程1中执行了wait,那么线程1就会停留在此处,类似于阻塞,然后A在线程2中调用了notify,并且线程2执行结束之后线程1继续执行,如果对象A不在某处调用notify,线程1会一直停留在wait那一行处不继续执行。或者A调用wait的时候传一个等待时间,如果在这个等待时间内notify没有被调用,线程1会恢复执行。如果对象A在多个线程调用wait,那么必须执行notifyAll才能唤醒所有等待的线程,否则只会喊醒其中一个。</p>
<h3 id="线程通信"><a href="#线程通信" class="headerlink" title="线程通信"></a>线程通信</h3><p>线程之间的通信机制:(共享内存、消息传递)<br>深入理解Java内存模型<a href="http://www.infoq.com/cn/articles/java-memory-model-1" target="_blank" rel="external">http://www.infoq.com/cn/articles/java-memory-model-1</a></p>
<h3 id="Volatile的官方定义"><a href="#Volatile的官方定义" class="headerlink" title="Volatile的官方定义"></a>Volatile的官方定义</h3><p>Java语言规范第三版中对volatile的定义如下: java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致的更新,线程应该确保通过排他锁单独获得这个变量。Java语言提供了volatile,在某些情况下比锁更加方便。如果一个字段被声明成volatile,java线程内存模型确保所有线程看到这个变量的值是一致的</p>
<h3 id="线程池"><a href="#线程池" class="headerlink" title="线程池"></a>线程池</h3><p>为什么要使用线程池<br>避免频繁地创建和销毁线程,达到线程对象的重用。另外,使用线程池还可以根据项目灵活地控制并发的数目。<br>从Java5开始,Java提供了自己的线程池。每次只执行指定数量的线程,java.util.concurrent.ThreadPoolExecutor<br>public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<runnable> workQueue,RejectedExecutionHandler handler); </runnable></p>
<h4 id="参数介绍:"><a href="#参数介绍:" class="headerlink" title="参数介绍:"></a>参数介绍:</h4><ul>
<li>corePoolSize 核心线程数,指保留的线程池大小(不超过maximumPoolSize值时,线程池中最多有corePoolSize 个线程工作)。 </li>
<li>maximumPoolSize 指的是线程池的最大大小(线程池中最大有corePoolSize 个线程可运行)。 </li>
<li>keepAliveTime 指的是空闲线程结束的超时时间(当一个线程不工作时,过keepAliveTime 长时间将停止该线程)。 </li>
<li>unit 是一个枚举,表示 keepAliveTime 的单位(有NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS,7个可选值)。 </li>
<li>workQueue 表示存放任务的队列(存放需要被线程池执行的线程队列)。 </li>
<li>handler 拒绝策略(添加任务失败后如何处理该任务)</li>
</ul>
<h4 id="要点:"><a href="#要点:" class="headerlink" title="要点:"></a>要点:</h4><ul>
<li>1、线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行它们。</li>
<li>2、当调用 execute() 方法添加一个任务时,线程池会做如下判断:<ul>
<li>a. 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;</li>
<li>b. 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列。</li>
<li>c. 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建线程运行这个任务;</li>
<li>d. 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会抛出异常,告诉调用者“我不能再接受任务了”。</li>
</ul>
</li>
<li>3、当一个线程完成任务时,它会从队列中取下一个任务来执行。</li>
<li>4、当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小。</li>
</ul>
<p>这个过程说明,并不是先加入任务就一定会先执行。假设队列大小为4,corePoolSize为2,maximumPoolSize为6,那么当加入15个任务时,执行的顺序类似这样:首先执行任务 1、2,然后任务3~6被放入队列。这时候队列满了,任务7、8、9、10 会被马上执行,而任务 11~15则会抛出异常。最终顺序是:1、2、7、8、9、10、3、4、5、6。当然这个过程是针对指定大小的ArrayBlockingQueue<runnable>来说,如果是LinkedBlockingQueue<runnable>,因为该队列无大小限制,所以不存在上述问题。</runnable></runnable></p>
<h4 id="线程池创建"><a href="#线程池创建" class="headerlink" title="线程池创建"></a>线程池创建</h4><p>Executors.newCachedThreadPool(); //创建一个缓冲池,缓冲池容量大小为Integer.MAX_VALUE<br><br>Executors.newSingleThreadExecutor(); //创建容量为1的缓冲池<br><br>Executors.newFixedThreadPool(int); //创建固定容量大小的缓冲池<br></p>
]]></content>
<summary type="html">
<h3 id="HaspMap原理"><a href="#HaspMap原理" class="headerlink" title="HaspMap原理"></a>HaspMap原理</h3><p>根据key的hashCode与Enty[]长度取模获取index来决定放入Enty中的位置,index重复则使用Entry.next在同一个index中放入多个值<br>具体可看:<a href="http://www.cnblogs.com/xwdreamer/archive/2012/05/14/2499339.html">http://www.cnblogs.com/xwdreamer/archive/2012/05/14/2499339.html</a> 介绍</p>
<h3 id="HashMap和HashTable的区别"><a href="#HashMap和HashTable的区别" class="headerlink" title="HashMap和HashTable的区别"></a>HashMap和HashTable的区别</h3><p>HaspMap继承AbstractMap ,HashTable继承Dictionary<br>HashMap的方法不是同步的,HashTable的方法是同步的<br>HashMap允许key和value为Null,HashTable不允许key和value为null<br>详见:<a href="http://blog.csdn.net/shohokuf/article/details/3932967">http://blog.csdn.net/shohokuf/article/details/3932967</a></p>
</summary>
<category term="DEFAULT" scheme="http://yoursite.com/categories/DEFAULT/"/>
</entry>
<entry>
<title>Hello World</title>
<link href="http://yoursite.com/2016/09/24/hello-world/"/>
<id>http://yoursite.com/2016/09/24/hello-world/</id>
<published>2016-09-23T16:35:54.000Z</published>
<updated>2016-09-24T08:12:24.000Z</updated>
<content type="html"><![CDATA[<p>Welcome to <a href="https://hexo.io/" target="_blank" rel="external">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/" target="_blank" rel="external">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html" target="_blank" rel="external">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues" target="_blank" rel="external">GitHub</a>.</p>
<h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo new <span class="string">"My New Post"</span></div></pre></td></tr></table></figure>
<a id="more"></a>
<p>More info: <a href="https://hexo.io/docs/writing.html" target="_blank" rel="external">Writing</a></p>
<h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo server</div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/server.html" target="_blank" rel="external">Server</a></p>
<h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo generate</div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/generating.html" target="_blank" rel="external">Generating</a></p>
<h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo deploy</div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/deployment.html" target="_blank" rel="external">Deployment</a></p>
]]></content>
<summary type="html">
Hello World ,第一篇测试文章
</summary>
</entry>
</feed>