<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Magican</title>
  <subtitle>Programming is Magica</subtitle>
  <link href="/atom.xml" rel="self"/>
  
  <link href="http://thundertrick.github.io/"/>
  <updated>2017-01-03T06:40:24.000Z</updated>
  <id>http://thundertrick.github.io/</id>
  
  <author>
    <name>Xuyang Hu</name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>4种 Java 多参数构建模式</title>
    <link href="http://thundertrick.github.io/2017/01/03/4-java-constructors/"/>
    <id>http://thundertrick.github.io/2017/01/03/4-java-constructors/</id>
    <published>2017-01-03T06:37:40.000Z</published>
    <updated>2017-01-03T06:40:24.000Z</updated>
    
    <content type="html"><![CDATA[<p>最近在实际项目中遇到了多参数初始化问题。如何在模块初始化时传入多个参数（5个以上）？如何更安全？如何更灵活？如何可扩展？如何简化调用代码？如何增强可读性？我在面试中也常提出这样的问题。以上内容如果读过《Efective Jave》会很容易在第二章找到答案。</p>
<p>《Efective Jave》中主要介绍了 3 种多参数构建方法，我在项目里还用到了第 4 种。下面一一介绍。</p>
<a id="more"></a>
<p>##0x00 简单、常用：重叠构造器<br>代码示例：<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></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">A</span> </span>&#123;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">int</span> v1;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">int</span> v2;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">int</span> v3;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">int</span> v4;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">int</span> v5;</div><div class="line">    </div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="title">A</span><span class="params">(<span class="keyword">int</span> v1)</span> </span>&#123; <span class="keyword">this</span>(v1, DEFUALT_V2)&#125;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="title">A</span><span class="params">(<span class="keyword">int</span> v1, <span class="keyword">int</span> v2)</span> </span>&#123; <span class="keyword">this</span>(v1, v2, DEFUALT_V3)&#125;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="title">A</span><span class="params">(<span class="keyword">int</span> v1, <span class="keyword">int</span> v2, <span class="keyword">int</span> v3)</span> </span>&#123; <span class="keyword">this</span>(v1, v2, v3, DEFUALT_V4)&#125;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="title">A</span><span class="params">(<span class="keyword">int</span> v1, <span class="keyword">int</span> v2, <span class="keyword">int</span> v3, <span class="keyword">int</span> v4)</span> </span>&#123; <span class="keyword">this</span>(v1, v2, v3, v4, DEFUALT_V5)&#125;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="title">A</span><span class="params">(<span class="keyword">int</span> v1, <span class="keyword">int</span> v2, <span class="keyword">int</span> v3, <span class="keyword">int</span> v4, <span class="keyword">int</span> v5)</span> </span>&#123;</div><div class="line">        <span class="keyword">this</span>.v1 = v1;</div><div class="line">        <span class="keyword">this</span>.v2 = v2;</div><div class="line">        <span class="keyword">this</span>.v3 = v3;</div><div class="line">        <span class="keyword">this</span>.v4 = v4;</div><div class="line">        <span class="keyword">this</span>.v5 = v5;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>优点：</p>
<ol>
<li>逻辑、层级清晰明了。适合参数层级关系明确的类，如 Android 里的 View。</li>
</ol>
<p>缺点：</p>
<ol>
<li>参数增多时，可读性变差</li>
<li>如示例所示，如果连续传入多个同样类型的变量，容易把顺序弄错</li>
<li>灵活性不足，无法指定初始化特定几个参数</li>
</ol>
<p>##0x01 简单、灵活：重复 set 方法<br>代码示例：<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></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">B</span> </span>&#123;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">int</span> v1 = DEFAULT_V1;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">int</span> v2 = DEFAULT_V2;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">int</span> v3 = DEFAULT_V3;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">int</span> v4 = DEFAULT_V4;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">int</span> v5 = DEFAULT_V5;</div><div class="line">    </div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="title">B</span><span class="params">()</span> </span>&#123;&#125;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setV1</span><span class="params">(<span class="keyword">int</span> val)</span> </span>&#123; v1 = val; &#125;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setV2</span><span class="params">(<span class="keyword">int</span> val)</span> </span>&#123; v2 = val; &#125;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setV3</span><span class="params">(<span class="keyword">int</span> val)</span> </span>&#123; v3 = val; &#125;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setV4</span><span class="params">(<span class="keyword">int</span> val)</span> </span>&#123; v4 = val; &#125;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setV5</span><span class="params">(<span class="keyword">int</span> val)</span> </span>&#123; v5 = val; &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>优点:</p>
<ol>
<li>简单</li>
<li>灵活，支持定制式初始化，即参数可选，如果不需要自定义的变量可以直接不给初始化方法</li>
<li>支持动态改变参数，set 方法也可以在程序运行的任何阶段调用</li>
</ol>
<p>缺点：</p>
<ol>
<li>如果变量的需要按一定顺序初始化，那么这种调用方式将带来风险。实际项目被这个坑过。提供外部的接口最好在编写时排除这种漏洞的隐患</li>
<li>set 方法可在任何时间调用，更改变量的值。和缺点 1 同理，如果变量耦合了其他逻辑，那么随时可调用 set 方法就是不安全的。</li>
</ol>
<h2 id="0x02-安全、可读：Builder-构建器"><a href="#0x02-安全、可读：Builder-构建器" class="headerlink" title="0x02 安全、可读：Builder 构建器"></a>0x02 安全、可读：Builder 构建器</h2><p>代码示例<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></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">C</span> </span>&#123;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">int</span> v1;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">int</span> v2;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">int</span> v3;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">int</span> v4;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">int</span> v5;</div><div class="line">    </div><div class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Builder</span> </span>&#123;</div><div class="line">        <span class="keyword">private</span> <span class="keyword">int</span> v1 = DEFAULT_V1;</div><div class="line">        <span class="keyword">private</span> <span class="keyword">int</span> v2 = DEFAULT_V2;</div><div class="line">        <span class="keyword">private</span> <span class="keyword">int</span> v3 = DEFAULT_V3;</div><div class="line">        <span class="keyword">private</span> <span class="keyword">int</span> v4 = DEFAULT_V4;</div><div class="line">        <span class="keyword">private</span> <span class="keyword">int</span> v5 = DEFAULT_V5;</div><div class="line"></div><div class="line">        <span class="function"><span class="keyword">public</span> <span class="title">Builder</span><span class="params">(<span class="keyword">int</span> v1)</span> </span>&#123; <span class="keyword">this</span>.v1 = v1; <span class="keyword">return</span> <span class="keyword">this</span>;&#125;</div><div class="line">        <span class="function"><span class="keyword">public</span> Builder <span class="title">v2</span><span class="params">(<span class="keyword">int</span> val)</span> </span>&#123; <span class="keyword">this</span>.v2 = val; <span class="keyword">return</span> <span class="keyword">this</span>; &#125;</div><div class="line">        <span class="function"><span class="keyword">public</span> Builder <span class="title">v3</span><span class="params">(<span class="keyword">int</span> val)</span> </span>&#123; <span class="keyword">this</span>.v3 = val; <span class="keyword">return</span> <span class="keyword">this</span>; &#125;</div><div class="line">        <span class="function"><span class="keyword">public</span> Builder <span class="title">v4</span><span class="params">(<span class="keyword">int</span> val)</span> </span>&#123; <span class="keyword">this</span>.v4 = val; <span class="keyword">return</span> <span class="keyword">this</span>; &#125;</div><div class="line">        <span class="function"><span class="keyword">public</span> Builder <span class="title">v5</span><span class="params">(<span class="keyword">int</span> val)</span> </span>&#123; <span class="keyword">this</span>.v5 = val; <span class="keyword">return</span> <span class="keyword">this</span>; &#125;</div><div class="line">        <span class="function"><span class="keyword">public</span> C <span class="title">build</span><span class="params">()</span> </span>&#123; <span class="keyword">return</span> <span class="keyword">new</span> C(<span class="keyword">this</span>); &#125;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">private</span> <span class="title">C</span><span class="params">(Builder builder)</span> </span>&#123;</div><div class="line">        <span class="keyword">this</span>.v1 = builder.v1;</div><div class="line">        <span class="keyword">this</span>.v2 = builder.v2;</div><div class="line">        <span class="keyword">this</span>.v3 = builder.v3;</div><div class="line">        <span class="keyword">this</span>.v4 = builder.v4;</div><div class="line">        <span class="keyword">this</span>.v5 = builder.v5;</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"><span class="comment">// Usage:</span></div><div class="line"><span class="comment">// C c = new C.Builder(1).v2(2).v3(3).v4(4).v5(5).build();</span></div></pre></td></tr></table></figure></p>
<p>优点：</p>
<ol>
<li>灵活，支持定制式初始化</li>
<li>可读性强，参见 Android 的 Animator 类，一个语句完成类的初始化和调用</li>
<li>可以在 <code>build()</code> 方法内统一进行参数校验，为《Ecfective Java》推荐方法</li>
</ol>
<p>缺点：</p>
<ol>
<li>复杂，构建所需代码行数增加</li>
<li>参数在传入时为确定参数，不支持动态改变</li>
</ol>
<h2 id="0x03-实时参数：Provider-模式"><a href="#0x03-实时参数：Provider-模式" class="headerlink" title="0x03 实时参数：Provider 模式"></a>0x03 实时参数：Provider 模式</h2><p>该方法借鉴了 <code>Builder</code> 构建器，但是将构建器独立于类外，同时提供实时获取的接口。<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><div class="line">36</div><div class="line">37</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">D</span> </span>&#123;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">int</span> v1;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">int</span> v2;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">int</span> v3;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">int</span> v4;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">int</span> v5;</div><div class="line">    </div><div class="line">    <span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Provider</span> </span>&#123;</div><div class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getV1</span><span class="params">()</span></span>;</div><div class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getV2</span><span class="params">()</span></span>;</div><div class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getV3</span><span class="params">()</span></span>;</div><div class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getV4</span><span class="params">()</span></span>;</div><div class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getV5</span><span class="params">()</span></span>;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="title">D</span><span class="params">(Provider provider)</span> </span>&#123;</div><div class="line">        <span class="keyword">this</span>.v1 = provider.getV1();</div><div class="line">        <span class="keyword">this</span>.v2 = builder.v2;</div><div class="line">        <span class="keyword">this</span>.v3 = builder.v3;</div><div class="line">        <span class="keyword">this</span>.v4 = builder.v4;</div><div class="line">        <span class="keyword">this</span>.v5 = builder.v5;</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"><span class="comment">// Usage:</span></div><div class="line"><span class="comment">// public class IProvider implement D.Provider &#123;</span></div><div class="line"><span class="comment">//        @Override</span></div><div class="line"><span class="comment">//        public int getV1() &#123; return val; &#125;</span></div><div class="line"><span class="comment">//        @Override</span></div><div class="line"><span class="comment">//        public int getV2() &#123; return val; &#125;</span></div><div class="line"><span class="comment">//        @Override</span></div><div class="line"><span class="comment">//        public int getV3() &#123; return val; &#125;</span></div><div class="line"><span class="comment">//        @Override</span></div><div class="line"><span class="comment">//        public int getV4() &#123; return val; &#125;</span></div><div class="line"><span class="comment">//        @Override</span></div><div class="line"><span class="comment">//        public int getV5() &#123; return val; &#125; </span></div><div class="line"><span class="comment">// &#125;</span></div><div class="line"><span class="comment">// D d = new D(new IProvider());</span></div></pre></td></tr></table></figure></p>
<p>优点：</p>
<ol>
<li>借鉴了 <code>Builder</code> 构建器的优点，隔离了参数传入方法和初始化方法</li>
<li><code>Provider</code> 由调用方实现，使动态参数的传入变为可能</li>
<li>调用节点只需要调用一行语句，初始化参数的准备移至他处。这种场景需求可能发生在一个核心类的 <code>initAll()</code> 方法中，调用者需要在该方法内先后初始化十几个模块。如果每个模块都要写十行代码那就非常恐怖了。</li>
</ol>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;最近在实际项目中遇到了多参数初始化问题。如何在模块初始化时传入多个参数（5个以上）？如何更安全？如何更灵活？如何可扩展？如何简化调用代码？如何增强可读性？我在面试中也常提出这样的问题。以上内容如果读过《Efective Jave》会很容易在第二章找到答案。&lt;/p&gt;
&lt;p&gt;《Efective Jave》中主要介绍了 3 种多参数构建方法，我在项目里还用到了第 4 种。下面一一介绍。&lt;/p&gt;
    
    </summary>
    
    
      <category term="Android" scheme="http://thundertrick.github.io/tags/Android/"/>
    
      <category term="java" scheme="http://thundertrick.github.io/tags/java/"/>
    
  </entry>
  
  <entry>
    <title>Mac 下 Paddlepaddle 安装配置</title>
    <link href="http://thundertrick.github.io/2016/10/24/Mac-%E4%B8%8B-Paddlepaddle-%E5%AE%89%E8%A3%85%E9%85%8D%E7%BD%AE/"/>
    <id>http://thundertrick.github.io/2016/10/24/Mac-下-Paddlepaddle-安装配置/</id>
    <published>2016-10-24T07:37:04.000Z</published>
    <updated>2016-11-08T03:54:37.000Z</updated>
    
    <content type="html"><![CDATA[<p>百度新推出了<code>paddlepaddle</code>深度学习工具，目前官方还未支持 Mac 下 binary 安装。参考<a href="http://www.paddlepaddle.org/doc/build/index.html" target="_blank" rel="external">最新官方文档</a>，笔者先基于源码编译安装，发现 BLAS 依赖是个非常麻烦的坑，最后使用官方推荐的 docker 镜像方式进行安装。</p>
<a id="more"></a>
<ol>
<li>参照官网安装 <a href="https://docs.docker.com/docker-for-mac/" target="_blank" rel="external">Docker for Mac</a>，傻瓜式安装非常简单，不再累述；</li>
<li><p>判断本地 CPU 是否支持 <code>AVX</code>指令集：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">if cat /proc/cpuinfo | grep -q avx ; then echo &quot;Support AVX&quot;; else echo &quot;Not support AVX&quot;; fi</div></pre></td></tr></table></figure>
</li>
<li><p>根据是否支持 <code>AVX</code> 选择镜像下载：</p>
</li>
</ol>
<table>
<thead>
<tr>
<th></th>
<th>normal</th>
<th>devel</th>
<th>demo</th>
</tr>
</thead>
<tbody>
<tr>
<td>CPU</td>
<td>cpu-latest</td>
<td>cpu-devel-latest</td>
<td>cpu-demo-latest</td>
</tr>
<tr>
<td>GPU</td>
<td>gpu-latest</td>
<td>gpu-devel-latest</td>
<td>gpu-demo-latest</td>
</tr>
<tr>
<td>CPU WITHOUT AVX</td>
<td>cpu-noavx-latest</td>
<td>cpu-noavx-devel-latest</td>
<td>cpu-noavx-demo-latest</td>
</tr>
<tr>
<td>GPU WITHOUT AVX</td>
<td>gpu-noavx-latest</td>
<td>gpu-noavx-devel-latest</td>
<td>gpu-noavx-demo-latest</td>
</tr>
</tbody>
</table>
<p>虽然新版的文档只有6个镜像，但实际上上述表格中所有镜像都在同步更新（<a href="https://hub.docker.com/r/paddledev/paddle/tags/" target="_blank" rel="external">地址</a>）。 没有本文选择<code>cpu-noavx-latest</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></pre></td><td class="code"><pre><div class="line">$ docker pull paddledev/paddle:cpu-noavx-latest</div><div class="line">$ docker run -it paddledev/paddle:cpu-noavx-latest </div><div class="line">root@c9eea5b52828:/# paddle version</div><div class="line">PaddlePaddle 0.8.0b3, compiled with</div><div class="line">    with_avx: OFF</div><div class="line">    with_gpu: OFF</div><div class="line">    with_double: OFF</div><div class="line">    with_python: ON</div><div class="line">    with_rdma: OFF</div><div class="line">    with_glog: ON</div><div class="line">    with_gflags: ON</div><div class="line">    with_metric_learning: </div><div class="line">    with_timer: OFF</div><div class="line">    with_predict_sdk:</div></pre></td></tr></table></figure></p>
<p>安装成功！</p>
<p>##注意：<br><a href="http://deeplearning.baidu.com/doc/build/build_from_source.html" target="_blank" rel="external">旧版官网</a>上提到的镜像下载语句：<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">$ docker run -it paddledev/paddlepaddle:cpu-latest</div></pre></td></tr></table></figure></p>
<p>是<strong>错的！！！</strong>。仓库路径应该为<code>paddledev/paddle</code>，而非<code>paddledev/paddlepaddle</code>。这个小问题折腾了我很久，希望对读者有所帮助。</p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;百度新推出了&lt;code&gt;paddlepaddle&lt;/code&gt;深度学习工具，目前官方还未支持 Mac 下 binary 安装。参考&lt;a href=&quot;http://www.paddlepaddle.org/doc/build/index.html&quot;&gt;最新官方文档&lt;/a&gt;，笔者先基于源码编译安装，发现 BLAS 依赖是个非常麻烦的坑，最后使用官方推荐的 docker 镜像方式进行安装。&lt;/p&gt;
    
    </summary>
    
    
      <category term="paddlepaddle" scheme="http://thundertrick.github.io/tags/paddlepaddle/"/>
    
      <category term="mac" scheme="http://thundertrick.github.io/tags/mac/"/>
    
      <category term="deep learning" scheme="http://thundertrick.github.io/tags/deep-learning/"/>
    
  </entry>
  
  <entry>
    <title>Android RemoteView 资源ID索引错误解决方案</title>
    <link href="http://thundertrick.github.io/2016/10/21/Android-RemoteView-%E8%B5%84%E6%BA%90ID%E7%B4%A2%E5%BC%95%E9%94%99%E8%AF%AF%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/"/>
    <id>http://thundertrick.github.io/2016/10/21/Android-RemoteView-资源ID索引错误解决方案/</id>
    <published>2016-10-21T06:42:39.000Z</published>
    <updated>2016-11-09T03:44:57.000Z</updated>
    
    <content type="html"><![CDATA[<p>应用升级时如果替换了通知等 RemoteView 中的资源文件，则可能会导致新的升级包资源 id 发生变动，在部分机型上体现为<code>android.app.RemoteServiceException</code>。崩溃日志大致如下：</p>
<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></pre></td><td class="code"><pre><div class="line">Bad notification posted from package com.mypkg.name: Couldn&apos;t create icon: StatusBarIcon(pkg=com.mypkg.name user=0 id=0x7f0200dc level=0 visible=true num=0 )</div><div class="line">android.app.ActivityThread$H.handleMessage(ActivityThread.java:1638) </div><div class="line">android.os.Handler.dispatchMessage(Handler.java:111) </div><div class="line">android.os.Looper.loop(Looper.java:194) </div><div class="line">android.app.ActivityThread.main(ActivityThread.java:5637) </div><div class="line">java.lang.reflect.Method.invoke(Native Method) </div><div class="line">java.lang.reflect.Method.invoke(Method.java:372) </div><div class="line">com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:960) </div><div class="line">com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)</div></pre></td></tr></table></figure>
<p>前段时间升级直接导致 crash 收集平台被该 bug 刷屏，而测试过程又一次都没有复现。<a href="http://stackoverflow.com/questions/31771204/bad-notification-posted-from-package" target="_blank" rel="external">StackOverFlow</a>  上也没有太好的解决方案。这里探索了一种固化资源 id 的解决方案，线上验证也是可行的，bug率明显下降。但是另一种类似的<code>cannot expand view</code>还未能解决。</p>
<a id="more"></a>
<p>通过反编译可以发现，Android App 会在 <code>res/values/public.xml</code> 里存储所有的资源文件名到资源文件 id 的映射关系。如果在编译前手动添加部分资源的 id 到 public.xml 下，那么这些资源的 id 就得以固化，升级以及添加修改资源都不会对这些 id 产生影响。此外，<code>res/values/ids.xml</code> 也起到了类似作用，只不过仅覆盖 id 资源。</p>
<p>因此，解决思路应该是反编译 Apk 包，获得最新的<code>public.xml</code>，讲所有<code>RemoteView</code>涉及到的资源文件，包括<code>string, dimen, drawable, id, layout</code>等，提取出来并保存在项目源码中的<code>res/values/public.xml</code>和<code>res/values/ids.xml</code>文件中。</p>
<p><strong><em>注意：Gradle 自 1.3.0 以后版本编译时会默认忽略本地的 <code>public.xml</code> 文件，因此还需要添加 Gradle 脚本使 <code>public.xml</code> 生效。打开 app 的 <code>build.gradle</code> 文件，在最后添加如下脚本 (<a href="http://blog.csdn.net/ceabie/article/details/50867791" target="_blank" rel="external">参考连接</a>中也提到了利用 Gradle 插件的解决方案)：</em></strong></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></pre></td><td class="code"><pre><div class="line">afterEvaluate &#123;</div><div class="line">    <span class="keyword">for</span> (variant in android.applicationVariants) &#123;</div><div class="line">        def scope = variant.getVariantData().getScope()</div><div class="line">        String mergeTaskName = scope.getMergeResourcesTask().name</div><div class="line">        def mergeTask = tasks.getByName(mergeTaskName)</div><div class="line"></div><div class="line">        mergeTask.doLast &#123;</div><div class="line">            copy &#123;</div><div class="line">                <span class="keyword">int</span> i=<span class="number">0</span></div><div class="line">                from([<span class="string">'res'</span>]) &#123;</div><div class="line">                    include <span class="string">'values/public.xml'</span></div><div class="line">                    rename <span class="string">'public.xml'</span>, (i == <span class="number">0</span>? <span class="string">"public.xml"</span>: <span class="string">"public_$&#123;i&#125;.xml"</span>)</div><div class="line">                    i++</div><div class="line">                &#125;</div><div class="line"></div><div class="line">                into(mergeTask.outputDir)</div><div class="line">            &#125;</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>— Update<br>如果需要对<code>submodule</code>中的资源也增加id固化，则可以在上面代码<code>[&#39;res&#39;]</code>中增加相应资源路径即可。</p>
<p>参考：</p>
<ol>
<li><a href="http://blog.csdn.net/ceabie/article/details/50867791" target="_blank" rel="external">android gradle plugin 1.3.0 以上使用 public.xml 固定 id</a></li>
</ol>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;应用升级时如果替换了通知等 RemoteView 中的资源文件，则可能会导致新的升级包资源 id 发生变动，在部分机型上体现为&lt;code&gt;android.app.RemoteServiceException&lt;/code&gt;。崩溃日志大致如下：&lt;/p&gt;
&lt;figure class=&quot;highlight plain&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;div class=&quot;line&quot;&gt;1&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;2&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;3&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;4&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;5&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;6&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;7&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;8&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;9&lt;/div&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;div class=&quot;line&quot;&gt;Bad notification posted from package com.mypkg.name: Couldn&amp;apos;t create icon: StatusBarIcon(pkg=com.mypkg.name user=0 id=0x7f0200dc level=0 visible=true num=0 )&lt;/div&gt;&lt;div class=&quot;line&quot;&gt;android.app.ActivityThread$H.handleMessage(ActivityThread.java:1638) &lt;/div&gt;&lt;div class=&quot;line&quot;&gt;android.os.Handler.dispatchMessage(Handler.java:111) &lt;/div&gt;&lt;div class=&quot;line&quot;&gt;android.os.Looper.loop(Looper.java:194) &lt;/div&gt;&lt;div class=&quot;line&quot;&gt;android.app.ActivityThread.main(ActivityThread.java:5637) &lt;/div&gt;&lt;div class=&quot;line&quot;&gt;java.lang.reflect.Method.invoke(Native Method) &lt;/div&gt;&lt;div class=&quot;line&quot;&gt;java.lang.reflect.Method.invoke(Method.java:372) &lt;/div&gt;&lt;div class=&quot;line&quot;&gt;com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:960) &lt;/div&gt;&lt;div class=&quot;line&quot;&gt;com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)&lt;/div&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;
&lt;p&gt;前段时间升级直接导致 crash 收集平台被该 bug 刷屏，而测试过程又一次都没有复现。&lt;a href=&quot;http://stackoverflow.com/questions/31771204/bad-notification-posted-from-package&quot;&gt;StackOverFlow&lt;/a&gt;  上也没有太好的解决方案。这里探索了一种固化资源 id 的解决方案，线上验证也是可行的，bug率明显下降。但是另一种类似的&lt;code&gt;cannot expand view&lt;/code&gt;还未能解决。&lt;/p&gt;
    
    </summary>
    
    
      <category term="Android" scheme="http://thundertrick.github.io/tags/Android/"/>
    
      <category term="bugs" scheme="http://thundertrick.github.io/tags/bugs/"/>
    
  </entry>
  
  <entry>
    <title>HEXO next 主题增加搜索引擎验证</title>
    <link href="http://thundertrick.github.io/2016/08/16/hexo-search-engine-vertify/"/>
    <id>http://thundertrick.github.io/2016/08/16/hexo-search-engine-vertify/</id>
    <published>2016-08-16T04:20:19.000Z</published>
    <updated>2016-11-08T04:58:58.000Z</updated>
    
    <content type="html"><![CDATA[<p>Github 上利用 hexo 建立的博客是无法被搜索引擎搜索到的。Github 本身也不会将信息提交给引擎。所以，为了让博客信息被检索到，我们需要手动将博客网站提交给搜索引擎并验证，实际上就是验证网站是我们自己的。对 hexo 比较友好的验证方法包括：</p>
<ol>
<li>文件验证：将一个 html 文件配置到 source 目录下，使之可以访问并获取其中的字符串。</li>
<li>HTML meta 标签验证：在主页的 html 头里增加一个 meta 标签，记录搜索引擎提供的字符串。</li>
</ol>
<p>如果使用了 Next 主题，source 目录下所有的 html 都会按主题模板化，这使得文件验证生成的页面中字符串无法被搜索引擎识别。虽然理论上可以对单独的地址进行模板屏蔽，但一个网站冷不丁冒出来一个风格迥异的页面还是不能让人接受。所以，我最后选择了 HTML meta 标签验证方法。</p>
<a id="more"></a>
<p><a href="https://www.google.com/webmasters/tools/home?hl=zh-CN" target="_blank" rel="external">Google 引擎验证申请地址</a><br><a href="http://www.baidu.com/search/url_submit.htm" target="_blank" rel="external">Baidu 引擎验证申请地址</a></p>
<p><del>Next 主题下，页面的 header 设置在<code>themes/next/layout/_partials/head.swig</code>内。默认也给我们提供了模板，感谢<a href="https://github.com/iissnan" target="_blank" rel="external">开发者 iissnan</a>。我们只需要把下面标签补全即可：</del></p>
<figure class="highlight html"><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">&#123;% if theme.google_site_verification %&#125;</div><div class="line">  <span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"google-site-verification"</span> <span class="attr">content</span>=<span class="string">"IQs30MFrhmrm-Nfmv-_neEbXELyUuxvZtdin1ALJ4aA"</span> /&gt;</span></div><div class="line">&#123;% endif %&#125;</div><div class="line"></div><div class="line">&#123;% if theme.baidu_site_verification %&#125;</div><div class="line">  <span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"baidu-site-verification"</span> <span class="attr">content</span>=<span class="string">"H1J5y75sN7"</span> /&gt;</span></div><div class="line">&#123;% endif %&#125;</div></pre></td></tr></table></figure>
<p><del>同时，在<code>themes/next/_config.yml</code>中将<code>google-site-verification</code>和<code>baidu_site_verification</code>的值设置为<code>true</code>即可。</del></p>
<p>P.S.<br>百度现在不支持 https 网址的验证，ORZ。</p>
<hr>
<p>感谢<a href="http://weibo.com/2284890987" target="_blank" rel="external">@小硕硕_</a> 的提醒，更正确的方法是在<code>_config.xml</code>里直接定义<code>google-site-verification</code>和<code>baidu_site_verification</code>的值为相应id。</p>
<p>Referrence:</p>
<ol>
<li><a href="http://www.jianshu.com/p/619dab2d3c08" target="_blank" rel="external">hexo干货系列：（六）hexo提交搜索引擎（百度+谷歌）</a></li>
</ol>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;Github 上利用 hexo 建立的博客是无法被搜索引擎搜索到的。Github 本身也不会将信息提交给引擎。所以，为了让博客信息被检索到，我们需要手动将博客网站提交给搜索引擎并验证，实际上就是验证网站是我们自己的。对 hexo 比较友好的验证方法包括：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;文件验证：将一个 html 文件配置到 source 目录下，使之可以访问并获取其中的字符串。&lt;/li&gt;
&lt;li&gt;HTML meta 标签验证：在主页的 html 头里增加一个 meta 标签，记录搜索引擎提供的字符串。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果使用了 Next 主题，source 目录下所有的 html 都会按主题模板化，这使得文件验证生成的页面中字符串无法被搜索引擎识别。虽然理论上可以对单独的地址进行模板屏蔽，但一个网站冷不丁冒出来一个风格迥异的页面还是不能让人接受。所以，我最后选择了 HTML meta 标签验证方法。&lt;/p&gt;
    
    </summary>
    
    
      <category term="Hexo" scheme="http://thundertrick.github.io/tags/Hexo/"/>
    
      <category term="Baidu" scheme="http://thundertrick.github.io/tags/Baidu/"/>
    
      <category term="Google" scheme="http://thundertrick.github.io/tags/Google/"/>
    
  </entry>
  
  <entry>
    <title>Facebook Android SDK Tips Part 1 LikeView Bugs and Fixes</title>
    <link href="http://thundertrick.github.io/2016/08/15/facebook-sdk-tips/"/>
    <id>http://thundertrick.github.io/2016/08/15/facebook-sdk-tips/</id>
    <published>2016-08-15T11:59:17.000Z</published>
    <updated>2016-08-15T12:05:22.000Z</updated>
    
    <content type="html"><![CDATA[<p>Solutions for some bugs I met when using Facebook LikeView. The docs of Facebook SDK is totally #@!$#@!$!</p>
<p>Official Reference: <a href="https://developers.facebook.com/docs/reference/android/current/class/LikeView" target="_blank" rel="external">LikeView Reference</a></p>
<a id="more"></a>
<p>##BUG 0x01: The developers or testers cannot access the Like Page</p>
<ol>
<li>Check the internet connection.</li>
<li>Check if the page is allowed to be liked.</li>
<li>Check the account of developers or testers have the permission of developer or tester under the APP ID.</li>
<li>Check Facebook App support before initialize LikeView, and DO NOT just check the installation of Facebook App. For some lower version of Facebook App, things may not work properly. Using SDK for checking as following:</li>
</ol>
<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">if</span> (Build.VERSION.SDK_INT &gt;= <span class="number">15</span>) &#123;</div><div class="line">    <span class="keyword">if</span> (LikeDialog.canShowNativeDialog() || LikeDialog.canShowWebFallback()) &#123;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<h2 id="BUG-0x02-Crash-when-initializing"><a href="#BUG-0x02-Crash-when-initializing" class="headerlink" title="BUG 0x02: Crash when initializing"></a>BUG 0x02: Crash when initializing</h2><ol>
<li>DO NOT initialize LikeView in your layout.xml as the Official guide recommended, which is unsafe for API level &lt; 15. ( min version for FB SDK 4.10 ) All of the FB SDK method should be used after API level judgement.</li>
<li>If you only want to open LikeDialog in Facebook App and only use <code>LikeDialog.canShowNativeDialog()</code> for judgement, LikeDialog may fail to open after swipe all the data of Facebook App. I recommend to use web dialog just in case.</li>
</ol>
<h2 id="BUG-0x03-Crash-in-onActivityResult"><a href="#BUG-0x03-Crash-in-onActivityResult" class="headerlink" title="BUG 0x03: Crash in onActivityResult()"></a>BUG 0x03: Crash in onActivityResult()</h2><p>Stack overflow give a way to get the like result in onActivityResult() method. But it should add a <code>data != null</code> judgment, otherwise app will crash when not data returns.</p>
<h2 id="BUG-0x04-Native-Like-Button-permission"><a href="#BUG-0x04-Native-Like-Button-permission" class="headerlink" title="BUG 0x04: Native Like Button permission"></a>BUG 0x04: Native Like Button permission</h2><p>App Review should be done to get Native Like Button permission. Otherwise, only developers and test users can access like button.</p>
<p>(Moved from <a href="http://huxyz.blogspot.com/2016/03/facebook-android-sdk-tips-part-1.html" target="_blank" rel="external">another blog site of my</a>)</p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;Solutions for some bugs I met when using Facebook LikeView. The docs of Facebook SDK is totally #@!$#@!$!&lt;/p&gt;
&lt;p&gt;Official Reference: &lt;a href=&quot;https://developers.facebook.com/docs/reference/android/current/class/LikeView&quot;&gt;LikeView Reference&lt;/a&gt;&lt;/p&gt;
    
    </summary>
    
    
      <category term="Android" scheme="http://thundertrick.github.io/tags/Android/"/>
    
      <category term="Facebook" scheme="http://thundertrick.github.io/tags/Facebook/"/>
    
  </entry>
  
  <entry>
    <title>Buck 安装配置与测试</title>
    <link href="http://thundertrick.github.io/2016/08/12/buck-test/"/>
    <id>http://thundertrick.github.io/2016/08/12/buck-test/</id>
    <published>2016-08-12T11:40:32.000Z</published>
    <updated>2016-08-15T11:55:26.000Z</updated>
    
    <content type="html"><![CDATA[<blockquote>
<p>Buck is a build system developed and used by Facebook. It encourages the creation of small, reusable modules consisting of code and resources, and supports a variety of languages on many platforms.</p>
</blockquote>
<p>Facebook 开源的东东，据说微信也在用。接手的项目以前是 Ant，现在转 Gradle。但由于项目本身携带了大量历史遗留代码，并且集合了数个 submodule，编译起来非常缓慢，拖延了开发效率。这里测试一下 Buck 替代的可能性。</p>
<a id="more"></a>
<h2 id="0x01-安装"><a href="#0x01-安装" class="headerlink" title="0x01 安装"></a>0x01 安装</h2><p>OS X 下使用 homebrew <a href="https://buckbuild.com/setup/install.html" target="_blank" rel="external">安装</a>：</p>
<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">brew update</div><div class="line">brew tap facebook/fb</div><div class="line">brew install buck</div><div class="line">brew install watchman</div></pre></td></tr></table></figure>
<p>Watchman 是 FB 强力推荐安装的，可以有效提高 Buck 的编译效率。此外，对于 Android 开发，我们还必须把 Android SDK 和 NDK 的路径告诉 Buck。设置方法只需配置好ANDROID_HOME，ANDROID_NDK，ANDROID_NDK_REPOSITORY 这几个环境变量即可，本文暂不累述。</p>
<h2 id="0x02-创建本地配置"><a href="#0x02-创建本地配置" class="headerlink" title="0x02 创建本地配置"></a>0x02 创建本地配置</h2><p>… // TODO</p>
]]></content>
    
    <summary type="html">
    
      &lt;blockquote&gt;
&lt;p&gt;Buck is a build system developed and used by Facebook. It encourages the creation of small, reusable modules consisting of code and resources, and supports a variety of languages on many platforms.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Facebook 开源的东东，据说微信也在用。接手的项目以前是 Ant，现在转 Gradle。但由于项目本身携带了大量历史遗留代码，并且集合了数个 submodule，编译起来非常缓慢，拖延了开发效率。这里测试一下 Buck 替代的可能性。&lt;/p&gt;
    
    </summary>
    
    
      <category term="Android" scheme="http://thundertrick.github.io/tags/Android/"/>
    
      <category term="Facebook" scheme="http://thundertrick.github.io/tags/Facebook/"/>
    
      <category term="Buck" scheme="http://thundertrick.github.io/tags/Buck/"/>
    
  </entry>
  
  <entry>
    <title>Effective Java - 1.1 类的创建</title>
    <link href="http://thundertrick.github.io/2016/08/08/effectiv-java-1-1-1/"/>
    <id>http://thundertrick.github.io/2016/08/08/effectiv-java-1-1-1/</id>
    <published>2016-08-08T12:13:19.000Z</published>
    <updated>2016-08-15T12:30:09.000Z</updated>
    
    <content type="html"><![CDATA[<p>获得一个实例最常见的方法就是构造器。但构造器并非在所有场景下都是最佳方案。本文收集几个特殊的构造方法以备需要。文中大部分内容源自 Joshua Bloch 的 Effective Java （second edition），实际上也是一个读书笔记。</p>
<a id="more"></a>
<h2 id="0x01-静态工厂方法"><a href="#0x01-静态工厂方法" class="headerlink" title="0x01 静态工厂方法"></a>0x01 静态工厂方法</h2><h3 id="1-方法示例："><a href="#1-方法示例：" class="headerlink" title="1. 方法示例："></a>1. 方法示例：</h3><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">public</span> <span class="keyword">static</span> Boolean <span class="title">valueOf</span><span class="params">(<span class="keyword">boolean</span> b)</span> </span>&#123;</div><div class="line">	<span class="keyword">return</span> b ? Boolean.TRUE : Boolean.FALSE;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<h3 id="2-优点："><a href="#2-优点：" class="headerlink" title="2. 优点："></a>2. 优点：</h3><ol>
<li><strong>有名称</strong>。构造器实际上只能用类名命名，无法更多地描述构造信息。并且实际使用中，同一个类常有数个不同的构造方法，如果不加以区分（缺少必要注释）则很容易使用错误。而静态工厂方法，可以使用方法名去描述构造实例的更多信息，易于区分。</li>
<li><strong>不必每次调用都创建一个新的对象</strong>。重复调用可以利用好预先构建好的实例，从而减少了重复创建的开支。这点我目前的理解是静态工厂方法类内部可以调用其他的单例实例。</li>
<li><strong>可以返回原类型的任何子类型</strong>。这样在选择返回对象时就有了更大的灵活性。</li>
<li><strong>创建参数化实例时代码更加简洁</strong>。举例说明，原始代码：</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">Map&lt;String, List&lt;String&gt;&gt; m = <span class="keyword">new</span> HashMap&lt;String, List&lt;String&gt;&gt;;</div></pre></td></tr></table></figure>
<p>假设<code>HashMap</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="keyword">static</span> &lt;K, V&gt; <span class="function">HashMap&lt;K, V&gt; <span class="title">newInstance</span><span class="params">()</span> </span>&#123;</div><div class="line">	<span class="keyword">return</span> <span class="keyword">new</span> HashMap&lt;K, V&gt;();</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>那么原始代码就可以简化为：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">Map&lt;String, List&lt;String&gt;&gt; m = HashMap.newInstance();</div></pre></td></tr></table></figure>
<h3 id="3-缺点："><a href="#3-缺点：" class="headerlink" title="3. 缺点："></a>3. 缺点：</h3><ol>
<li>类如果不含公有的或者受保护的构造器，就不能被子类化。</li>
<li>与其他静态方法没有本质上的区别。这个主要是对JavaDoc不友好，无法像构造方法一样被标识。</li>
</ol>
<h3 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h3><p>静态工厂方法常用的方法名称如下：</p>
<ol>
<li><code>valueOf</code>, <code>of</code></li>
<li><code>getInstance</code>, <code>newInstance</code></li>
<li><code>getType</code>, <code>newType</code></li>
</ol>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;获得一个实例最常见的方法就是构造器。但构造器并非在所有场景下都是最佳方案。本文收集几个特殊的构造方法以备需要。文中大部分内容源自 Joshua Bloch 的 Effective Java （second edition），实际上也是一个读书笔记。&lt;/p&gt;
    
    </summary>
    
    
      <category term="Android" scheme="http://thundertrick.github.io/tags/Android/"/>
    
      <category term="Java" scheme="http://thundertrick.github.io/tags/Java/"/>
    
  </entry>
  
  <entry>
    <title>安卓WiFi传输相关技术</title>
    <link href="http://thundertrick.github.io/2016/07/29/android-wifi/"/>
    <id>http://thundertrick.github.io/2016/07/29/android-wifi/</id>
    <published>2016-07-29T10:10:38.000Z</published>
    <updated>2016-07-29T10:15:43.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="大纲"><a href="#大纲" class="headerlink" title="大纲"></a>大纲</h2><ol>
<li>Wifi传输概述</li>
<li><code>WifiP2pManager</code>类的介绍和使用</li>
<li>Wifi热点创建相关技术</li>
<li>基于Wifi的文件传输方法</li>
<li>Demo的展示与介绍</li>
<li>小结</li>
</ol>
<a id="more"></a>
<h2 id="1-Wifi传输概述"><a href="#1-Wifi传输概述" class="headerlink" title="1. Wifi传输概述"></a>1. Wifi传输概述</h2><h3 id="1-1-步骤"><a href="#1-1-步骤" class="headerlink" title="1.1 步骤"></a>1.1 步骤</h3><ol>
<li>发现对方IP地址：涉及<code>WifiP2pManager</code>和Wifi热点的创建</li>
<li>监听端口，建立Socket通讯</li>
<li>传输文件或其他信息</li>
</ol>
<h3 id="1-2-应用"><a href="#1-2-应用" class="headerlink" title="1.2 应用"></a>1.2 应用</h3><ol>
<li>应用、照片、视频等文件的分发和传输</li>
<li>手机与手机，手机与PC网页的通讯、文件传输</li>
</ol>
<h2 id="2-WifiP2pManager类的介绍和使用"><a href="#2-WifiP2pManager类的介绍和使用" class="headerlink" title="2. WifiP2pManager类的介绍和使用"></a>2. <code>WifiP2pManager</code>类的介绍和使用</h2><p>该<a href="http://developer.android.com/intl/zh-cn/reference/android/net/wifi/p2p/WifiP2pManager.html" target="_blank" rel="external">方法</a>提供了对<strong>WiFi peer-to-peer</strong>传输的管理API，从而使得应用可以发现可用的peer，设置到peer的连接以及查询peer列表。本质上其功能也可以通过UDP广播实现。</p>
<h3 id="2-1-简介"><a href="#2-1-简介" class="headerlink" title="2.1 简介"></a>2.1 简介</h3><p>WiFi p2p常用方法</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></pre></td><td class="code"><pre><div class="line"><span class="comment">// Initialization </span></div><div class="line"><span class="function"><span class="keyword">public</span> Channel <span class="title">initialize</span><span class="params">(Context srcContext, Looper srcLooper, ChannelListener listener)</span></span>;</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">connect</span><span class="params">(Channel c, WifiP2pConfig config, ActionListener listener)</span></span>;</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">discoverPeers</span><span class="params">(Channel c, ActionListener listener)</span></span>;</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">createGroup</span><span class="params">(Channel c, ActionListener listener)</span></span>;</div><div class="line"></div><div class="line"><span class="comment">// Request Info</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">requestPeers</span><span class="params">(Channel c, PeerListListener listener)</span></span>;</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">requestConnectionInfo</span><span class="params">(Channel c, ConnectionInfoListener listener)</span></span>;</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">requestGroupInfo</span><span class="params">(Channel c, GroupInfoListener listener)</span></span>;</div><div class="line"></div><div class="line"><span class="comment">// ...</span></div></pre></td></tr></table></figure>
<p>WiFi p2p常用监听器</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></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">ActionListener</span> </span>&#123;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onSuccess</span><span class="params">()</span></span>;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onFailure</span><span class="params">(<span class="keyword">int</span> reason)</span></span>;</div><div class="line">&#125;</div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">PeerListListener</span> </span>&#123;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onPeersAvailable</span><span class="params">(WifiP2pDeviceList peers)</span></span>;</div><div class="line">&#125;</div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">ChannelListener</span> </span>&#123;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onChannelDisconnected</span><span class="params">()</span></span>;</div><div class="line">&#125;</div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">ConnectionInfoListener</span> </span>&#123;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onConnectionInfoAvailable</span><span class="params">(WifiP2pInfo info)</span></span>;</div><div class="line">&#125;</div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">GroupInfoListener</span> </span>&#123;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onGroupInfoAvailable</span><span class="params">(WifiP2pGroup group)</span></span>;</div><div class="line">&#125;</div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">ServiceResponseListener</span> </span>&#123;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onServiceAvailable</span><span class="params">(<span class="keyword">int</span> protocolType,</span></span></div><div class="line">            <span class="keyword">byte</span>[] responseData, WifiP2pDevice srcDevice);</div><div class="line">&#125;</div><div class="line"><span class="comment">// ...</span></div><div class="line">~~~   </div><div class="line"></div><div class="line">WiFi p2p Intent</div><div class="line"></div><div class="line">~~~java</div><div class="line"><span class="meta">@SdkConstant</span>(SdkConstantType.BROADCAST_INTENT_ACTION)</div><div class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String WIFI_P2P_CONNECTION_CHANGED_ACTION;</div><div class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String WIFI_P2P_PEERS_CHANGED_ACTION;</div><div class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String WIFI_P2P_STATE_CHANGED_ACTION;</div><div class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String WIFI_P2P_THIS_DEVICE_CHANGED_ACTION;</div></pre></td></tr></table></figure>
<h3 id="2-2-初始化"><a href="#2-2-初始化" class="headerlink" title="2.2 初始化"></a>2.2 初始化</h3><h4 id="2-2-1-对wifi-p2p-intent广播进行监听"><a href="#2-2-1-对wifi-p2p-intent广播进行监听" class="headerlink" title="2.2.1 对wifi p2p intent广播进行监听"></a>2.2.1 对wifi p2p intent广播进行监听</h4><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></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">WiFiDirectBroadcastReceiver</span> <span class="keyword">extends</span> <span class="title">BroadcastReceiver</span> </span>&#123;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> WifiP2pManager mManager;</div><div class="line">    <span class="keyword">private</span> Channel mChannel;</div><div class="line">    <span class="keyword">private</span> MyWiFiActivity mActivity;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="title">WiFiDirectBroadcastReceiver</span><span class="params">(WifiP2pManager manager, Channel channel,</span></span></div><div class="line">            MyWifiActivity activity) &#123;</div><div class="line">        <span class="keyword">super</span>();</div><div class="line">        <span class="keyword">this</span>.mManager = manager;</div><div class="line">        <span class="keyword">this</span>.mChannel = channel;</div><div class="line">        <span class="keyword">this</span>.mActivity = activity;</div><div class="line">    &#125;</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">void</span> <span class="title">onReceive</span><span class="params">(Context context, Intent intent)</span> </span>&#123;</div><div class="line">        String action = intent.getAction();</div><div class="line"></div><div class="line">        <span class="keyword">if</span> (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) &#123;</div><div class="line">            <span class="comment">// Check to see if Wi-Fi is enabled and notify appropriate activity</span></div><div class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) &#123;</div><div class="line">            <span class="comment">// Call WifiP2pManager.requestPeers() to get a list of current peers</span></div><div class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) &#123;</div><div class="line">            <span class="comment">// Respond to new connection or disconnections</span></div><div class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) &#123;</div><div class="line">            <span class="comment">// Respond to this device's wifi state changing</span></div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<h4 id="2-2-2-创建wifi-p2p应用"><a href="#2-2-2-创建wifi-p2p应用" class="headerlink" title="2.2.2 创建wifi p2p应用"></a>2.2.2 创建wifi p2p应用</h4><ol>
<li>申请权限</li>
</ol>
<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></pre></td><td class="code"><pre><div class="line"><span class="tag">&lt;<span class="name">uses-sdk</span> <span class="attr">android:minSdkVersion</span>=<span class="string">"14"</span> /&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">uses-permission</span> <span class="attr">android:name</span>=<span class="string">"android.permission.ACCESS_WIFI_STATE"</span> /&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">uses-permission</span> <span class="attr">android:name</span>=<span class="string">"android.permission.CHANGE_WIFI_STATE"</span> /&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">uses-permission</span> <span class="attr">android:name</span>=<span class="string">"android.permission.CHANGE_NETWORK_STATE"</span> /&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">uses-permission</span> <span class="attr">android:name</span>=<span class="string">"android.permission.INTERNET"</span> /&gt;</span></div><div class="line"><span class="tag">&lt;<span class="name">uses-permission</span> <span class="attr">android:name</span>=<span class="string">"android.permission.ACCESS_NETWORK_STATE"</span> /&gt;</span></div></pre></td></tr></table></figure>
<ol>
<li>初始化<code>WiFiP2PManager</code>，设置<code>IntentFilter</code>并注册广播接收对象</li>
</ol>
<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></pre></td><td class="code"><pre><div class="line">IntentFilter mIntentFilter;</div><div class="line"><span class="meta">@Override</span></div><div class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span></span>&#123;</div><div class="line">    mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);</div><div class="line">    mChannel = mManager.initialize(<span class="keyword">this</span>, getMainLooper(), <span class="keyword">null</span>);</div><div class="line">    mReceiver = <span class="keyword">new</span> WiFiDirectBroadcastReceiver(mManager, mChannel, <span class="keyword">this</span>);</div><div class="line">    </div><div class="line">    mIntentFilter = <span class="keyword">new</span> IntentFilter();</div><div class="line">    mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);</div><div class="line">    mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);</div><div class="line">    mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);</div><div class="line">    mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);</div><div class="line">&#125;</div><div class="line"><span class="meta">@Override</span></div><div class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onResume</span><span class="params">()</span> </span>&#123;</div><div class="line">    <span class="keyword">super</span>.onResume();</div><div class="line">    registerReceiver(mReceiver, mIntentFilter);</div><div class="line">&#125;</div><div class="line"><span class="meta">@Override</span></div><div class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onPause</span><span class="params">()</span> </span>&#123;</div><div class="line">    <span class="keyword">super</span>.onPause();</div><div class="line">    unregisterReceiver(mReceiver);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<h3 id="2-3-发现方法"><a href="#2-3-发现方法" class="headerlink" title="2.3 发现方法"></a>2.3 发现方法</h3><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></pre></td><td class="code"><pre><div class="line"><span class="comment">// Descover methods</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">discoverPeers</span><span class="params">(Channel c, ActionListener listener)</span></span>;</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">discoverServices</span><span class="params">(Channel c, ActionListener listener)</span>；</span></div><div class="line"></div><div class="line"><span class="comment">// Listeners</span></div><div class="line"><span class="keyword">public</span> interface ActionListener &#123;</div><div class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onSuccess</span><span class="params">()</span></span>;</div><div class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onFailure</span><span class="params">(<span class="keyword">int</span> reason)</span></span>;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<h2 id="3-Wifi热点创建相关技术"><a href="#3-Wifi热点创建相关技术" class="headerlink" title="3. Wifi热点创建相关技术"></a>3. Wifi热点创建相关技术</h2><p>安卓系统将热点控制API设置为<code>@hide</code>属性，需要使用反射机制调用。Wifi热点的创建相关技术主要分为两步：</p>
<ol>
<li><p>创建<code>WifiConfiguration</code>， 调用<code>setWifiApEnabled</code>函数讲配置文件写入系统，从而开启Wifi热点。</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></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">createWifiAp</span><span class="params">(String ssid, String password)</span> </span>&#123;</div><div class="line">        <span class="keyword">if</span> (mWifiManager.isWifiEnabled()) &#123;</div><div class="line">            mWifiManager.setWifiEnabled(<span class="keyword">false</span>);</div><div class="line">        &#125;</div><div class="line"></div><div class="line">        mNetConfig = <span class="keyword">new</span> WifiConfiguration();</div><div class="line"></div><div class="line">        mNetConfig.SSID = ssid;</div><div class="line">        mNetConfig.preSharedKey = password;</div><div class="line">        mNetConfig.status = WifiConfiguration.Status.ENABLED;</div><div class="line">        mNetConfig.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);</div><div class="line">        mNetConfig.allowedProtocols.set(WifiConfiguration.Protocol.RSN);</div><div class="line">        mNetConfig.allowedProtocols.set(WifiConfiguration.Protocol.WPA);</div><div class="line">        mNetConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);</div><div class="line">        mNetConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);</div><div class="line">        mNetConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);</div><div class="line">        mNetConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);</div><div class="line">        mNetConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);<span class="comment">//NONE);</span></div><div class="line"></div><div class="line">        <span class="keyword">try</span> &#123;</div><div class="line">            Method setWifiApMethod = mWifiManager.getClass().getMethod(<span class="string">"setWifiApEnabled"</span>, WifiConfiguration.class, <span class="keyword">boolean</span>.class);</div><div class="line">            <span class="keyword">boolean</span> apstatus = (Boolean) setWifiApMethod.invoke(mWifiManager, mNetConfig, <span class="keyword">true</span>);</div><div class="line"></div><div class="line">            Method isWifiApEnabledmethod = mWifiManager.getClass().getMethod(<span class="string">"isWifiApEnabled"</span>);</div><div class="line">            <span class="keyword">while</span> (!(Boolean) isWifiApEnabledmethod.invoke(mWifiManager)) &#123;</div><div class="line">            &#125;</div><div class="line">            ;</div><div class="line">            Method getWifiApStateMethod = mWifiManager.getClass().getMethod(<span class="string">"getWifiApState"</span>);</div><div class="line">            <span class="keyword">int</span> apstate = (Integer) getWifiApStateMethod.invoke(mWifiManager);</div><div class="line">            Method getWifiApConfigurationMethod = mWifiManager.getClass().getMethod(<span class="string">"getWifiApConfiguration"</span>);</div><div class="line">            mNetConfig = (WifiConfiguration) getWifiApConfigurationMethod.invoke(mWifiManager);</div><div class="line">            Log.d(<span class="string">"CLIENT"</span>, <span class="string">"\nSSID:"</span> + mNetConfig.SSID + <span class="string">"\nPassword:"</span> + mNetConfig.preSharedKey + <span class="string">"\n"</span>);</div><div class="line"></div><div class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</div><div class="line">            Log.e(TAG, e.toString());</div><div class="line">            e.printStackTrace();</div><div class="line">        &#125;</div><div class="line">    &#125;</div></pre></td></tr></table></figure>
</li>
<li><p>下载端连接后，扫描<code>/proc/net/arp</code>文件获取连接到主机的IP。当然也可以等下载机访问我们指定的主机网址，再通过请求知道下载机的IP地址，这里暂不累述。</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></pre></td><td class="code"><pre><div class="line">  <span class="comment">/**</span></div><div class="line"> * Gets a list of the clients connected to the Hotspot </div><div class="line"> * <span class="doctag">@param</span> onlyReachables &#123;<span class="doctag">@code</span> false&#125; if the list should contain unreachable (probably disconnected) clients, &#123;<span class="doctag">@code</span> true&#125; otherwise</div><div class="line"> * <span class="doctag">@param</span> reachableTimeout Reachable Timout in miliseconds</div><div class="line"> * <span class="doctag">@param</span> finishListener, Interface called when the scan method finishes </div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">getClientList</span><span class="params">(<span class="keyword">final</span> <span class="keyword">boolean</span> onlyReachables, <span class="keyword">final</span> <span class="keyword">int</span> reachableTimeout, <span class="keyword">final</span> FinishScanListener finishListener)</span> </span>&#123;</div><div class="line"></div><div class="line"></div><div class="line">	Runnable runnable = <span class="keyword">new</span> Runnable() &#123;</div><div class="line">		<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</div><div class="line"></div><div class="line">			BufferedReader br = <span class="keyword">null</span>;</div><div class="line">			<span class="keyword">final</span> ArrayList&lt;ClientScanResult&gt; result = <span class="keyword">new</span> ArrayList&lt;ClientScanResult&gt;();</div><div class="line">			</div><div class="line">			<span class="keyword">try</span> &#123;</div><div class="line">				br = <span class="keyword">new</span> BufferedReader(<span class="keyword">new</span> FileReader(<span class="string">"/proc/net/arp"</span>));</div><div class="line">				String line;</div><div class="line">				<span class="keyword">while</span> ((line = br.readLine()) != <span class="keyword">null</span>) &#123;</div><div class="line">					String[] splitted = line.split(<span class="string">" +"</span>);</div><div class="line"></div><div class="line">					<span class="keyword">if</span> ((splitted != <span class="keyword">null</span>) &amp;&amp; (splitted.length &gt;= <span class="number">4</span>)) &#123;</div><div class="line">						<span class="comment">// Basic sanity check</span></div><div class="line">						String mac = splitted[<span class="number">3</span>];</div><div class="line"></div><div class="line">						<span class="keyword">if</span> (mac.matches(<span class="string">"..:..:..:..:..:.."</span>)) &#123;</div><div class="line">							<span class="keyword">boolean</span> isReachable = InetAddress.getByName(splitted[<span class="number">0</span>]).isReachable(reachableTimeout);</div><div class="line"></div><div class="line">							<span class="keyword">if</span> (!onlyReachables || isReachable) &#123;</div><div class="line">								result.add(<span class="keyword">new</span> ClientScanResult(splitted[<span class="number">0</span>], splitted[<span class="number">3</span>], splitted[<span class="number">5</span>], isReachable));</div><div class="line">							&#125;</div><div class="line">						&#125;</div><div class="line">					&#125;</div><div class="line">				&#125;</div><div class="line">			&#125; <span class="keyword">catch</span> (Exception e) &#123;</div><div class="line">				Log.e(<span class="keyword">this</span>.getClass().toString(), e.toString());</div><div class="line">			&#125; <span class="keyword">finally</span> &#123;</div><div class="line">				<span class="keyword">try</span> &#123;</div><div class="line">					br.close();</div><div class="line">				&#125; <span class="keyword">catch</span> (IOException e) &#123;</div><div class="line">					Log.e(<span class="keyword">this</span>.getClass().toString(), e.getMessage());</div><div class="line">				&#125;</div><div class="line">			&#125;</div><div class="line"></div><div class="line">			<span class="comment">// Get a handler that can be used to post to the main thread</span></div><div class="line">			Handler mainHandler = <span class="keyword">new</span> Handler(context.getMainLooper());</div><div class="line">			Runnable myRunnable = <span class="keyword">new</span> Runnable() &#123;</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">run</span><span class="params">()</span> </span>&#123;</div><div class="line">					finishListener.onFinishScan(result);</div><div class="line">				&#125;</div><div class="line">			&#125;;</div><div class="line">			mainHandler.post(myRunnable);</div><div class="line">		&#125;</div><div class="line">	&#125;;</div><div class="line"></div><div class="line">	Thread mythread = <span class="keyword">new</span> Thread(runnable);</div><div class="line">	mythread.start();</div><div class="line">&#125;</div></pre></td></tr></table></figure>
</li>
</ol>
<h2 id="4-基于Wifi的文件传输方法"><a href="#4-基于Wifi的文件传输方法" class="headerlink" title="4. 基于Wifi的文件传输方法"></a>4. 基于Wifi的文件传输方法</h2><p>基于WiFi的数据传输主要有两个技术点：一方面是文件传输，另一方面是下载端的网页实时获得文件传输的进度。前者可以直接使用<code>ServerSocket</code>实现，后者对于双方均安装我们的下载app的情况没有难度，但对于一边是app发送文件，一边是网页打开连接下载文件，就需要基于<strong><code>JavaScript</code></strong>的<code>XMLHttpRequest</code>可以实现主机和下载机网页的信息交流。</p>
<h3 id="4-1-使用ServerSocket传输数据"><a href="#4-1-使用ServerSocket传输数据" class="headerlink" title="4.1 使用ServerSocket传输数据"></a>4.1 使用<code>ServerSocket</code>传输数据</h3><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></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * Sends the HTTP response to the client, including headers (as applicable)</div><div class="line"> * and content.</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">processRequest</span><span class="params">(Socket client)</span> <span class="keyword">throws</span> IllegalStateException, IOException </span>&#123;</div><div class="line">    Log.e(TAG, <span class="string">"Starting to process request"</span>);</div><div class="line">    client.setKeepAlive(<span class="keyword">true</span>);</div><div class="line">    InputStream is = client.getInputStream();</div><div class="line">    <span class="keyword">final</span> <span class="keyword">int</span> bufsize = <span class="number">8192</span>;</div><div class="line">    <span class="keyword">byte</span>[] buf = <span class="keyword">new</span> <span class="keyword">byte</span>[bufsize];</div><div class="line">    <span class="keyword">int</span> splitbyte = <span class="number">0</span>;</div><div class="line">    <span class="keyword">int</span> rlen = <span class="number">0</span>;</div><div class="line">    &#123;</div><div class="line">        <span class="keyword">int</span> read = is.read(buf, <span class="number">0</span>, bufsize);</div><div class="line">        <span class="keyword">while</span> (read &gt; <span class="number">0</span>) &#123;</div><div class="line">            rlen += read;</div><div class="line">            splitbyte = findHeaderEnd(buf, rlen);</div><div class="line">            <span class="keyword">if</span> (splitbyte &gt; <span class="number">0</span>)</div><div class="line">                <span class="keyword">break</span>;</div><div class="line">            read = is.read(buf, rlen, bufsize - rlen);</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="comment">// Create a BufferedReader for parsing the header.</span></div><div class="line">    ByteArrayInputStream hbis = <span class="keyword">new</span> ByteArrayInputStream(buf, <span class="number">0</span>, rlen);</div><div class="line">    BufferedReader hin = <span class="keyword">new</span> BufferedReader(<span class="keyword">new</span> InputStreamReader(hbis));</div><div class="line">    Properties pre = <span class="keyword">new</span> Properties();</div><div class="line">    Properties parms = <span class="keyword">new</span> Properties();</div><div class="line">    Properties header = <span class="keyword">new</span> Properties();</div><div class="line"></div><div class="line">    <span class="keyword">try</span> &#123;</div><div class="line">        decodeHeader(hin, pre, parms, header);</div><div class="line">    &#125; <span class="keyword">catch</span> (InterruptedException e1) &#123;</div><div class="line">        Log.e(TAG, <span class="string">"Exception: "</span> + e1.getMessage());</div><div class="line">        e1.printStackTrace();</div><div class="line">    &#125;</div><div class="line">  </div><div class="line">    String range = header.getProperty(<span class="string">"range"</span>);</div><div class="line">    cbSkip = <span class="number">0</span>;</div><div class="line">    <span class="keyword">if</span> (range != <span class="keyword">null</span>) &#123;</div><div class="line">        Log.e(TAG, <span class="string">"range is: "</span> + range);</div><div class="line">        range = range.substring(<span class="number">6</span>);</div><div class="line">        <span class="keyword">int</span> charPos = range.indexOf(<span class="string">'-'</span>);</div><div class="line">        <span class="keyword">if</span> (charPos &gt; <span class="number">0</span>) &#123;</div><div class="line">            range = range.substring(<span class="number">0</span>, charPos);</div><div class="line">        &#125;</div><div class="line">        cbSkip = Long.parseLong(range);</div><div class="line">        Log.i(TAG, <span class="string">"range found!! "</span> + cbSkip);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    sendHTMLtext(HTMLManager.getDownloadingHTML(), client.getOutputStream());</div><div class="line">    mSendState = SEND_STATE_SENDING;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">sendHTMLtext</span><span class="params">(String htmlStr, OutputStream outputStream)</span> </span>&#123;</div><div class="line">    PrintWriter printWriter = <span class="keyword">new</span> PrintWriter(outputStream);</div><div class="line">    printWriter.println(htmlStr);</div><div class="line">    printWriter.close();</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<h3 id="4-2-使用XMLHttpRequest在网页上实时获取下载进度"><a href="#4-2-使用XMLHttpRequest在网页上实时获取下载进度" class="headerlink" title="4.2 使用XMLHttpRequest在网页上实时获取下载进度"></a>4.2 使用<code>XMLHttpRequest</code>在网页上实时获取下载进度</h3><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><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></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> xmlhttp = <span class="keyword">new</span> XMLHttpRequest;</div><div class="line"><span class="keyword">var</span> url = <span class="string">"http://192.168.43.1:8080"</span>;</div><div class="line"><span class="keyword">var</span> timer = setInterval(<span class="string">"loadurl(url)"</span>, <span class="number">500</span>); <span class="comment">// 定时请求刷新</span></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">loadurl</span>(<span class="params">url</span>) </span>&#123;</div><div class="line">        <span class="keyword">if</span> (xmlhttp != <span class="literal">null</span>) &#123;</div><div class="line">            xmlhttp.onreadystatechange = state_Change;</div><div class="line">            xmlhttp.open(<span class="string">"GET"</span>, url, <span class="literal">true</span>);</div><div class="line">            xmlhttp.send(<span class="literal">null</span>);</div><div class="line">        &#125; <span class="keyword">else</span> &#123;</div><div class="line">            alert(<span class="string">"Your browser does not support XMLHTTP."</span>);</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">state_Change</span>(<span class="params"></span>) </span>&#123;</div><div class="line">    <span class="keyword">var</span> infoBar = <span class="built_in">document</span>.getElementsByClassName(<span class="string">"cube"</span>)[<span class="number">0</span>];</div><div class="line">    <span class="keyword">if</span> (xmlhttp.responseText == <span class="string">""</span>) <span class="keyword">return</span>;</div><div class="line">    <span class="keyword">var</span> percent = <span class="built_in">parseInt</span>(xmlhttp.responseText.substring(<span class="number">0</span>, <span class="number">3</span>));</div><div class="line">    <span class="keyword">if</span> (percent != <span class="literal">NaN</span>) &#123;</div><div class="line">        infoBar.innerHTML = xmlhttp.responseText; <span class="comment">// 刷新DOM元素</span></div><div class="line">        <span class="keyword">if</span> (percent == <span class="number">100</span>) &#123;</div><div class="line">            clearInterval(timer);</div><div class="line">            infoBar.innerHTML = <span class="string">"Complete. Please install it."</span>;</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<h2 id="5-Demo的展示与介绍"><a href="#5-Demo的展示与介绍" class="headerlink" title="5. Demo的展示与介绍"></a>5. Demo的展示与介绍</h2><p>wifi热点的创建和文件传输</p>
<h2 id="6-小结"><a href="#6-小结" class="headerlink" title="6. 小结"></a>6. 小结</h2><h3 id="6-1-基于安卓的wifi传输-能做到什么-？"><a href="#6-1-基于安卓的wifi传输-能做到什么-？" class="headerlink" title="6.1 基于安卓的wifi传输 ==能做到什么==？"></a>6.1 基于安卓的wifi传输 ==能做到什么==？</h3><ol>
<li>局域网内，安装我们APP的手机之间的互相发现和连接</li>
<li>热点的创建和定制</li>
<li>免流量的高速、稳定的数据传输，相对于蓝牙和NFC具有很大优势</li>
<li>一方安装了APP，另一方仍可通过热点连接，基于网页JS实现与主机APP的信息交互</li>
</ol>
<h3 id="6-2-基于安卓的wifi传输-不能做到什么-？-有哪些坑-？"><a href="#6-2-基于安卓的wifi传输-不能做到什么-？-有哪些坑-？" class="headerlink" title="6.2 基于安卓的wifi传输 ==不能做到什么==？==有哪些坑==？"></a>6.2 基于安卓的wifi传输 ==不能做到什么==？==有哪些坑==？</h3><ol>
<li>没有底层权限，很多服务器常见的设置都无法完成，比如无法设置<code>IPTable</code></li>
<li>安卓网页的局限，浏览器对JS的支持性和PC端不同，需要额外设计</li>
<li>部分安卓厂商自己修改了官方的热点API，比如HTC，这使得在这些手机上创建热点需要额外配置</li>
</ol>
]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;大纲&quot;&gt;&lt;a href=&quot;#大纲&quot; class=&quot;headerlink&quot; title=&quot;大纲&quot;&gt;&lt;/a&gt;大纲&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;Wifi传输概述&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WifiP2pManager&lt;/code&gt;类的介绍和使用&lt;/li&gt;
&lt;li&gt;Wifi热点创建相关技术&lt;/li&gt;
&lt;li&gt;基于Wifi的文件传输方法&lt;/li&gt;
&lt;li&gt;Demo的展示与介绍&lt;/li&gt;
&lt;li&gt;小结&lt;/li&gt;
&lt;/ol&gt;
    
    </summary>
    
    
      <category term="Android" scheme="http://thundertrick.github.io/tags/Android/"/>
    
      <category term="Wi-Fi" scheme="http://thundertrick.github.io/tags/Wi-Fi/"/>
    
  </entry>
  
  <entry>
    <title>Hello World</title>
    <link href="http://thundertrick.github.io/2016/07/29/hello-world/"/>
    <id>http://thundertrick.github.io/2016/07/29/hello-world/</id>
    <published>2016-07-29T07:15:10.000Z</published>
    <updated>2016-07-29T07:15:10.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>
<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">
    
      &lt;p&gt;Welcome to &lt;a href=&quot;https://hexo.io/&quot; target=&quot;_blank&quot; rel=&quot;external&quot;&gt;Hexo&lt;/a&gt;! This is your very first post. Check &lt;a href=&quot;https://hexo.
    
    </summary>
    
    
  </entry>
  
</feed>
