<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>smilEdit</title>
  
  <link href="/atom.xml" rel="self"/>
  
  <link href="http://yoursite.com/"/>
  <updated>2018-11-14T03:14:57.677Z</updated>
  <id>http://yoursite.com/</id>
  
  <author>
    <name>Zhanglf</name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>十一月的第二个星期三</title>
    <link href="http://yoursite.com/2018/11/14/%E5%8D%81%E4%B8%80%E6%9C%88%E7%9A%84%E7%AC%AC%E5%8D%81%E5%9B%9B%E5%A4%A9/"/>
    <id>http://yoursite.com/2018/11/14/十一月的第十四天/</id>
    <published>2018-11-14T03:05:45.000Z</published>
    <updated>2018-11-14T03:14:57.677Z</updated>
    
    <content type="html"><![CDATA[<p>距离 2018 年结束还有 47 天。</p>
<a id="more"></a>
<p>有点难集中注意力做一件事。</p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;距离 2018 年结束还有 47 天。&lt;/p&gt;
    
    </summary>
    
      <category term="随笔" scheme="http://yoursite.com/categories/%E9%9A%8F%E7%AC%94/"/>
    
    
      <category term="个人随想" scheme="http://yoursite.com/tags/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
  </entry>
  
  <entry>
    <title>窗口机制和拥塞避免算法</title>
    <link href="http://yoursite.com/2018/10/21/%E7%AA%97%E5%8F%A3%E6%9C%BA%E5%88%B6%E5%92%8C%E6%8B%A5%E5%A1%9E%E9%81%BF%E5%85%8D%E7%AE%97%E6%B3%95/"/>
    <id>http://yoursite.com/2018/10/21/窗口机制和拥塞避免算法/</id>
    <published>2018-10-21T12:26:02.000Z</published>
    <updated>2018-10-22T02:22:15.036Z</updated>
    
    <content type="html"><![CDATA[<h3 id="窗口机制"><a href="#窗口机制" class="headerlink" title="窗口机制"></a>窗口机制</h3><p>滑动窗口是 TCP 协议中非常重要的一个概念。</p>
<p>TCP 在解决可靠传输以及包乱序这个问题的时，引入了 Sliding Window 。</p>
<p>滑动窗口分为接受窗口和发送窗口。</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/8EBAD15B-5F50-4536-8E31-0FD0BBBCBB1D.png" alt="8EBAD15B-5F50-4536-8E31-0FD0BBBCBB1D"></p>
<a id="more"></a>
<p>TCP 头有一个字段叫 Window ，这个字段是接收端告诉发送端自己还有多少缓冲区可以接收数据。Window 是一个 16bit 位字段，代表的是窗口字节容量，也就是TCP的标准窗口最大为 2^16 -1 = 65535 个字节。</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/7F44F015-BE82-4486-BAE6-3FD6EBE863AC.png" alt="7F44F015-BE82-4486-BAE6-3FD6EBE863AC"></p>
<ul>
<li>LastByteAcked 被接收端 Ack 过的位置，只要被 Ack 过才算是真正的发送成功</li>
<li>LastByteSent 表示已经发送了，但是没有收到 Ack</li>
<li>LastByteWritten 上层应用正在写的地方</li>
</ul>
<hr>
<ul>
<li>LastByteRead 缓冲区中读到的位置</li>
<li>NextByteExpected 收到的连续包的最后一个位置</li>
<li>LastByteRcved 收到包的最后一个位置，中间可能有一些数据没有到达</li>
</ul>
<hr>
<ul>
<li>接收端在 ACK 中返回自己的 Window 为 最大缓存区大小 MaxRcvBuffer - LastByteRcvd -1 </li>
<li>发送端根据该字段大小控制数据发送的多少</li>
</ul>
<p>对于发送方来说，任何时候它缓存区中的数据都可以分为四类：</p>
<ol>
<li>已经发送并且收到了发送端 ACK 的</li>
<li>发送但是没有收到发送端 ACK 的</li>
<li>未发送但是发送端允许发送的</li>
<li>未发送且发送端不允许发送的</li>
</ol>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/B4F9CEA8-7F2D-45BD-AE13-FC4C3A86590C.png" alt="B4F9CEA8-7F2D-45BD-AE13-FC4C3A86590C"></p>
<p>当收到发送端的 ACK 时，对之前的数据重新分类：</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/96CB0775-1CE7-4927-BADE-A09B6843455A.png" alt="96CB0775-1CE7-4927-BADE-A09B6843455A"></p>
<p>当收到的 ACK = 36 时窗口滑动。</p>
<h3 id="拥塞避免算法"><a href="#拥塞避免算法" class="headerlink" title="拥塞避免算法"></a>拥塞避免算法</h3><p>为什么会设计这么一个算法？</p>
<p>TCP 通过滑动窗口来控制流量，但是控制的仅仅是收发两端的流量数据，并不知道当前网络中发生了什么，如果不清楚当前网络的情况，当网络出现延时情况时，大量数据都需要重传，网络中的将出现非常多的重传数据，这样又会导致更多的包丢失。</p>
<p>TCP 就是像一个交通法则，管理约束着所有在公路网上行驶的车辆，避免出现大规模的堵塞现象。</p>
<p>该规则主要有四个算法：</p>
<p>(cwnd 全称 Congestion Window)</p>
<h4 id="慢启动-Slow-Start"><a href="#慢启动-Slow-Start" class="headerlink" title="慢启动  Slow Start"></a>慢启动  Slow Start</h4><p>表面意思比较好理解，</p>
<p>买了一个馒头，吃了之后发现不够饱。又买了两个，还是不够饱，再买四个吃… 别问我为什么一开始不买十个，一开始我也不知道我要吃几个才饱。只能是慢慢试探自己的胃。</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/0C04D101-E84D-4649-8249-547CAB75A118.png" alt="0C04D101-E84D-4649-8249-547CAB75A118"></p>
<p>具体一开始买几个吃，以及吃不饱之后再买几个吃，这个就比较有讲究了。目前知道是这个增长速度是指数形式的。</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/15401293153337.jpg" alt></p>
<h4 id="拥塞避免-Congestion-Avoidance"><a href="#拥塞避免-Congestion-Avoidance" class="headerlink" title="拥塞避免 Congestion Avoidance"></a>拥塞避免 Congestion Avoidance</h4><p>ssthresh (slow start threshold)，是一个上限，当 cwnd &gt;= ssthresh 时，就会进入拥塞避免算法，该值一般是 65535 字节。</p>
<p>之前说过，慢算法是指数上涨，而拥塞避免算法是线性上涨。</p>
<p>还是吃馒头，当吃到一定个数时，觉得有点饱了，但是还没到完全吃不下的地步，可又能再按照之前的方式增加，否则就太浪费了，那么就调整算法，相对的减缓增加的数量。</p>
<h4 id="拥塞发生"><a href="#拥塞发生" class="headerlink" title="拥塞发生"></a>拥塞发生</h4><p>当 RTO （Retransmission TimeOut） 超时，重传数据包，此时参数发生改变：</p>
<ol>
<li>sshthresh = cwnd/2</li>
<li>cwnd 重置为 1</li>
<li>重新进入慢启动过程</li>
</ol>
<p>因为丢包现象严重时，需要快速减少在网络上传输的包，然后重新观察网络状况。</p>
<p><strong>Fast Retransmit 算法，</strong>收到 3 个 duplicate ACK 时就开启重传，因为还能收到 ACK 所以认为没那么严重，减少的量也没上上面那种大：</p>
<ol>
<li>cwnd = cwnd/2</li>
<li>sshthresh = cwnd</li>
<li>进入快速恢复算法 —— Fast Recovery</li>
</ol>
<h4 id="快速恢复-Fast-Recovery"><a href="#快速恢复-Fast-Recovery" class="headerlink" title="快速恢复 Fast Recovery"></a>快速恢复 Fast Recovery</h4><p><strong>TCP Reno ：</strong></p>
<p>快速重传和快速恢复算法一般同时使用。快速恢复算法是认为，你还有 3 个 Duplicated Acks 说明网络也不那么糟糕，所以没有必要像 RTO 超时那么强烈。此前的参数：</p>
<ol>
<li>cwnd = cwnd/2</li>
<li>sshthresh = cwnd</li>
</ol>
<p><strong>Fast Recovery 算法启动：</strong></p>
<ol>
<li>cwnd = sshthresh  + 3 * MSS （ 3 的意思是确认有 3 个数据包被收到了）</li>
<li>重传 Duplicated ACKs 指定的数据包</li>
<li>如果再收到 duplicated Acks，那么 cwnd = cwnd + 1</li>
<li>如果收到了新的 Ack，那么，cwnd = sshthresh ，然后就进入了拥塞避免的算法了</li>
</ol>
<p>参考链接：</p>
<p><a href="https://www.zhihu.com/question/32255109" target="_blank" rel="noopener">https://www.zhihu.com/question/32255109</a><br><a href="http://www.tcpipguide.com/free/t_TCPSlidingWindowAcknowledgmentSystemForDataTranspo-6.htm" target="_blank" rel="noopener">http://www.tcpipguide.com/free/t_TCPSlidingWindowAcknowledgmentSystemForDataTranspo-6.htm</a><br><a href="https://coolshell.cn/articles/11609.html" target="_blank" rel="noopener">https://coolshell.cn/articles/11609.html</a><br><a href="https://www.cnblogs.com/luoquan/p/4886345.html" target="_blank" rel="noopener">https://www.cnblogs.com/luoquan/p/4886345.html</a></p>
]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;窗口机制&quot;&gt;&lt;a href=&quot;#窗口机制&quot; class=&quot;headerlink&quot; title=&quot;窗口机制&quot;&gt;&lt;/a&gt;窗口机制&lt;/h3&gt;&lt;p&gt;滑动窗口是 TCP 协议中非常重要的一个概念。&lt;/p&gt;
&lt;p&gt;TCP 在解决可靠传输以及包乱序这个问题的时，引入了 Sliding Window 。&lt;/p&gt;
&lt;p&gt;滑动窗口分为接受窗口和发送窗口。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://on9hzfn6s.bkt.clouddn.com/8EBAD15B-5F50-4536-8E31-0FD0BBBCBB1D.png&quot; alt=&quot;8EBAD15B-5F50-4536-8E31-0FD0BBBCBB1D&quot;&gt;&lt;/p&gt;
    
    </summary>
    
      <category term="计算机基础" scheme="http://yoursite.com/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/"/>
    
    
      <category term="计算机网络" scheme="http://yoursite.com/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/"/>
    
      <category term="协议" scheme="http://yoursite.com/tags/%E5%8D%8F%E8%AE%AE/"/>
    
      <category term="网络" scheme="http://yoursite.com/tags/%E7%BD%91%E7%BB%9C/"/>
    
      <category term="传输" scheme="http://yoursite.com/tags/%E4%BC%A0%E8%BE%93/"/>
    
      <category term="TCP" scheme="http://yoursite.com/tags/TCP/"/>
    
  </entry>
  
  <entry>
    <title>TCP的三次握手和四次挥手</title>
    <link href="http://yoursite.com/2018/10/18/TCP%E7%9A%84%E4%B8%89%E6%AC%A1%E6%8F%A1%E6%89%8B%E5%92%8C%E5%9B%9B%E6%AC%A1%E6%8C%A5%E6%89%8B/"/>
    <id>http://yoursite.com/2018/10/18/TCP的三次握手和四次挥手/</id>
    <published>2018-10-18T06:25:40.000Z</published>
    <updated>2018-10-22T12:06:02.856Z</updated>
    
    <content type="html"><![CDATA[<h4 id="三次握手"><a href="#三次握手" class="headerlink" title="三次握手"></a>三次握手</h4><p>为什么是三次而不是两次或者四次？  因为两次太少，四次浪费，三次是保证双方相互明确对方能收能发的最低值。</p>
<p>理论上多少次握手这个可信的通道都是建立不起来的，但是通过三次握手至少可以确认它是可用的，往上加握手次数只是在提高这个可信的程度。</p>
<p>说是三次握手其实不够准确，因为其实就是两次握手两次确认，只是其中一方将握手和确认合并在了一块。或者说其实只是一次握手，毕竟是 three-way handshake，而不是 three handshakes ，有三个步骤的一次握手。</p>
<a id="more"></a>
<p>TCP 协议中大致分为五类报文：</p>
<ol>
<li>SYN <strong>建立连接</strong>（Synchronize </li>
<li>Data   <strong>数据传输</strong>                           </li>
<li>FIN <strong>断开连接</strong>（Finish                       </li>
<li>Reset <strong>重置连接</strong>                             </li>
<li>ACK <strong>确认连接</strong>（Acknowledgement               </li>
</ol>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/27894C0E-E440-4C22-8E32-E47D14735ED0.png" alt="27894C0E-E440-4C22-8E32-E47D14735ED0"></p>
<p>这图已经将三次握手的过程，画的非常清楚了，只需要知道一点，就是这个 seq 是什么，有什么用？</p>
<p>seq ： 是由操作系统动态随机选取的一个 32 位长的序列号，该序列号是为了告诉对方哪些数据是合法的，因为之后的数据都会在此基础上增加。</p>
<p>TCP 握手，握的是什么，就是交换双方的数据原点的序列号，也是就是这个 seq 。</p>
<p><strong>来看看，如果我们换成四次握手是怎么样的：</strong></p>
<ol>
<li>A 发送 SYN + A’seq</li>
<li>B 接收 A 的连接请求，记录 A’seq 到本地，命名 B 的 ACK 为 A’seq + 1</li>
<li>B 发送 SYN + B’s seq</li>
<li>A 接收到 B 的同步信号，记录 B’seq 到本地，命名 A 的 ACK 为 B’seq + 1</li>
</ol>
<p>其中 2 和 3 可以合并为一个步骤。</p>
<p>那么如果 4 这个步骤中 A 的 ACK ，B 没有收到会怎么样呢？</p>
<p>A 不会重传这个 ACK ，而是 B 在没有收到 A 的 ACK 时，会不断的重传自己的 seq 直到接收的 A 的 ACK 为止。</p>
<p><strong>如果换成两次握手又会是怎么样？</strong></p>
<ol>
<li>A 发送 SYN + A’seq</li>
<li>B 发送 SYN + B’seq + ACK</li>
</ol>
<p>由于最后少了 A 的 ACK ，所以 B 不确定 A 是否真的收到了 B 的 seq ，可能 B 的 seq 发送失败了，那么这次握手其实是不成功的，但是双方都不清楚。</p>
<h4 id="四次挥手"><a href="#四次挥手" class="headerlink" title="四次挥手"></a>四次挥手</h4><p>了解了三次握手之后再理解四次挥手就简单许多。</p>
<p>为什么挥手比握手多一次呢？多的这一次做了什么？</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/20170607205756255.gif" alt="20170607205756255"></p>
<p>看上图可以很直观的知道，关闭请求是客户端发出的，当客户端发出关闭请求时，服务端可能还有数据没有传输完成，所以会先发一个收到关闭请求的 ack ，等数据全部传输完成之后再发送 FIN，其它三步骤和三次握手基本一样。</p>
<p>这里有个比较有意思的东西，在客户端发送了最后的 ACK 包之后，会等待 2MSL ，这个 2MSL 是什么，为什么最后需要等待 2MSL 呢？</p>
<p>MSL（Maximum Segment Lifetime），报文最大生存时间，任何报文在网络上超过该时长都会被丢弃。</p>
<p>等待 2MSL 的目的就是担心最后一个 ACK 包对方没有收到，因为如果对方真的没有收到这个 ACK 就会重新发送之前的 FIN，那么此时就需要再次发送 ACK ，然后重置等待时间为 2MSL ，直到对方不发送 FIN 默认就是收到了 ACK 。</p>
]]></content>
    
    <summary type="html">
    
      &lt;h4 id=&quot;三次握手&quot;&gt;&lt;a href=&quot;#三次握手&quot; class=&quot;headerlink&quot; title=&quot;三次握手&quot;&gt;&lt;/a&gt;三次握手&lt;/h4&gt;&lt;p&gt;为什么是三次而不是两次或者四次？  因为两次太少，四次浪费，三次是保证双方相互明确对方能收能发的最低值。&lt;/p&gt;
&lt;p&gt;理论上多少次握手这个可信的通道都是建立不起来的，但是通过三次握手至少可以确认它是可用的，往上加握手次数只是在提高这个可信的程度。&lt;/p&gt;
&lt;p&gt;说是三次握手其实不够准确，因为其实就是两次握手两次确认，只是其中一方将握手和确认合并在了一块。或者说其实只是一次握手，毕竟是 three-way handshake，而不是 three handshakes ，有三个步骤的一次握手。&lt;/p&gt;
    
    </summary>
    
      <category term="计算机基础" scheme="http://yoursite.com/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/"/>
    
    
      <category term="计算机网络" scheme="http://yoursite.com/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/"/>
    
      <category term="协议" scheme="http://yoursite.com/tags/%E5%8D%8F%E8%AE%AE/"/>
    
      <category term="网络" scheme="http://yoursite.com/tags/%E7%BD%91%E7%BB%9C/"/>
    
      <category term="传输" scheme="http://yoursite.com/tags/%E4%BC%A0%E8%BE%93/"/>
    
  </entry>
  
  <entry>
    <title>CAP</title>
    <link href="http://yoursite.com/2018/10/17/CAP/"/>
    <id>http://yoursite.com/2018/10/17/CAP/</id>
    <published>2018-10-17T03:01:59.000Z</published>
    <updated>2018-10-18T06:22:21.787Z</updated>
    
    <content type="html"><![CDATA[<p>对于一个分布式计算系统来说，不可能同时满足以下三点：</p>
<p><strong>Consistency 一致性</strong><br>所有节点访问到的都是同一份最新的数据</p>
<p><strong>Availablity 可用性</strong><br>每次请求都能获取到响应，不一定是最新的</p>
<p><strong>Partition tolerance 分区容错性</strong><br>由于网络原因，两台不同服务器可能没法通信</p>
<p>CAP 理论说的是，由于网络通信的问题，所以分区容错性是一定存在的，那么在此基础上 C 和 A 是不能够共存的。</p>
<a id="more"></a>
<p>为什么不能够共存呢？</p>
<p>举个例子：</p>
<p>G1 和 G2 是两台服务器，上面存在一条共同的记录 V0，现在一个用户向服务器发起一个写入请求，将 V0 修改为 V1，G1 修改完成后返回确认指令。</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/941D1AC5-4756-432A-BEBF-A5F075DD7AD2.png" alt="941D1AC5-4756-432A-BEBF-A5F075DD7AD2"></p>
<p>但是如果用户这时候向 G2 发起读的请求就会返回 V0：</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/A73EBBAE-A4E7-4B23-B13C-4EDADD8504F4.png" alt="A73EBBAE-A4E7-4B23-B13C-4EDADD8504F4"></p>
<p>那么这样就不能够保证一致性了，所以为了保证一性质，可以在用户向 G1 发起写入请求时，G1 与 G2 之间进行数据同步，并上锁，不允许用户访问该数据，当同步完成之后才给用户返回写入完成的指令。这时用户再向 G2 发起读的请求，由于 G1 已经和 G2 同步过数据，所以读取到数据是 V1：</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/A04460AE-3BAD-4D11-A082-AFB13E951BBB.png" alt="A04460AE-3BAD-4D11-A082-AFB13E951BBB"></p>
<p>这样就能够解决一致性的问题了。也就是说按照这种方案可以同时满足 C 和 P 。</p>
<p>但是在 G1 与 G2 同步的过程中，如果有用户请求 G2 读取数据，那么由于此时 G1 和 G2 在同步数据，该数据属于上锁状态，暂时不允许被读，否则会返回 V0 这种过期数据。所以这时的 G2 是不可用的，不满足可用性这个特点。</p>
<p>反之，如果在 G1 和 G2 同步的过程中，不对该数据上锁，那么用户访问 G2 就会返回 V0 这条过期数据，虽然数据可能不是最新数据，但是 G2 至少是处于可响应的状态，那么这样就能够同时满足 A 和 P ，不满足 C。</p>
<p>到处可以看出 CAP 三者中，最多只能是 CA 或者 CP。</p>
<p>当然，如果存在这么一个服务器，它的运算和存储能力都是无穷大，并且网络通信都是百分之百畅通且无延时，那么也就不需要分布式这个系统了。这样在一定程度上也是满足了 CAP 三者。</p>
<p>图片来源：<a href="https://mwhittaker.github.io/blog/an_illustrated_proof_of_the_cap_theorem/" target="_blank" rel="noopener">https://mwhittaker.github.io/blog/an_illustrated_proof_of_the_cap_theorem/</a></p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;对于一个分布式计算系统来说，不可能同时满足以下三点：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Consistency 一致性&lt;/strong&gt;&lt;br&gt;所有节点访问到的都是同一份最新的数据&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Availablity 可用性&lt;/strong&gt;&lt;br&gt;每次请求都能获取到响应，不一定是最新的&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Partition tolerance 分区容错性&lt;/strong&gt;&lt;br&gt;由于网络原因，两台不同服务器可能没法通信&lt;/p&gt;
&lt;p&gt;CAP 理论说的是，由于网络通信的问题，所以分区容错性是一定存在的，那么在此基础上 C 和 A 是不能够共存的。&lt;/p&gt;
    
    </summary>
    
      <category term="计算机基础" scheme="http://yoursite.com/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/"/>
    
    
      <category term="计算机网络" scheme="http://yoursite.com/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/"/>
    
      <category term="分布式" scheme="http://yoursite.com/tags/%E5%88%86%E5%B8%83%E5%BC%8F/"/>
    
  </entry>
  
  <entry>
    <title>一天</title>
    <link href="http://yoursite.com/2018/01/19/%E4%B8%80%E5%A4%A9/"/>
    <id>http://yoursite.com/2018/01/19/一天/</id>
    <published>2018-01-19T08:34:39.000Z</published>
    <updated>2018-02-11T07:12:37.510Z</updated>
    
    <content type="html"><![CDATA[<center><br><br><img src="http://on9hzfn6s.bkt.clouddn.com/屏幕快照 2018-01-11 下午10.58.05.png" alt="屏幕快照 2018-01-11 下午10.58.05"><br><br></center>

<a id="more"></a>
]]></content>
    
    <summary type="html">
    
      &lt;center&gt;&lt;br&gt;&lt;br&gt;&lt;img src=&quot;http://on9hzfn6s.bkt.clouddn.com/屏幕快照 2018-01-11 下午10.58.05.png&quot; alt=&quot;屏幕快照 2018-01-11 下午10.58.05&quot;&gt;&lt;br&gt;&lt;br&gt;&lt;/center&gt;
    
    </summary>
    
      <category term="随笔" scheme="http://yoursite.com/categories/%E9%9A%8F%E7%AC%94/"/>
    
    
      <category term="随笔" scheme="http://yoursite.com/tags/%E9%9A%8F%E7%AC%94/"/>
    
  </entry>
  
  <entry>
    <title>雪落香杉树</title>
    <link href="http://yoursite.com/2017/09/25/%E9%9B%AA%E8%90%BD%E9%A6%99%E6%9D%89%E6%A0%91/"/>
    <id>http://yoursite.com/2017/09/25/雪落香杉树/</id>
    <published>2017-09-25T03:32:16.000Z</published>
    <updated>2017-09-25T08:24:42.000Z</updated>
    
    <content type="html"><![CDATA[<center><br><br><img src="http://on9hzfn6s.bkt.clouddn.com/s29476260.jpg" alt="s29476260"><br><br></center>

<p>先大抵说说故事。</p>
<a id="more"></a>
<p>在一个靠近西雅图的海岛上，住着美国人以及一些日裔，人们靠种草莓或者出海捕鱼为生，一切看起来都是那么祥和太平。</p>
<p>美丽的日裔少女初枝和邻家男孩伊什梅尔（美国人）青梅竹马，互生情愫，一起在海边嬉戏，在香山树洞中接吻… </p>
<p>但女孩因为自己的身份（日裔），心生芥蒂，从不在公众场合与伊什梅尔相认。</p>
<p>这份平静持续到日本偷袭了珍珠港。所有岛上的日裔都要被送出岛。那时候少女刚满 18 岁，离别前的一天，又是在香杉树洞中，他进入了她的身体，不过她推开了他，他说他们还是会在一起的，可能就是在战争结束后，他说他爱她。不过她却表示自己很迷茫。她不知道他们的未来，也不知道她对他的感情是否就是爱情。</p>
<p>岛上的日裔们被送去了沙漠中的集中营，在营中，她收到了他的信，他说他非常的想她，不过被她母亲发现了。不论是在什么角度，她母亲都觉得他们不合适，少女同意了，其实在她心里，她也是觉得他们不是一类人，她写了一信给他，说是他们不合适，以后就别联系了。</p>
<p>在集中营里她认识了她的丈夫宫本天道，也是从那个海岛上来了，后来他们在集中营里结了婚。</p>
<p>战争结束后，初枝夫妇回到了海岛上，伊什梅尔也回来了，不过战争带走了他的一只胳膊，当他看到自己的日思夜想的心上人成了别人老婆，还有了孩子，他无 FUCK 可说。</p>
<p>事情发生在一个雾蒙蒙的黎明，渔民们出海捕鱼，包括宫本。他在捕鱼时发现一艘渔船因为电池耗尽在海上漂泊，他给了渔船的主人卡尔自己的备用电池。他们分开后不久，卡尔的船被突如其来的一艘货船的巨浪打到，他不慎掉落水中，溺死在了自己的渔网里。</p>
<p>第二天有人发现了死在渔网中的卡尔，在调查中，许多的线索都指向天道，很多人也认为就是天道谋杀了卡尔。天道则是认为自己是日裔，不想多辩解什么，静静的等待审判到临。</p>
<p>伊什梅尔作为本地报社的负责人也出庭了，他还是忘不掉初枝，在法庭看到身为被告人妻子的她还是很是心动。在无意间他看到了一份只有他发现的资料，就是那艘货船的路线，他明白这份资料将在一定程度上，可以直接让天道无罪释放。</p>
<p>法庭上，就因为种族的问题，那些美国人潜意识里面就认定，天道就是杀人凶手，因为他长了一副日本人的脸。起诉人律师也刻意强调这件事。</p>
<p>那份资料在伊什梅尔口袋中躺了一整天之后，还是被交到了法官手里，天道被无罪释放了。</p>
<p>故事的叙述形式是穿插进行的，文章伊始就正在法庭接受审判的天道，之后又写伊什梅尔看到初枝回忆起小时候的场景。过去和现在的场景回来的交错进行。</p>
<p>书名雪落香杉树，有种异常纯洁的唯美。在香山树下他们相识相爱，也是在香山树下，他们相互分别。如果她是美国人，或许事情就是完全另一番景象了。可惜没有如果。</p>
<p>许多人觉得爱情可以跨越种族，跨越阶级，甚至跨越性别，却不知这些跨越之间存在着多么大的鸿沟。电视剧我的娜塔莎中日本女护士伊田纪子和庞天德半个世纪的苦恋，电影泰坦尼克号中 Rose 和 Jack 这对来着不同阶层的年轻人短暂的狂欢，平凡的世界中青梅竹马的穷小子少安与官二代润叶的无奈妥协，电影断背山中深爱对方的杰克和恩尼斯迫于现实的选择… 从现实到文学，此类例子数不胜数，以前有个老师和对我们说，婚姻中最重要的一点是门当户对，我一直都是嗤之以鼻，现在，在一定程度上，对当年老师说的话，我还是很支持理解的。</p>
<p>可以说自己变的世俗了，另一个角度来看，也是成长了。</p>
<p>单从爱情这条线就可以看出本书的想要表达的那个意思。我想作者和读者都是很期待有情人终成眷属吧。纯白的雪轻轻的落在香杉树上，微暖的树洞中，悸动的两人互述相思，一切都是那么美好。可惜事不如人愿，从初枝和伊什梅尔在那个时期出生，他们的血脉似乎就决定了，他们是不可能的。</p>
<p>书中有一个场景，那是战争结束后，伊什梅尔第一次在海岛上看到初枝，在一个商铺中，初枝抱着自己的孩子，伊什梅尔看着自己心爱的女人有了自己的家庭，感受着断臂的隐隐作痛，想到自己的断臂就是拜日本人所赐，他不禁愤怒的对初枝骂道，日本鬼子！</p>
<p>伊什梅尔尚且如此，岛上的其他美国人呢？</p>
<p>因而那场对于宫本天道的审判从一开始就是不公正的，许多人看着那副日本人的面孔，即使他是美国人，即使二战他也为美国人奋战沙场，可从骨子里，偏见就是挥之不去，始终存在。</p>
<p>或许有人该为那战争买单，但绝不是他们。难道只因为血脉就另眼相看？</p>
<p>全文，文笔细腻柔美，小岛的风景写的太好了。译者水平也好，翻译的很棒。另外，书本封面设计的有味道。</p>
]]></content>
    
    <summary type="html">
    
      &lt;center&gt;&lt;br&gt;&lt;br&gt;&lt;img src=&quot;http://on9hzfn6s.bkt.clouddn.com/s29476260.jpg&quot; alt=&quot;s29476260&quot;&gt;&lt;br&gt;&lt;br&gt;&lt;/center&gt;

&lt;p&gt;先大抵说说故事。&lt;/p&gt;
    
    </summary>
    
      <category term="阅读" scheme="http://yoursite.com/categories/%E9%98%85%E8%AF%BB/"/>
    
    
      <category term="读书笔记" scheme="http://yoursite.com/tags/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/"/>
    
  </entry>
  
  <entry>
    <title>Chrome 扩展程序之 Vimium</title>
    <link href="http://yoursite.com/2017/09/20/Chrome%E6%8F%92%E4%BB%B6%E4%B9%8BVimium/"/>
    <id>http://yoursite.com/2017/09/20/Chrome插件之Vimium/</id>
    <published>2017-09-20T02:20:49.000Z</published>
    <updated>2017-09-20T03:50:33.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Vimium"><a href="#Vimium" class="headerlink" title="Vimium"></a><a href="https://chrome.google.com/webstore/search/vimium?hl=zh-CN" target="_blank" rel="noopener">Vimium</a></h2><p>是否想过只用键盘就能完成浏览网页的日常需求？</p>
<p>我想其中最为困难的一点莫过于面对网页中茫茫多的超链接，用键盘基本是拿它没辙的吧。</p>
<p>当然，有了 Vimium ，就可以一战。</p>
<a id="more"></a>
<p>下面是按 f 键之后的网页，这时候只需要输入指定的字母就能自动跳转到对应的网页中。</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/FA2C37DB-44FA-4DA0-AF87-E916069E5702.png" alt="FA2C37DB-44FA-4DA0-AF87-E916069E5702"></p>
<p>一般网页跳转有两种方式，就是另起一个 tab 加载网页和在本 tab 加载网页，这两者 Vimium 都考虑到了，分别是 F(shift + f) 和 f 。</p>
<p>Vimium 有非常多的快捷键，只有想不到，没有做不到，这里说说我用到频率最多的几个。</p>
<p>直接输入问号会出现 Vimium 常用的快捷键，如下图:</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/7F6C4B45-B712-475E-A11B-1507600A7571.png" alt="7F6C4B45-B712-475E-A11B-1507600A7571"></p>
<p>上面列举了一些常用的快捷键。</p>
<h3 id="Tab-切换"><a href="#Tab-切换" class="headerlink" title="Tab 切换"></a>Tab 切换</h3><p>使用 Chrome 时切换 Tab 太频繁了。从最开始的 control + tab 从左到右一个一个切换到后来的 ⌥ + ⌘ + ← 或者 ⌥ + ⌘ + → 自由的左右切换 tab ，不过我觉得快捷键的位置还是有点儿变扭，毕竟方向键不好按到。Vimium 提供了更加方便的组合方式，通过 J(shift + j) 或者 K (shift + k) 自由的左右切换。</p>
<h3 id="滚动"><a href="#滚动" class="headerlink" title="滚动"></a>滚动</h3><p><strong>一点点向下浏览</strong> j</p>
<p><strong>一点点向上浏览</strong> k</p>
<p><strong>很多点很多点向下浏览</strong> d （down）</p>
<p><strong>很多点很多点向上浏览</strong> u （up）</p>
<p><strong>去顶部</strong> gg</p>
<p><strong>去底部</strong> G(shift + g)</p>
<h3 id="打开关闭"><a href="#打开关闭" class="headerlink" title="打开关闭"></a>打开关闭</h3><p><strong>关闭当前界面</strong> x （其实系统自带的也已经很不错了 ⌘ + w ）</p>
<p><strong>打开上一个被关闭的界面</strong> X（shift + x），这对组合很不错啊。（这个需求其实很常用，之前一直用系统自带的，shift + ⌘ + t）</p>
<p><strong>打开一个新的 tab</strong> t ，不过其实熟悉了一些打开方式之后，新打开一个 tab 这个步骤基本是没用的。 （系统自带的是⌘ + t）</p>
<p><strong>将粘贴板上的地址在新的 tab 中打开</strong> P(shift + p)</p>
<p><strong>将粘贴板上的地址在当前的 tab 中打开</strong> p</p>
<p><strong>返回上一个界面</strong> H(shift + h）</p>
<p><strong>去到下一个界面</strong> L(shift + l）</p>
<p>效果和用鼠标点这个是一样的：<br><img src="http://on9hzfn6s.bkt.clouddn.com/18D08384-E40A-468F-BFF7-A6A2A61A59ED.png" alt="18D08384-E40A-468F-BFF7-A6A2A61A59ED"></p>
<p><strong>打开历史浏览或者书签或者直接 Google 在新的 tab 中</strong> O(shift + o)</p>
<p><strong>打开历史浏览或者书签或者直接 Google 在当前界面</strong> o</p>
<p>有点类似 Alfred</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/09FCCA23-12D8-44D3-AF21-57F91EF84ED8.png" alt="09FCCA23-12D8-44D3-AF21-57F91EF84ED8"></p>
<h3 id="最后"><a href="#最后" class="headerlink" title="最后"></a>最后</h3><p>一般新建 tab 的都是在原有快捷键上加个 shift，也就是小写换成大写，方便记忆，很人性化。这个在原有的系统中，就是点击超级链接的时候，按住 ⌘ 再点，也能达到同样的效果。</p>
<p>Vimium 的快捷键不仅很多，而且设计的非常的人性化，许多常用的按键都是设计在触手可及的地方，像是浏览网页的 j、k、d、u 等等按键。</p>
<p>不过也有几个我觉得是 bug 的地方，所有的快捷键在非正常网页的地方都不起作用，例如在 OneTab 的界面或者是浏览器程序扩展界面按 J、K 之类的根本没用，有点不爽。</p>
<p>以及一些界面 F 和 f 的超级链接显示效果会有点距离的误差。</p>
<p>总的来说，还是很棒的，不过也要多使用熟悉吧。</p>
]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;Vimium&quot;&gt;&lt;a href=&quot;#Vimium&quot; class=&quot;headerlink&quot; title=&quot;Vimium&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://chrome.google.com/webstore/search/vimium?hl=zh-CN&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vimium&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;是否想过只用键盘就能完成浏览网页的日常需求？&lt;/p&gt;
&lt;p&gt;我想其中最为困难的一点莫过于面对网页中茫茫多的超链接，用键盘基本是拿它没辙的吧。&lt;/p&gt;
&lt;p&gt;当然，有了 Vimium ，就可以一战。&lt;/p&gt;
    
    </summary>
    
      <category term="效率" scheme="http://yoursite.com/categories/%E6%95%88%E7%8E%87/"/>
    
    
      <category term="Chrome" scheme="http://yoursite.com/tags/Chrome/"/>
    
  </entry>
  
  <entry>
    <title>compileSdkVersion,buildToolsVersion, minSdkVersion 和 targetSdkVersion</title>
    <link href="http://yoursite.com/2017/08/09/compileSdkVersion-minSdkVersion-%E5%92%8C-targetSdkVersion/"/>
    <id>http://yoursite.com/2017/08/09/compileSdkVersion-minSdkVersion-和-targetSdkVersion/</id>
    <published>2017-08-09T09:00:42.000Z</published>
    <updated>2017-08-09T10:19:42.000Z</updated>
    
    <content type="html"><![CDATA[<p>一直对这几个版本的概念都不是特别清楚，前几天面试的时候还被问到过，发现有必要好好整理一下。</p>
<a id="more"></a>
<h4 id="compileSdkVersion"><a href="#compileSdkVersion" class="headerlink" title="compileSdkVersion"></a>compileSdkVersion</h4><p>它告诉 Gradle 使用哪个 Android SDK 版本来运行你的应用，要使用当然要先下载。</p>
<p>重点： 修改 compileSdkVersion 并不会改变运行的时候的行为，但是有可能会出现新的编译问题，例如 compileSdkVersion 版本改成很低之后，出现如下的编译问题：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Error:(53, 30) 错误: -source 1.6 中不支持 diamond 运算符</span><br><span class="line">(请使用 -source 7 或更高版本以启用 diamond 运算符)</span><br></pre></td></tr></table></figure>
<p>虽然它纯粹只是在编译的时候使用，但是官方强烈建议我们使用最新的 SDK 进行编译，因为这样可以使用新的编译检查避免很多问题。</p>
<p>没有道理不用最新的啊？</p>
<h4 id="buildeToolsVersion"><a href="#buildeToolsVersion" class="headerlink" title="buildeToolsVersion"></a>buildeToolsVersion</h4><p>前面我们说了 compileSdkVersion 是我们SDK的版本号，也就是 API Level，例如 API-19、API-20、API-21 等等。</p>
<p>buildeToolsVersion 是我们构建工具的版本，其中包括了打包工具 aapt、dx 等等。这个工具的目录位于..your_sdk_path/build-tools/XX.XX.XX。</p>
<h4 id="minSdkVersion"><a href="#minSdkVersion" class="headerlink" title="minSdkVersion"></a>minSdkVersion</h4><p>这个概念相对非常好理解。就是该应用的最低要求。例如我们应用的 minSdkVersion 是 10 。 那么最高只支持 9 的手机是不能够安装这个应用的。</p>
<p>该设置的好处在开发也起到一个好处，在你使用了高于 minSdkVersion 的 API 时会警告你。</p>
<p>相对来说越低越好，但是许多时候，一些技术在低版本的设配上很难实现，这种时候是去做兼容还是舍弃就要好好决定了。</p>
<h4 id="targetSdkVersion"><a href="#targetSdkVersion" class="headerlink" title="targetSdkVersion"></a>targetSdkVersion</h4><p>相对来说，它是这几个概念中最难被理解的。</p>
<p>官方说它有点 interesting ， “targetSdkVersion is the main way Android provides forward compatibility” 。（ targetSdkVersion 是 Android 系统提供前向兼容的主要手段。）</p>
<p>这句话怎么理解呢？</p>
<p>举个例子，如果 API 10 中，有一个 A 方法是输出 “我喜欢你” ,而随着系统的升级，在 API 11 中，A 方法依然存在，但是源码却经过了改变，变成了输出“我喜欢你妈”。这种情况虽然非常少发生，但是还是有可能发生的。</p>
<p>那么这个时候设置 targetSdkVersion 的好处就来了。当设置 targetSdkVersion 为 10 时，系统运行时就会使用 API 10，输出“我喜欢你”；设置 targetSdkVersion 为 11 就会输出“我喜欢你妈”。</p>
<p>这么一解释，是不是就比较能够明白 targetSdkVersion 是 Android 系统提供前向兼容的主要手段 这句话了呢。</p>
<p>虽然 API 不会，但是 API 的行为却发生了变化。虽然一般情况下我们是将 targetSdkVersion 更新成最新的，但是要特别注意，最好是去查看新版 API 中，老的一些方法的变化，否则盲目的更新，可能就会出现 “我喜欢你” 就会变成 “我喜欢你妈” 这样的错误（虽然官方也是极力避免这种情况的发生）。</p>
<hr>
<p>照上面所说，一般情况下，这三种 Sdk 的版本的关系是这样的<br>minSdkVersion &lt;= targetSdkVersion &lt;= compileSdkVersion</p>
<p>但是理想上，这三者的关系应该是这样的：</p>
<p>minSdkVersion (lowest possible) &lt;= targetSdkVersion == compileSdkVersion (latest SDK)</p>
<hr>
<p>参考链接：</p>
<p><a href="https://stackoverflow.com/questions/24521017/android-gradle-buildtoolsversion-vs-compilesdkversion" target="_blank" rel="noopener">buildtoolsVersion vs compileSdkVersion</a></p>
<p><a href="http://www.bubuko.com/infodetail-1008155.html" target="_blank" rel="noopener">Android关于buildToolVersion与CompileSdkVersion的区别</a></p>
<p><a href="https://developer.android.com/guide/topics/manifest/uses-sdk-element.html#filtering" target="_blank" rel="noopener">关于 SDK 的版本，官网的一些解释。</a></p>
<p><a href="https://race604.com/android-targetsdkversion/" target="_blank" rel="noopener">Android targetSdkVersion 原理</a></p>
<p><a href="http://chinagdg.org/2016/01/picking-your-compilesdkversion-minsdkversion-targetsdkversion/" target="_blank" rel="noopener">如何选择 compileSdkVersion, minSdkVersion 和 targetSdkVersion</a></p>
<p><a href="http://blog.csdn.net/u012719153/article/details/50619881" target="_blank" rel="noopener">minSdkVersion、targetSdkVersion、compileSdkVersion三者的作用解析</a></p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;一直对这几个版本的概念都不是特别清楚，前几天面试的时候还被问到过，发现有必要好好整理一下。&lt;/p&gt;
    
    </summary>
    
      <category term="安卓" scheme="http://yoursite.com/categories/%E5%AE%89%E5%8D%93/"/>
    
    
      <category term="Android" scheme="http://yoursite.com/tags/Android/"/>
    
  </entry>
  
  <entry>
    <title>Android打包</title>
    <link href="http://yoursite.com/2017/08/09/Android%E6%89%93%E5%8C%85/"/>
    <id>http://yoursite.com/2017/08/09/Android打包/</id>
    <published>2017-08-09T07:13:52.000Z</published>
    <updated>2017-08-09T08:46:03.000Z</updated>
    
    <content type="html"><![CDATA[<p>打包的事，之前很少做，也了解的比较少，今天好好看了看，总结一下，以后要是用到了，或许可以少走些弯路。</p>
<a id="more"></a>
<h3 id="多渠道打包"><a href="#多渠道打包" class="headerlink" title="多渠道打包"></a>多渠道打包</h3><h4 id="友盟多渠道打包"><a href="#友盟多渠道打包" class="headerlink" title="友盟多渠道打包"></a>友盟多渠道打包</h4><p>友盟在 Github 也有相对应的<a href="https://github.com/umeng/umeng-muti-channel-build-tool" target="_blank" rel="noopener">文档</a>，主要是利用 Android Gradle 中的 ProductFlavor 功能添加的多个渠道。</p>
<p>首先在 AndroidManifest.xml 中添加</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;meta-data android:value=&quot;UMENG_CHANNEL_VALUE&quot; android:name=&quot;UMENG_CHANNEL&quot;/&gt;</span><br></pre></td></tr></table></figure>
<p>接着在 app 的 build.gradle 中添加：</p>
<figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">productFlavors &#123;</span><br><span class="line">    anzhi &#123;</span><br><span class="line">        manifestPlaceholders = [<span class="string">UMENG_CHANNEL_VALUE:</span> <span class="string">"anzhi"</span>]</span><br><span class="line">    &#125;</span><br><span class="line">    baidu &#123;</span><br><span class="line">        manifestPlaceholders = [<span class="string">UMENG_CHANNEL_VALUE:</span> <span class="string">"baidu"</span>]</span><br><span class="line">    &#125;</span><br><span class="line">    c360 &#123;</span><br><span class="line">        manifestPlaceholders = [<span class="string">UMENG_CHANNEL_VALUE:</span> <span class="string">"c360"</span>]</span><br><span class="line">    &#125;</span><br><span class="line">    yingyongbao &#123;</span><br><span class="line">        manifestPlaceholders = [<span class="string">UMENG_CHANNEL_VALUE:</span> <span class="string">"yingyongbao"</span>]</span><br><span class="line">    &#125;</span><br><span class="line">    huawei &#123;</span><br><span class="line">        manifestPlaceholders = [<span class="string">UMENG_CHANNEL_VALUE:</span> <span class="string">"huawei"</span>]</span><br><span class="line">    &#125;</span><br><span class="line">    xiaomi &#123;</span><br><span class="line">        manifestPlaceholders = [<span class="string">UMENG_CHANNEL_VALUE:</span> <span class="string">"xiaomi"</span>]</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>上面的配置看起来有点蠢，可以抽取出来，用一个方法来实现：</p>
<figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">productFlavors &#123;</span><br><span class="line">       anzhi &#123;&#125;</span><br><span class="line">       baidu &#123;&#125;</span><br><span class="line">       c360 &#123;&#125;</span><br><span class="line">       yingyongbao &#123;&#125;</span><br><span class="line">       huawei &#123;&#125;</span><br><span class="line">       xiaomi &#123;&#125;</span><br><span class="line">       productFlavors.all &#123; flavor -&gt;</span><br><span class="line">           flavor.manifestPlaceholders = [<span class="string">UMENG_CHANNEL_VALUE:</span> name]</span><br><span class="line">       &#125;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure>
<p>另外，签名的配置肯定不能少，也是在 app 的 build.gradle 文件中：</p>
<figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">signingConfigs &#123;</span><br><span class="line">       release &#123;</span><br><span class="line">           storeFile file(<span class="string">"demo.jks"</span>)</span><br><span class="line">           storePassword <span class="string">"123123"</span></span><br><span class="line">           keyAlias <span class="string">"123123"</span></span><br><span class="line">           keyPassword <span class="string">"123123"</span></span><br><span class="line">       &#125;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure>
<p>jks 和 keystore 俩文件，前者是 Android Studio 生成的，后者是 Eclipse 生成的，使用的时候两者都是可以的。</p>
<p>在 buildTypes 中加入对生成的 apk 的命名方式：</p>
<figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">android.applicationVariants.all &#123; variant -&gt;</span><br><span class="line">        variant.outputs.each &#123; output -&gt;</span><br><span class="line">            <span class="keyword">def</span> outputFile = output.outputFile</span><br><span class="line">            <span class="keyword">if</span> (outputFile != <span class="literal">null</span> &amp;&amp; outputFile.name.endsWith(<span class="string">'.apk'</span>)) &#123;</span><br><span class="line">                File outputDirectory = <span class="keyword">new</span> File(outputFile.parent);</span><br><span class="line">                <span class="keyword">def</span> fileName</span><br><span class="line">                <span class="keyword">if</span> (variant.buildType.name == <span class="string">"release"</span>) &#123;</span><br><span class="line"><span class="comment">//                    fileName = "app_v$&#123;defaultConfig.versionName&#125;_$&#123;packageTime()&#125;_$&#123;variant.productFlavors[0].name&#125;.apk"</span></span><br><span class="line">                    fileName = <span class="string">"caixiangji_$&#123;variant.productFlavors[0].name&#125;.apk"</span></span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line"><span class="comment">//                    fileName = "app_v$&#123;defaultConfig.versionName&#125;_$&#123;packageTime()&#125;_beta.apk"</span></span><br><span class="line">                    fileName = <span class="string">"caixiangji_$&#123;variant.productFlavors[0].name&#125;_beta.apk"</span></span><br><span class="line">                &#125;</span><br><span class="line">                output.outputFile = <span class="keyword">new</span> File(outputDirectory, fileName)</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<p>然后在 AS 自带的 Terminal 下输入：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gradlew assembleRelease</span><br></pre></td></tr></table></figure>
<p>不过有可能出现一些问题，我在 mac 下就遇到过，例如：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">-bash ：gradlew command not found</span><br></pre></td></tr></table></figure>
<p>那么有可能是<a href="http://blog.csdn.net/yyh352091626/article/details/52343951" target="_blank" rel="noopener">权限问题</a>，执行 </p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo chmod +x gradlew</span><br></pre></td></tr></table></figure>
<p>还有，在 mac 下执行当前目录下的命令要在前面加上 “./“。</p>
<p>当然也有可能是你没有<a href="http://www.sohu.com/a/158458258_500663" target="_blank" rel="noopener">配置好</a>环境变量，按步骤设置一遍就好了。</p>
<p>如果一切顺利，那么差不多等上 10 分钟可能就打包好了。其实除了命令行，也可以直接使用图形化窗口操作，双击运行即可。</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/屏幕快照 2017-08-09 下午4.00.08.png" alt="屏幕快照 2017-08-09 下午4.00.08"></p>
<h4 id="美团的多渠道打包"><a href="#美团的多渠道打包" class="headerlink" title="美团的多渠道打包"></a>美团的多渠道打包</h4><p><a href="https://github.com/Meituan-Dianping/walle" target="_blank" rel="noopener">Walle</a> ： Android Signature V2 Scheme 签名下的新一代渠道包<a href="http://www.jianshu.com/p/0ba717f7385f" target="_blank" rel="noopener">打包神器</a>。</p>
<p>打包速度相对前者来说，真的是特特别快。</p>
<p>集成步骤 Github 上的文档写的也挺详细的了。</p>
<h5 id="配置build-gradle"><a href="#配置build-gradle" class="headerlink" title="配置build.gradle"></a>配置build.gradle</h5><p>在位于项目的根目录 <code>build.gradle</code> 文件中添加Walle Gradle插件的依赖， 如下：</p>
<figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">buildscript &#123;</span><br><span class="line">    dependencies &#123;</span><br><span class="line">        classpath <span class="string">'com.meituan.android.walle:plugin:1.1.5'</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>并在当前App的 <code>build.gradle</code> 文件中apply这个插件，并添加上用于读取渠道号的AAR</p>
<figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">apply <span class="string">plugin:</span> <span class="string">'walle'</span></span><br><span class="line"></span><br><span class="line">dependencies &#123;</span><br><span class="line">    compile <span class="string">'com.meituan.android.walle:library:1.1.5'</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h5 id="配置插件"><a href="#配置插件" class="headerlink" title="配置插件"></a>配置插件</h5><figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">walle &#123;</span><br><span class="line">    <span class="comment">// 指定渠道包的输出路径</span></span><br><span class="line">    apkOutputFolder = <span class="keyword">new</span> File(<span class="string">"$&#123;project.buildDir&#125;/outputs/channels"</span>);</span><br><span class="line">    <span class="comment">// 定制渠道包的APK的文件名称</span></span><br><span class="line">    apkFileNameFormat = <span class="string">'$&#123;appName&#125;-$&#123;packageName&#125;-$&#123;channel&#125;-$&#123;buildType&#125;-v$&#123;versionName&#125;-$&#123;versionCode&#125;-$&#123;buildTime&#125;.apk'</span>;</span><br><span class="line">    <span class="comment">// 渠道配置文件</span></span><br><span class="line">    channelFile = <span class="keyword">new</span> File(<span class="string">"$&#123;project.getProjectDir()&#125;/channel"</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>这里是将渠道的配置文件单独抽取出来了，所以需要在 app 文件夹下新建一个文件 channel （ Text 类型），在里面配置渠道的信息，例如：</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/1638147-1e316c70eb9a0af6.png" alt="1638147-1e316c70eb9a0af6"></p>
<p>最后可以打包了，所有渠道的：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./gradlew clean assembleReleaseChannels</span><br></pre></td></tr></table></figure>
<p>或者是单独的渠道 (华为)：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./gradlew clean assembleReleaseChannels -PchannelList=huawei</span><br></pre></td></tr></table></figure>
<p>也可以直接用界面操作。</p>
<p>3 分钟不到， 10 多个不同渠道的包就打完了。</p>
<p>输出的位置是在 outputs/channels ，也可以自己配置。</p>
<h3 id="多版本，多环境"><a href="#多版本，多环境" class="headerlink" title="多版本，多环境"></a><a href="http://www.jianshu.com/p/872dc6f89cb4" target="_blank" rel="noopener">多版本，多环境</a></h3><p>多渠道使用 Walle 的情况下，我们可以基于 buildTypes 和 productFlavors 使用多版本和多环境的打包。</p>
<h4 id="多版本"><a href="#多版本" class="headerlink" title="多版本"></a>多版本</h4><p>基于buildTypes</p>
<ol>
<li>debug:调试版本,无混淆</li>
<li>release:发布版本,有混淆、压缩</li>
</ol>
<figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">buildTypes &#123;</span><br><span class="line">        release &#123;</span><br><span class="line">            minifyEnabled <span class="literal">true</span></span><br><span class="line">            proguardFiles getDefaultProguardFile(<span class="string">'proguard-android.txt'</span>), <span class="string">'proguard-rules.pro'</span></span><br><span class="line">            signingConfig signingConfigs.test</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        debug &#123;</span><br><span class="line">            minifyEnabled <span class="literal">false</span></span><br><span class="line">            proguardFiles getDefaultProguardFile(<span class="string">'proguard-android.txt'</span>), <span class="string">'proguard-rules.pro'</span></span><br><span class="line"></span><br><span class="line">            signingConfig signingConfigs.test</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<h4 id="多环境"><a href="#多环境" class="headerlink" title="多环境"></a>多环境</h4><p>基于productFlavors</p>
<ol>
<li>develop:开发环境，开发和自测时使用</li>
<li>check:测试环境，克隆一份生产环境的配置，在这里测试通过后，再发布到生产环境。</li>
<li>product:生产环境，正式提供服务的。</li>
</ol>
<figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">productFlavors &#123;</span><br><span class="line">        <span class="comment">//开发环境</span></span><br><span class="line">        develop &#123;</span><br><span class="line">            buildConfigField <span class="string">"int"</span>, <span class="string">"ENV_TYPE"</span>, <span class="string">"1"</span></span><br><span class="line">            applicationId <span class="string">'com.zhanglf.servertest.develop'</span></span><br><span class="line">            manifestPlaceholders = [</span><br><span class="line"><span class="symbol">                    app_name:</span> <span class="string">"开-Demo"</span>,</span><br><span class="line"><span class="symbol">                    app_icon:</span> <span class="string">"@mipmap/dev_launcher"</span></span><br><span class="line">            ]</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//测试环境</span></span><br><span class="line">        check &#123;</span><br><span class="line">            buildConfigField <span class="string">"int"</span>, <span class="string">"ENV_TYPE"</span>, <span class="string">"2"</span></span><br><span class="line">            applicationId <span class="string">'com.zhanglf.servertest.check'</span></span><br><span class="line">            manifestPlaceholders = [</span><br><span class="line"><span class="symbol">                    app_name:</span> <span class="string">"测-Demo"</span>,</span><br><span class="line"><span class="symbol">                    app_icon:</span> <span class="string">"@mipmap/check_launcher"</span></span><br><span class="line">            ]</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//生产环境</span></span><br><span class="line">        product &#123;</span><br><span class="line">            buildConfigField <span class="string">"int"</span>, <span class="string">"ENV_TYPE"</span>, <span class="string">"3"</span></span><br><span class="line">            applicationId <span class="string">'com.zhanglf.servertest.product'</span></span><br><span class="line">            manifestPlaceholders = [</span><br><span class="line"><span class="symbol">                    app_name:</span> <span class="string">"Demo"</span>,</span><br><span class="line"><span class="symbol">                    app_icon:</span> <span class="string">"@mipmap/pro_launcher"</span></span><br><span class="line">            ]</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<p>在 mainfest 中使用占位符：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">android:icon=&quot;$&#123;app_icon&#125;&quot;</span><br><span class="line">android:label=&quot;$&#123;app_name&#125;&quot;</span><br></pre></td></tr></table></figure>
<h3 id="不同渠道-资源替换问题"><a href="#不同渠道-资源替换问题" class="headerlink" title="不同渠道 资源替换问题"></a>不同渠道 资源替换问题</h3><p>一种比较想到的方式是就是通过代码的方式获取渠道信息，再通过该信息，分配不同的资源。但是该方式的缺点是，不同的资源在打包的时候都被放进了 apk 中。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">String channel = WalleChannelReader.getChannel(<span class="keyword">this</span>.getApplicationContext());</span><br></pre></td></tr></table></figure>
<p>另一种方式就是根据不同的渠道在打包的时候就将对应的资源分配好了，上面的多环境中的 icon 和 app_name 占位符的方式就是如此。</p>
<p>具体实现：</p>
<p>在项目工程的 src 文件夹下创建对应渠道的文件夹，下面存放资源文件，如下：</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/20151227235630312.png" alt="20151227235630312"></p>
<p>这样通过不同渠道打包的时候，资源文件会自动覆盖 main 中的资源，而且 main 中的或者是别的渠道中的文件都不会再该渠道的包中出现，从而更加节省空间。</p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;打包的事，之前很少做，也了解的比较少，今天好好看了看，总结一下，以后要是用到了，或许可以少走些弯路。&lt;/p&gt;
    
    </summary>
    
      <category term="安卓" scheme="http://yoursite.com/categories/%E5%AE%89%E5%8D%93/"/>
    
    
      <category term="Android" scheme="http://yoursite.com/tags/Android/"/>
    
  </entry>
  
  <entry>
    <title>百妖谱</title>
    <link href="http://yoursite.com/2017/06/23/%E7%99%BE%E5%A6%96%E8%B0%B1/"/>
    <id>http://yoursite.com/2017/06/23/百妖谱/</id>
    <published>2017-06-23T13:17:14.000Z</published>
    <updated>2017-06-25T07:10:25.000Z</updated>
    
    <content type="html"><![CDATA[<center><br><br><img src="http://on9hzfn6s.bkt.clouddn.com/s29259213 2.jpg" alt="s29259213 2"><br><br></center>

<a id="more"></a>
<p>上周六晚和舍友去武林广场吃鱼，在五楼恰巧看到了一家非常不错的书店，整体风格很棒。</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/image.jpeg" alt="image"></p>
<p>名字叫西西弗。我印象中，西方神话中有个经常推石头的人也叫西西什么的。我试着查了下。</p>
<p>果然，百科中这么说的，“<strong>西西弗书店</strong>” 的名称源于《希腊神话》中的西西弗斯。</p>
<p>这个西西弗斯是怎么样一个人呢？</p>
<p>资料中是这么说的，他绑架了死神，让世间没有了死亡，触犯了众神。为了惩罚他，便要求他把一块巨石推上山顶，而由于那巨石太重了，到了山顶就又滚下山去，于是他就永无止境地做这件事，生命也就这样慢慢消耗殆尽。</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/4238c4464eb1af761fcaa9b554e12495.jpg" alt="4238c4464eb1af761fcaa9b554e12495"></p>
<p>据我了解，他聪明盖世，戏耍死神，调皮是一方面。往大了说，他还代表了人类对自身绝望命运的不屈。</p>
<p>我不经想要当一回出卷老师，多揣测一下这书店为什么要以这个人物来命名了。这是想要说明我们可以通过书籍去反抗去进步，让知识改变命运吗，即使可能每天的工作上去就如同滚上山的石头一般，看上去没有用，甚至第二天或者晚上就会又滚下来，但是我们还是要坚持，日复一日。读书即使如此。</p>
<p>写到这，我又想到了一个人，准确说是一个名字，哈利波特系列中的女主，赫敏。</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/heming.jpeg" alt="heming"></p>
<p>她的名字由来也是有点意思的。（那本书中的人物名称都很有故事）</p>
<p>来源于希腊古神<strong>赫尔墨斯</strong>，也是一个大智慧者，传说他发明了数字和字母，不过有点点狡猾，还会点膜法，和赫敏真是太贴切了。</p>
<p>说回到主角<strong>百妖谱</strong>身上来。距离我上次在书店买书(不算上路边打折书摊和二手书店的话)，说实话，我已经没有任何的记忆了。原因很简单，贵。</p>
<p>质量一样，还贵，虽然实体书店经营不易，可是我更不容易啊。而且说实话，这种类型的书，若是没有外人推荐，我是会直接略过的。</p>
<p>正好前几天女朋友在看，还以很快的速度看完了，要知道那人其实不是很爱看书的。主动去找这书看，我想我是不会去的，毕竟那不是我的菜，不过送上门来，额，看了看价格，还是，勉为其难的拿下了。30 多元钱呐，一分都不便宜。就当支持下实体书店了。</p>
<p>真的，不得不说！！我讨厌腰封，又叫书腰，就是这个玩意：</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/shuyao.jpeg" alt="shuyao"></p>
<p>越来越流行，好像没有书腰的书就是二流书似得。以前是新人出书的时候，出版社会添加一些有的没有的算不算奖项的奖项或者推荐语之类的噱头上去吸引读者的，生怕别人不知道这书有多好看。现在是但凡新出的书，再版的书，不论新人旧人，无名人还是大名人，都来这么一套。</p>
<p>我讨厌书腰的一个原因是这东西太碍事了，看书的时候套着多不方便啊。但是直接丢了又会觉得我买的书有点不完整了，而且有些书腰设计的其实并不赖，但是这玩意真的影响平常的阅读，要为这种屁大点事情纠结费心，即使一小会儿，我都非常讨厌。</p>
<p>说回到书的内容。</p>
<p><strong>百妖谱</strong>，上面记载了许许多多的妖怪的故事。朋友给我介绍的时候就说过，有点像是夏目友人帐，这个动画片最新的一季好像又开始更新，不过第一季我就看过两集，就没看了。说实话，治愈系的风格，不是我的菜。（那什么，我可是要尝百草，舔苦胆的人，不要治愈，要现实）</p>
<p>我不知道作者目前是否已经写了一百个妖怪了，手上的这本上面一共记载了十个妖怪。书本到手的第二天，也就是周日，和一个同事去图书馆待了小半天，一开始没个像样的地方坐，做在地板上，依靠着窗户，有点犯困，买了杯青柠饮料，发现有点涩，没有第一次的好喝，慢慢悠悠的看了五个故事。</p>
<p>之后每个晚上睡前一个，刚好一周，都看完了，挑两个印象深的说说。</p>
<p>作者说的这些妖怪，大都是各种书籍中有介绍的，根据它们的特征，给它们编了一些可能是恰到好处的所谓治愈系故事。</p>
<p>先说点大致的背景，这是一个六道轮回看得见的世界，设定中妖魔鬼怪，神仙凡人拥有各自的管理者。其中妖的管理者都住在于一个叫桃都的地方，女主桃夭是桃都的一个医生，目前看来，医术高超，战斗力爆表。</p>
<p>女主外出给妖怪看病的过程中，遇到了各种各样的有故事的妖怪。</p>
<p>灰狐就不说了，萌萌的<em>滚滚</em>，就是为了放在身边当小可爱用的。</p>
<p>说两个妖怪的故事，腾根和应声。</p>
<p><strong>腾根</strong>，传说中“追恶凶”的十二位神明之一，非俗世之兽，善嗅，能辨仙魔真身，人间善恶自不在话下。</p>
<center><br><br><img src="http://on9hzfn6s.bkt.clouddn.com/20300544108051148776635074160_s 2.jpg" alt="20300544108051148776635074160_s 2"><br><br></center>

<p>这是一对表面上很恩爱的普通老夫妻，但实际上老奶奶却是老公公（腾根）所要捉拿的要犯。她是蛊虫世家的唯一后嗣，她将家族中唯一存活的蛊种在了他身上，为的是他能一生一世和她在一起，俗不知，他是世间最善辨最懂蛊的人，早已看透这一切，却心甘情愿被她种下这情蛊，只为能与他厮守终身。</p>
<p>既然能遇见个让你不想离开的人，就留下吧。</p>
<p>爱情许多时候就是明知不可行而行之，再或许，看她犯傻也是一件开心快乐的事。</p>
<p>取次花丛懒回顾，半缘修道半缘君。</p>
<p>只能是羡慕他们了。</p>
<p><strong>应声</strong>，以应声虫为原型的妖怪。（应该是）</p>
<p>应声虫，百科中这样解释，被认为是引起这种怪病的寄生虫，栖息在人的肚子里。宿主每当发出声音时，肚子里就会有很小的声音效仿，且会越来越大声。</p>
<p>在成语中是用来比喻自己胸无主张，随声附和他人的人。作者这里将它极度化了。</p>
<p>故事比较简单，一个女孩，有点胖，有点自卑，别人说她是猪，她很难过，一直待在家里不出去，加上肚子中有应声虫，慢慢人脚变成了猪脚，甚至长出了猪尾巴。差不多就是这个意思。</p>
<p>这篇写的一般般，却让我思考了许多。</p>
<p>越是弱小的人，越是不自信，越是在乎别人的看法。</p>
<p>自卑来源于他人异样的眼光，更是来源于自身的低微。</p>
<p>他人的鼓励或是批评，或是嘲讽，各式各样，弱小的人往往经常将它们挂在心中，特别是你在乎的人对你的看法，如何学会正确的过滤它们，真是要时间不断磨砺自我心智。还有就是让自己变得更强大。</p>
<p>是的，不要将自己低微到尘埃中，<strong>他强任他强,打野来帮忙,他皮任他皮,当他是瓜皮。</strong></p>
<p>或许，可能，唔，我的身体里也寄生了不少的应声虫，它们在我中学时期大量繁殖，却又在大学毕业后不久大量消亡。</p>
<p>势必，我要将它们赶尽杀绝。</p>
<p>做自己。</p>
]]></content>
    
    <summary type="html">
    
      &lt;center&gt;&lt;br&gt;&lt;br&gt;&lt;img src=&quot;http://on9hzfn6s.bkt.clouddn.com/s29259213 2.jpg&quot; alt=&quot;s29259213 2&quot;&gt;&lt;br&gt;&lt;br&gt;&lt;/center&gt;
    
    </summary>
    
      <category term="阅读" scheme="http://yoursite.com/categories/%E9%98%85%E8%AF%BB/"/>
    
    
      <category term="读书笔记" scheme="http://yoursite.com/tags/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/"/>
    
  </entry>
  
  <entry>
    <title>当我跑步时我在谈些什么</title>
    <link href="http://yoursite.com/2017/06/21/%E5%BD%93%E6%88%91%E8%B7%91%E6%AD%A5%E6%97%B6%E6%88%91%E5%9C%A8%E8%B0%88%E4%BA%9B%E4%BB%80%E4%B9%88/"/>
    <id>http://yoursite.com/2017/06/21/当我跑步时我在谈些什么/</id>
    <published>2017-06-21T15:41:52.000Z</published>
    <updated>2017-06-25T07:11:03.000Z</updated>
    
    <content type="html"><![CDATA[<center><br><br><img src="http://on9hzfn6s.bkt.clouddn.com/s28316091.jpg" alt="s28316091"><br><br></center>

<a id="more"></a>
<p>这本书是前两周在 Amazon 买书的时候，系统推荐给我的，不得不说，推荐的敲到好处，我也一并买下了。</p>
<p>之前看村上春树的书总是耐不下心来，像是<strong>《海边的卡夫卡》</strong>，<strong>《挪威的森林》</strong>，只能是大概看懂个大概的故事情节，以及一些表面的我觉得可能是如此的作者想要提现出来的人生感悟，深入的话就不能够了。</p>
<p>所以大学时期我更喜欢看东野圭吾的书，故事性强，可读性高，人性啊立意方面的东西虽说也是不差，但是相比村上春树的文风，就像前几年我在朋友圈说过的，一个是流行，一个是古典。</p>
<p>趣味性方面，东野圭吾的书读起来更有意思一些，比较白话，不费劲，也没有什么深层次的东西（目前我的看法），而且篇幅相对短一点。</p>
<p>自从被安利看了第一本<strong>《白夜行》</strong>之后便一发不可收拾，图书馆他的作品一连看了十多本，其中最喜欢<strong>《恶意》</strong>。</p>
<p>之后就开始读村上春树作品。起初读他的书，总是将其当成是一个成就一样的东西，好像看完一本就能点亮一个图标或者是完成人生目标之类的东西，又好像为了能让自己看上去似乎饱读经典，能更好的装逼，实则背道而驰了。</p>
<p><strong>《当我跑步上我在谈些什么》</strong>这书名是根据被称为是”美国的契诃夫“作家 <em><a href="http://baike.baidu.com/link?url=8hoZddtnFQOYB_04pZqMe104G26Y8qhyJDa0UKnRop-dV49xWHMxmwxGkgDAYVvLkOEWSjAU6h9lo4UtQ9FzQ6PPlfS2ZaE8qWp-rtcEcFkLSqLia5Oz6BP1RAQSe9ON-qT2zXlD54heKEtAkOPjXa" target="_blank" rel="noopener">雷蒙德·卡佛</a></em> 的短篇小说 <a href="https://book.douban.com/subject/1421520/" target="_blank" rel="noopener">What We Talk About When We Talk About Love</a> 改编而来。记录了一些作者村上春树在跑步时记录的一些想法。由约十个短篇组成，我在午休期间陆陆续续的看完了，说两点让我印象深刻的观点或是想法吧。</p>
<p>说实话，我是才知道，原来村上春树是一名跑者，而且还不弱。连续跑了三十多年，风雨无阻，真是不容易。</p>
<p>这让我想到了另一个牛逼的人物，<a href="http://baike.baidu.com/link?url=AF4RrpJ6Mmria4-obQt34WPtgRmzD5j9yoq2uPEoWngIIY3ELjHEu6wIgrh-dGXDc0twSIFWcfmZ5LkuW-DPC9l9_RpRgacqu51BC1jJ6Y6AKSAthNYLWFUcQYaQ83dNDZ7XkhTTVZwVtL1h0LH9lQg-pFZ9upBHvXUnODP66WFNx2T58IDxJAU5OPbIcyv6TVpv-OJ-OJkqL__1JBvccUiUWAQ6tMx0Qs_mmKIQwJW" target="_blank" rel="noopener">图灵</a>，计算机天才（真正的计算机之父！），二战大功臣（让战争提前几年结束！）。</p>
<center><br><br><img src="http://on9hzfn6s.bkt.clouddn.com/5882b2b7d0a20cf4e32950c372094b36acaf9975 2.jpg" alt="5882b2b7d0a20cf4e32950c372094b36acaf9975 2"><br><br></center>

<p>他也是一名跑步爱好者，而且强的一匹，业余的成绩与当时的奥运会马拉松冠军成绩相差无几。当问他为什么要跑步时，他说，“我做的工作压力太大，我能把它从内心去除的唯一方式，就是使劲地跑。”可以看<a href="https://baijia.baidu.com/s?old_id=46660" target="_blank" rel="noopener">这篇文章</a>。</p>
<p>村上春树在跑超级马拉松的时候说，当他迈过四十二公里时，整个人，都发生了微妙的变化，仿佛进入了一个陌生的领域，越往后，越觉得自己不是人了，是一台机器，而且在不断的自我催眠，因为只有机器才能如此一直无止境的奔跑下去。我想那个过程中的肉体应该已经麻木到失去了知觉，思想却同时进入了一个非常纯粹的领域。（没有真正体会过的我只能暗自羡慕了）</p>
<center><br><br><img src="http://on9hzfn6s.bkt.clouddn.com/cscs.jpeg" alt="cscs"><br><br></center>

<p>村上春树说他在跑步的时候遇到一个问题，我想，这个问题不当只是出现在跑步中，几乎在坚持做所有的事情时都会出现。</p>
<p>总有那么一个时候，你突然想放松了，不想跑了。一开始作者觉得，可能是他跑的还不够久，或者是觉得自己的心态还没调整到位够好，若是专业的选手应该不会有这种问题出现，但是当他去询问一个专业的马拉松运动员时，被问者仿佛用看弱智的眼神看着他，回答道，怎么可能？我也有不想跑的时候啊。</p>
<p>看到这个回答的我和作者当时的感受十分相似，好像是突然轻松了一点。是啊，大家都是人啊，总是有那么一个时候想休息一下，放松一下不是吗。</p>
<p>可，坚持做一件事情的理由许多情况只有一个理由，不做这件事情的理由却是多到数不清。是了，我坚持做这一件事情，理由就一个，为了自己能更加健康一点，但是每天工作都那么累了，而且有可能，今天加班，今天脚疼，今天头晕，今天家里来客人了，今天朋友请喝酒，今天配、陪女朋友出去玩，今天下暴雨呢，今天生日啊，今天健身房没开，今天要看总决赛呢，今天搬家，今天···</p>
<p>我从几周前开始坚持每晚锻炼至少半个小时，到今天，20来天了。那种<em>今天有点特殊，就好好休息一下吧</em>的念头每次锻炼前都在缠着我，庆幸的是，除了昨晚看电影到凌晨，别的时候我都坚持下来了，就算这个月都是加班到我回家都十点了。</p>
<p>看电影到凌晨回家，这也算是不做这件事情的理由了，不是吗？而且我做的还只是室内的运动，若是室外运动或者打断的理由更多。</p>
<p>我有点能明白那种不想去做一件事情而给自己找理由的心理活动。当可以选择的时候，人总是想着做能让自己更加轻松点的事情，感觉又是说到了之前在人是否要有上进心的问题上，自律的问题或者就是所有事情的来源本质吧。</p>
<p>看这本书的时候，我总是有种跃跃欲试的冲动。可惜我要加班没那么多时间去跑步啊，可惜工作都那么累了哪还有什么精力去跑步呢，可惜家附近都是车道什么的找不到好的跑步地点。还是如此，那么多不做这件事情的理由在阻碍着我，而去做这件事的理由就只有，我想去跑。</p>
<p>经常运动的好处就是，作者几十年来从不生病。真是让人羡慕。</p>
<p>他还提到一个比较好玩的想法，他说有些人的体质是天生容易变胖，就比如作者自己，有些人则是天生不容易长胖，就比如作者的妻子，所以一开始作者比较羡慕他老婆，说是造物主的不公。可后来又觉得，从另一个角度来看，自己这样的体质或许是幸运的，因为担心容易变胖所以会适当的去锻炼，而像他妻子体质的人反而会因为怎么吃都没关系疏忽了锻炼。</p>
<p>当然，若是他老婆那种体质的人又有需要时刻锻炼自己的心态，那就非常了不得了。（看到这我，暗暗表扬了下自己，唔，不能骄傲）</p>
<p>最后，我发现看作者的随笔散文之类的玩意更容易了解作者本身，好像我说的是废话。其实若是厉害点的读者，就算看作者写的小说也能够与作者对话，了解作者吧。可惜我还不能够，看小说的时候，更多只能看到主人公的内心想法，而看不出作者的内心想法，特别是老道点的作者，更是捉摸不透。而看随笔就非常直接了，因为主人公就是作者，看起来会让你觉得很亲切，内容方面也是贴近生活，不用去理解虚构小说中的背景时代什么的，太费劲。还有就是像我这样时间都是碎片化的，没什么时间能够投入到一部长篇小说中，这种短短的一篇篇的随笔就是很不错的选择了，收获还不小呢。</p>
]]></content>
    
    <summary type="html">
    
      &lt;center&gt;&lt;br&gt;&lt;br&gt;&lt;img src=&quot;http://on9hzfn6s.bkt.clouddn.com/s28316091.jpg&quot; alt=&quot;s28316091&quot;&gt;&lt;br&gt;&lt;br&gt;&lt;/center&gt;
    
    </summary>
    
      <category term="阅读" scheme="http://yoursite.com/categories/%E9%98%85%E8%AF%BB/"/>
    
    
      <category term="读书笔记" scheme="http://yoursite.com/tags/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/"/>
    
  </entry>
  
  <entry>
    <title>漫长的告别</title>
    <link href="http://yoursite.com/2017/06/18/%E6%BC%AB%E9%95%BF%E7%9A%84%E5%91%8A%E5%88%AB/"/>
    <id>http://yoursite.com/2017/06/18/漫长的告别/</id>
    <published>2017-06-18T12:52:27.000Z</published>
    <updated>2017-07-02T09:20:19.000Z</updated>
    
    <content type="html"><![CDATA[<center><br><br><img src="http://on9hzfn6s.bkt.clouddn.com/s26538475.jpg" alt="s26538475"><br><br></center>

<a id="more"></a>
<p>这本书算是近期花费最多时间和精力看的熟了，相对来说也是篇幅比较长的。</p>
<p>书是在图书馆凭眼缘找到的，作者和书名在之前可能是略有耳闻，不过不是很清楚，从书架上去下发现村上春树为它写了2万多字的长序，而且还负责将其翻译成了日文版。从序中可以看出他对这本书的称赞和推荐。</p>
<p>一开始我只当成是普通的可能是言情伤感类的小说来看，没想到是一本侦探小说，那更是符合我口味了。</p>
<p>唔，不过看着看着我发觉它和一般的侦探小说可能是有许多不同的地方，将更多的笔墨花在人物性格的刻画上面，对于真正的故事情节，并没有想象中的那么悬疑或者说是有什么地方令人大吃一惊的。（恩？我好肤浅啊。）</p>
<p>许多人说，作者钱德勒那时候写文章已经到了随心所欲，能将所想全都写出来，我想，写作最高的境界无非就是如此了。</p>
<p>可惜，这书，没能够静下心来看，晚上睡前翻翻，虽说是整本都看完了，但是期间更多是觉得有些冗长，没有和作者产生共鸣，也没有体会到别人说的主角马洛那深深的孤独，看完的瞬间最大感受居然是–终于看完了啊，还为此松了一口气。</p>
<p>另外，看书的过程中，我怎么觉得，主角像是一个基佬。为了一个陌生的男的，赴汤蹈火似得，为了自己的职业操守？在被严刑拷打的过程中，装逼常伴他身，很酷。</p>
<p>那种我行我素，无所畏惧的性格但是倒还不错。</p>
<p>听说这本书是作者在照顾病中的妻子时写完的，所以书中也是弥漫着一丝的伤感和离别。</p>
<p>总之，不是很推荐，啊哈哈。</p>
<p>说一声再见，就是死去一点。</p>
]]></content>
    
    <summary type="html">
    
      &lt;center&gt;&lt;br&gt;&lt;br&gt;&lt;img src=&quot;http://on9hzfn6s.bkt.clouddn.com/s26538475.jpg&quot; alt=&quot;s26538475&quot;&gt;&lt;br&gt;&lt;br&gt;&lt;/center&gt;
    
    </summary>
    
      <category term="阅读" scheme="http://yoursite.com/categories/%E9%98%85%E8%AF%BB/"/>
    
    
      <category term="读书笔记" scheme="http://yoursite.com/tags/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/"/>
    
  </entry>
  
  <entry>
    <title>最近</title>
    <link href="http://yoursite.com/2017/06/18/%E6%9C%80%E8%BF%91/"/>
    <id>http://yoursite.com/2017/06/18/最近/</id>
    <published>2017-06-18T11:05:03.000Z</published>
    <updated>2017-06-18T12:46:08.000Z</updated>
    
    <content type="html"><![CDATA[<p>真是要命。</p>
<p><strong>生活</strong>，被挤压的，只剩 <strong>活</strong> 了。</p>
<p>希望自己能够充分利用时间，目标不论大小，努力完成。</p>
<p>看书慢一点。</p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;真是要命。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;生活&lt;/strong&gt;，被挤压的，只剩 &lt;strong&gt;活&lt;/strong&gt; 了。&lt;/p&gt;
&lt;p&gt;希望自己能够充分利用时间，目标不论大小，努力完成。&lt;/p&gt;
&lt;p&gt;看书慢一点。&lt;/p&gt;

    
    </summary>
    
      <category term="随笔" scheme="http://yoursite.com/categories/%E9%9A%8F%E7%AC%94/"/>
    
    
      <category term="随笔" scheme="http://yoursite.com/tags/%E9%9A%8F%E7%AC%94/"/>
    
  </entry>
  
  <entry>
    <title>2048 for Python</title>
    <link href="http://yoursite.com/2017/06/13/2048/"/>
    <id>http://yoursite.com/2017/06/13/2048/</id>
    <published>2017-06-13T03:20:19.000Z</published>
    <updated>2017-06-18T12:44:36.000Z</updated>
    
    <content type="html"><![CDATA[<p>真是办公室偷闲小能手，嘿嘿。（下图右上角就是游戏运行界面）</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/python2048.gif" alt="python2048"></p>
<a id="more"></a>
<p>一闪一闪的，是因为我使用全局热键唤出或者隐匿 iTerm2 ，这个软件的一些技巧和配色我之前有做过较为<a href="http://zhanglf.xyz/2017/04/14/Mac%E4%BD%BF%E7%94%A8%E6%8A%80%E5%B7%A7/#终端配色" target="_blank" rel="noopener">详细的说明</a>。</p>
<h4 id="输入"><a href="#输入" class="headerlink" title="输入"></a>输入</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">letter_codes = [ord(ch) <span class="keyword">for</span> ch <span class="keyword">in</span> <span class="string">'WASDRQwasdrq'</span>]</span><br><span class="line">actions = [<span class="string">'Up'</span>, <span class="string">'Left'</span>, <span class="string">'Down'</span>, <span class="string">'Right'</span>, <span class="string">'Restart'</span>, <span class="string">'Exit'</span>]</span><br><span class="line">actions_dict = dict(zip(letter_codes, actions * <span class="number">2</span>))</span><br></pre></td></tr></table></figure>
<p>考虑到大小写，所以用数组 <em>WASDRQwasdrq</em> 和 <em>act x 2</em> 中的操作一一对应。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">get_user_action</span><span class="params">(keyboard)</span>:</span></span><br><span class="line">    char = <span class="string">"N"</span></span><br><span class="line">    <span class="keyword">while</span> char <span class="keyword">not</span> <span class="keyword">in</span> actions_dict:</span><br><span class="line">        char = keyboard.getch()</span><br><span class="line">    <span class="keyword">return</span> actions_dict[char]</span><br></pre></td></tr></table></figure>
<p>除了 <em>N</em> 和 <em>actions_dict</em> 之外的字符输入都是无效的，阻塞循环等待。</p>
<h4 id="矩阵的操作"><a href="#矩阵的操作" class="headerlink" title="矩阵的操作"></a>矩阵的操作</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">transpose</span><span class="params">(field)</span>:</span></span><br><span class="line">    <span class="keyword">return</span> [list(row) <span class="keyword">for</span> row <span class="keyword">in</span> zip(*field)]</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">invert</span><span class="params">(field)</span>:</span></span><br><span class="line">    <span class="keyword">return</span> [row[::<span class="number">-1</span>] <span class="keyword">for</span> row <span class="keyword">in</span> field]</span><br></pre></td></tr></table></figure>
<p>分别是用来转置和逆转矩阵用的。（上下操作矩阵用转置，左右才做矩阵用逆转）</p>
<h4 id="棋盘初始化"><a href="#棋盘初始化" class="headerlink" title="棋盘初始化"></a>棋盘初始化</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, height=<span class="number">4</span>, width=<span class="number">4</span>, win=<span class="number">2048</span>)</span>:</span></span><br><span class="line">        self.height = height</span><br><span class="line">        self.width = width</span><br><span class="line">        self.win_value = win</span><br><span class="line">        self.score = <span class="number">0</span></span><br><span class="line">        self.highscore = <span class="number">0</span></span><br><span class="line">        self.reset()</span><br></pre></td></tr></table></figure>
<h4 id="绘制"><a href="#绘制" class="headerlink" title="绘制"></a>绘制</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">draw</span><span class="params">(self, screen)</span>:</span></span><br><span class="line">        help_string1 = <span class="string">'(W)Up (S)Down (A)Left (D)Right'</span></span><br><span class="line">        help_string2 = <span class="string">'     (R)Restart (Q)Exit'</span></span><br><span class="line">        gameover_string = <span class="string">'           GAME OVER'</span></span><br><span class="line">        win_string = <span class="string">'          YOU WIN!'</span></span><br><span class="line">        <span class="function"><span class="keyword">def</span> <span class="title">cast</span><span class="params">(string)</span>:</span></span><br><span class="line">            screen.addstr(string + <span class="string">'\n'</span>)</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">def</span> <span class="title">draw_hor_separator</span><span class="params">()</span>:</span></span><br><span class="line">            line = <span class="string">'+'</span> + (<span class="string">'+------'</span> * self.width + <span class="string">'+'</span>)[<span class="number">1</span>:]</span><br><span class="line">            separator = defaultdict(<span class="keyword">lambda</span>: line)</span><br><span class="line">            <span class="keyword">if</span> <span class="keyword">not</span> hasattr(draw_hor_separator, <span class="string">"counter"</span>):</span><br><span class="line">                draw_hor_separator.counter = <span class="number">0</span></span><br><span class="line">            cast(separator[draw_hor_separator.counter])</span><br><span class="line">            draw_hor_separator.counter += <span class="number">1</span></span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">def</span> <span class="title">draw_row</span><span class="params">(row)</span>:</span></span><br><span class="line">            cast(<span class="string">''</span>.join(<span class="string">'|&#123;: ^5&#125; '</span>.format(num) <span class="keyword">if</span> num &gt; <span class="number">0</span> <span class="keyword">else</span> <span class="string">'|      '</span> <span class="keyword">for</span> num <span class="keyword">in</span> row) + <span class="string">'|'</span>)</span><br><span class="line"></span><br><span class="line">        screen.clear()</span><br><span class="line">        cast(<span class="string">'SCORE: '</span> + str(self.score))</span><br><span class="line">        <span class="keyword">if</span> <span class="number">0</span> != self.highscore:</span><br><span class="line">            cast(<span class="string">'HIGHSCORE: '</span> + str(self.highscore))</span><br><span class="line">        <span class="keyword">for</span> row <span class="keyword">in</span> self.field:</span><br><span class="line">            draw_hor_separator()</span><br><span class="line">            draw_row(row)</span><br><span class="line">        draw_hor_separator()</span><br><span class="line">        <span class="keyword">if</span> self.is_win():</span><br><span class="line">            cast(win_string)</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            <span class="keyword">if</span> self.is_gameover():</span><br><span class="line">                cast(gameover_string)</span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                cast(help_string1)</span><br><span class="line">        cast(help_string2)</span><br></pre></td></tr></table></figure>
<p>绘制水平和垂直方向的线条，以及最高分的显示。</p>
<h4 id="棋盘操作"><a href="#棋盘操作" class="headerlink" title="棋盘操作"></a>棋盘操作</h4><h5 id="重置"><a href="#重置" class="headerlink" title="重置"></a>重置</h5><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">reset</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">if</span> self.score &gt; self.highscore:</span><br><span class="line">            self.highscore = self.score</span><br><span class="line">        self.score = <span class="number">0</span></span><br><span class="line">        self.field = [[<span class="number">0</span> <span class="keyword">for</span> i <span class="keyword">in</span> range(self.width)] <span class="keyword">for</span> j <span class="keyword">in</span> range(self.height)]</span><br><span class="line">        self.spawn()</span><br><span class="line">        self.spawn()</span><br></pre></td></tr></table></figure>
<h5 id="随机添加"><a href="#随机添加" class="headerlink" title="随机添加"></a>随机添加</h5><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">spawn</span><span class="params">(self)</span>:</span></span><br><span class="line">    new_element = <span class="number">4</span> <span class="keyword">if</span> randrange(<span class="number">100</span>) &gt; <span class="number">89</span> <span class="keyword">else</span> <span class="number">2</span></span><br><span class="line">    (i,j) = choice([(i,j) <span class="keyword">for</span> i <span class="keyword">in</span> range(self.width) <span class="keyword">for</span> j <span class="keyword">in</span> range(self.height) <span class="keyword">if</span> self.field[i][j] == <span class="number">0</span>])</span><br><span class="line">    self.field[i][j] = new_element</span><br></pre></td></tr></table></figure>
<p><em>spawn</em> 是卵，繁殖的意思，随机添加 2 或者 4 。</p>
<h5 id="移动"><a href="#移动" class="headerlink" title="移动"></a>移动</h5><p>虽然有四个方向的操作，但是通过对矩阵的转置和逆转，我们只要对一个方向进行处理，别的方向上操作，转化过来就行了。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">move</span><span class="params">(self, direction)</span>:</span></span><br><span class="line">        <span class="function"><span class="keyword">def</span> <span class="title">move_row_left</span><span class="params">(row)</span>:</span></span><br><span class="line">            <span class="function"><span class="keyword">def</span> <span class="title">tighten</span><span class="params">(row)</span>:</span> <span class="comment"># squeese non-zero elements together</span></span><br><span class="line">                new_row = [i <span class="keyword">for</span> i <span class="keyword">in</span> row <span class="keyword">if</span> i != <span class="number">0</span>]</span><br><span class="line">                new_row += [<span class="number">0</span> <span class="keyword">for</span> i <span class="keyword">in</span> range(len(row) - len(new_row))]</span><br><span class="line">                <span class="keyword">return</span> new_row</span><br><span class="line"></span><br><span class="line">            <span class="function"><span class="keyword">def</span> <span class="title">merge</span><span class="params">(row)</span>:</span></span><br><span class="line">                pair = <span class="keyword">False</span></span><br><span class="line">                new_row = []</span><br><span class="line">                <span class="keyword">for</span> i <span class="keyword">in</span> range(len(row)):</span><br><span class="line">                    <span class="keyword">if</span> pair:</span><br><span class="line">                        new_row.append(<span class="number">2</span> * row[i])</span><br><span class="line">                        self.score += <span class="number">2</span> * row[i]</span><br><span class="line">                        pair = <span class="keyword">False</span></span><br><span class="line">                    <span class="keyword">else</span>:</span><br><span class="line">                        <span class="keyword">if</span> i + <span class="number">1</span> &lt; len(row) <span class="keyword">and</span> row[i] == row[i + <span class="number">1</span>]:</span><br><span class="line">                            pair = <span class="keyword">True</span></span><br><span class="line">                            new_row.append(<span class="number">0</span>)</span><br><span class="line">                        <span class="keyword">else</span>:</span><br><span class="line">                            new_row.append(row[i])</span><br><span class="line">                <span class="keyword">assert</span> len(new_row) == len(row)</span><br><span class="line">                <span class="keyword">return</span> new_row</span><br><span class="line">            <span class="keyword">return</span> tighten(merge(tighten(row)))</span><br><span class="line"></span><br><span class="line">        moves = &#123;&#125;</span><br><span class="line">        moves[<span class="string">'Left'</span>]  = <span class="keyword">lambda</span> field:                              \</span><br><span class="line">                [move_row_left(row) <span class="keyword">for</span> row <span class="keyword">in</span> field]</span><br><span class="line">        moves[<span class="string">'Right'</span>] = <span class="keyword">lambda</span> field:                              \</span><br><span class="line">                invert(moves[<span class="string">'Left'</span>](invert(field)))</span><br><span class="line">        moves[<span class="string">'Up'</span>]    = <span class="keyword">lambda</span> field:                              \</span><br><span class="line">                transpose(moves[<span class="string">'Left'</span>](transpose(field)))</span><br><span class="line">        moves[<span class="string">'Down'</span>]  = <span class="keyword">lambda</span> field:                              \</span><br><span class="line">                transpose(moves[<span class="string">'Right'</span>](transpose(field)))</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> direction <span class="keyword">in</span> moves:</span><br><span class="line">            <span class="keyword">if</span> self.move_is_possible(direction):</span><br><span class="line">                self.field = moves[direction](self.field)</span><br><span class="line">                self.spawn()</span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">True</span></span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">False</span></span><br></pre></td></tr></table></figure>
<p>棋盘的合并都是先消除中间的空格再合并相邻的数字。<em>tighten</em> 是靠拢，<em>merge</em> 是合并。</p>
<h5 id="判断是否能移动"><a href="#判断是否能移动" class="headerlink" title="判断是否能移动"></a>判断是否能移动</h5><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">move_is_possible</span><span class="params">(self, direction)</span>:</span></span><br><span class="line">        <span class="function"><span class="keyword">def</span> <span class="title">row_is_left_movable</span><span class="params">(row)</span>:</span></span><br><span class="line">            <span class="function"><span class="keyword">def</span> <span class="title">change</span><span class="params">(i)</span>:</span> <span class="comment"># true if there'll be change in i-th tile</span></span><br><span class="line">                <span class="keyword">if</span> row[i] == <span class="number">0</span> <span class="keyword">and</span> row[i + <span class="number">1</span>] != <span class="number">0</span>: <span class="comment"># Move</span></span><br><span class="line">                    <span class="keyword">return</span> <span class="keyword">True</span></span><br><span class="line">                <span class="keyword">if</span> row[i] != <span class="number">0</span> <span class="keyword">and</span> row[i + <span class="number">1</span>] == row[i]: <span class="comment"># Merge</span></span><br><span class="line">                    <span class="keyword">return</span> <span class="keyword">True</span></span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">False</span></span><br><span class="line">            <span class="keyword">return</span> any(change(i) <span class="keyword">for</span> i <span class="keyword">in</span> range(len(row) - <span class="number">1</span>))</span><br><span class="line"></span><br><span class="line">        check = &#123;&#125;</span><br><span class="line">        check[<span class="string">'Left'</span>]  = <span class="keyword">lambda</span> field:                              \</span><br><span class="line">                any(row_is_left_movable(row) <span class="keyword">for</span> row <span class="keyword">in</span> field)</span><br><span class="line"></span><br><span class="line">        check[<span class="string">'Right'</span>] = <span class="keyword">lambda</span> field:                              \</span><br><span class="line">                 check[<span class="string">'Left'</span>](invert(field))</span><br><span class="line"></span><br><span class="line">        check[<span class="string">'Up'</span>]    = <span class="keyword">lambda</span> field:                              \</span><br><span class="line">                check[<span class="string">'Left'</span>](transpose(field))</span><br><span class="line"></span><br><span class="line">        check[<span class="string">'Down'</span>]  = <span class="keyword">lambda</span> field:                              \</span><br><span class="line">                check[<span class="string">'Right'</span>](transpose(field))</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> direction <span class="keyword">in</span> check:</span><br><span class="line">            <span class="keyword">return</span> check[direction](self.field)</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">False</span></span><br></pre></td></tr></table></figure>
<p>能移动就两种情况，一是有空格，一是有相邻位有相同的数字。</p>
<h4 id="状态"><a href="#状态" class="headerlink" title="状态"></a>状态</h4><p>先分析游戏都有哪些的状态，初始化（Init），游戏中（Game），获胜（Win），失败（GameOver），退出（Exit），如下图：</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/屏幕快照 2017-06-18 下午8.10.50.png" alt="屏幕快照 2017-06-18 下午8.10.50"></p>
<p>然后各个状态之间通过对应的方法联通。</p>
<p>补充主逻辑的代码：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">init</span><span class="params">()</span>:</span></span><br><span class="line">        <span class="comment">#重置游戏棋盘</span></span><br><span class="line">        game_field.reset()</span><br><span class="line">        <span class="keyword">return</span> <span class="string">'Game'</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">not_game</span><span class="params">(state)</span>:</span></span><br><span class="line">        <span class="comment">#画出 GameOver 或者 Win 的界面</span></span><br><span class="line">        game_field.draw(stdscr)</span><br><span class="line">        <span class="comment">#读取用户输入得到action，判断是重启游戏还是结束游戏</span></span><br><span class="line">        action = get_user_action(stdscr)</span><br><span class="line">        responses = defaultdict(<span class="keyword">lambda</span>: state) <span class="comment">#默认是当前状态，没有行为就会一直在当前界面循环</span></span><br><span class="line">        responses[<span class="string">'Restart'</span>], responses[<span class="string">'Exit'</span>] = <span class="string">'Init'</span>, <span class="string">'Exit'</span> <span class="comment">#对应不同的行为转换到不同的状态</span></span><br><span class="line">        <span class="keyword">return</span> responses[action]</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">game</span><span class="params">()</span>:</span></span><br><span class="line">        <span class="comment">#画出当前棋盘状态</span></span><br><span class="line">        game_field.draw(stdscr)</span><br><span class="line">        <span class="comment">#读取用户输入得到action</span></span><br><span class="line">        action = get_user_action(stdscr)</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> action == <span class="string">'Restart'</span>:</span><br><span class="line">            <span class="keyword">return</span> <span class="string">'Init'</span></span><br><span class="line">        <span class="keyword">if</span> action == <span class="string">'Exit'</span>:</span><br><span class="line">            <span class="keyword">return</span> <span class="string">'Exit'</span></span><br><span class="line">        <span class="keyword">if</span> game_field.move(action): <span class="comment"># move successful</span></span><br><span class="line">            <span class="keyword">if</span> game_field.is_win():</span><br><span class="line">                <span class="keyword">return</span> <span class="string">'Win'</span></span><br><span class="line">            <span class="keyword">if</span> game_field.is_gameover():</span><br><span class="line">                <span class="keyword">return</span> <span class="string">'Gameover'</span></span><br><span class="line">        <span class="keyword">return</span> <span class="string">'Game'</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    state_actions = &#123;</span><br><span class="line">            <span class="string">'Init'</span>: init,</span><br><span class="line">            <span class="string">'Win'</span>: <span class="keyword">lambda</span>: not_game(<span class="string">'Win'</span>),</span><br><span class="line">            <span class="string">'Gameover'</span>: <span class="keyword">lambda</span>: not_game(<span class="string">'Gameover'</span>),</span><br><span class="line">            <span class="string">'Game'</span>: game</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    curses.use_default_colors()</span><br><span class="line">    game_field = GameField(win=<span class="number">1024</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    state = <span class="string">'Init'</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">#状态机开始循环</span></span><br><span class="line">    <span class="keyword">while</span> state != <span class="string">'Exit'</span>:</span><br><span class="line">        state = state_actions[state]()</span><br></pre></td></tr></table></figure>
<p><a href="https://www.shiyanlou.com/courses/running" target="_blank" rel="noopener">代码来源</a></p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;真是办公室偷闲小能手，嘿嘿。（下图右上角就是游戏运行界面）&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://on9hzfn6s.bkt.clouddn.com/python2048.gif&quot; alt=&quot;python2048&quot;&gt;&lt;/p&gt;
    
    </summary>
    
      <category term="python" scheme="http://yoursite.com/categories/python/"/>
    
    
      <category term="Python" scheme="http://yoursite.com/tags/Python/"/>
    
  </entry>
  
  <entry>
    <title>长恨歌</title>
    <link href="http://yoursite.com/2017/06/05/%E9%95%BF%E6%81%A8%E6%AD%8C/"/>
    <id>http://yoursite.com/2017/06/05/长恨歌/</id>
    <published>2017-06-05T00:53:15.000Z</published>
    <updated>2017-07-02T13:16:57.000Z</updated>
    
    <content type="html"><![CDATA[<center><br><br><img src="http://on9hzfn6s.bkt.clouddn.com/s3018752.jpg" alt="s3018752"><br><br></center>

<a id="more"></a>
<p>被安利了两次之后还是看了，虽说我也不知道为什么就是不大喜欢民国时期的人情世故。</p>
<p>故事内容相对还是比较简单的。一个上海女学生，毕业没多久参加上海小姐竞选得了个第三名，之后莫名其妙的被大她近二十岁左右的主任（可能叫主人更准确点）包养了（这里说莫名其妙不是指被包养这个事情，因为这现象在当时的上海实在是很常见的，我觉得奇怪的是，这女的刚开始给我的感觉不像是个见两次面就同意被包养的，这个过渡于我来说略显突兀），之后不久新中国成立了，主任死了。女主回老家家待了一段时间，也不知是耐不住寂寞还是想上海了，又回来了，简单学了学，当了个护士，没事和邻居唠唠嗑，打打牌。</p>
<p>两男两女搓起了麻将，再之后也不知是太饥渴了，还是真的入了情，和其中一个男的搞上了，还把肚子弄大了，这男的没担当，靠不住，女主就睡了另一个男的，说这个孩子是他的。</p>
<p>去医院动手术的时候，女主突然决定把孩子生出来，就出了医院。</p>
<p>出来之后遇到了还是学生时候就喜欢她的备胎，这备胎也是喜当爹了，照顾她到生了孩子，真是感动中国十大人物，可惜她并不爱他。</p>
<p>再之后，没什么好说的，备胎在文革的时候，自杀了，女主倒是一直活得好好的，女儿也长大成人，还去了美国，故事就差不多结束了。</p>
<p>书本前几章都是废话，可能是我不懂欣赏，不过这获得了矛盾文学奖的作品，在豆瓣评价却不大理想。</p>
<blockquote>
<p>fr@nk  一星 2013-11-23<br>看完就想把书撕碎了扔到黄浦江里，人物干瘪，关系苍白，剧情狗血，完全是某位中年妇女对逝去年华的压抑却又要涌出的意淫，电影和电视剧的不成功就源自于此，一颗星给王老师靠吃红烧肉拗出来的文笔。</p>
</blockquote>
<p><br></p>
<blockquote>
<p>瞌睡的南瓜 一星 2012-06-17<br>不喜欢的女纸，不痛快的情感，缺底气的情节。看得很辛苦，读完很拧巴。简介说“一个女人四十年的情与爱，被一枝细腻而绚烂的笔写得哀婉动人”，后半句没一个形容词说对的。水木丁那篇评论说得好——王安忆是把女人看扁了。</p>
</blockquote>
<p>说实话，文笔细腻还是有的，写景和物的时候，例如前几章的弄堂，流言之类的。写的细腻到我一点都不想看，罗里吧嗦。虽然我知道写这种东西肯定是为了渲染什么悲情气氛，描写旧时上海怎么样的环境场景云云的为之后的情节做铺垫啊什么的狗屁。</p>
<p>对于书名为什么叫 <strong>长恨歌</strong> 我有点不解，有人说是</p>
<blockquote>
<p>大概是因为这个女人一生的爱情都很不成功吧。</p>
</blockquote>
<p><br></p>
<blockquote>
<p>在为一种已经远逝了的文化形态谱写一曲无尽的挽歌吧</p>
</blockquote>
<p>关于女主一生的爱情不成功，我想，这不都是咎由自取吗？选择被包养的时候就要做好那种准备。另外，我真是看不出来，她是否真的爱过谁。</p>
<p>爱主任？就算真的生活潦倒也十分不愿意将他送她的金条兑换了？未必，连人脸都完全记不得，可能留着那些东西只是为了怀念自己的青春之类的玩意。</p>
<p>爱备胎？好吧，这个所谓的程先生可以直接跳过，从头到尾就只是个备胎。</p>
<p>爱孩子她爹？这个倒是有一点点可能，不过这种男的，真是的太没用了。而且把孩子生下来更多的估计是为了她自己，和他是没太多关系的。</p>
<p>说到把孩子生下来倒是蛮佩服女主的，毕竟备胎跑了之后，她一个人含辛茹苦把孩子养大很不容易。</p>
<p>对于按个时代的女人的描写，我第一个会先到旗袍，提到旗袍一反应是汤唯和张曼玉：</p>
<center><br><br><img src="http://on9hzfn6s.bkt.clouddn.com/8F1CF5BA565490963F54BF94BB8DECAC.jpg" alt="8F1CF5BA565490963F54BF94BB8DECAC"><br><br><br><img src="http://on9hzfn6s.bkt.clouddn.com/abb.jpeg" alt="abb"><br><br></center>

<p>（哈哈，巧的是这两部剧的男主都是梁朝伟）</p>
<p>这书是昨天在图书馆看的，找了接近一个小时快崩溃的时候突然发现的，所以读起来更珍惜一点。</p>
<p>哦，其实一开始我一直以为女二是个同性恋来着，哈哈。说到这，必须说说，书中人物个性的塑造，我觉得不够好,很多角色的行为有点莫名。写到这我查了下作者本人，发现他是个女的。</p>
<p>啊哈哈，我说呢，一开始女主在校期间，和吴佩珍那段写的那么细腻，那么的小肚鸡肠女人心，我当时还佩服这作者还挺懂小女人的，那傲娇写的活灵活现。没想到啊没想到。</p>
<p>若是说，作者的目的就是写那么一个当时上海的较有经典特色女人的缩影，那我觉得她的写的还是很棒的，人物确实很市井。</p>
<p>若是… 那是真是把女人看扁了。</p>
]]></content>
    
    <summary type="html">
    
      &lt;center&gt;&lt;br&gt;&lt;br&gt;&lt;img src=&quot;http://on9hzfn6s.bkt.clouddn.com/s3018752.jpg&quot; alt=&quot;s3018752&quot;&gt;&lt;br&gt;&lt;br&gt;&lt;/center&gt;
    
    </summary>
    
      <category term="阅读" scheme="http://yoursite.com/categories/%E9%98%85%E8%AF%BB/"/>
    
    
      <category term="读书笔记" scheme="http://yoursite.com/tags/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/"/>
    
  </entry>
  
  <entry>
    <title>回首 5 月 展望 6 月</title>
    <link href="http://yoursite.com/2017/06/03/%E5%9B%9E%E9%A6%965%E6%9C%88%E5%B1%95%E6%9C%9B6%E6%9C%88/"/>
    <id>http://yoursite.com/2017/06/03/回首5月展望6月/</id>
    <published>2017-06-03T04:12:28.000Z</published>
    <updated>2017-06-03T08:20:25.000Z</updated>
    
    <content type="html"><![CDATA[<p>5 月结束了。</p>
<p>我翻了一下 5 月初，自己定的小目标，发现说了非常多的废话，真正确定的，明确的东西很少。</p>
<a id="more"></a>
<p>虽然如此，整个 5 月还做的比较不错的，像是说一个月至少看一本书，这个目标就是超超额完成了，不过像是每周看一个新的小知识点可能就是没有做到。</p>
<p>对于什么早睡之类的目标，这个整体完成度还是不错的，可能是有个别一两个晚上迟了点。</p>
<p>5 月去图书馆看了点书，也借了不少书。</p>
<p>5 月妈妈和姐姐来杭州了，我带她们去了杭州许多地方玩，以及吃了两顿不错的午饭。</p>
<p>5 月公司开了运动会，我拿了跳绳冠军。</p>
<p>5 月部门团建，大家一起去烧烤，玩的挺开心。</p>
<p>5 月买了一个单反，开始学习摄影。</p>
<p>5 月一个人去千岛湖露营过夜，走走停停，拍了不少的照片，还算潇洒。</p>
<p>5 月学了一门新语言 Python ，整理了一些关于它基础笔记，也用它搞了个小游戏。</p>
<p>…</p>
<p>忙碌的 5 月结束了，相信 6 月会过的更加充实，那么就定几个硬性的目标吧。</p>
<p>安卓，饭碗的东西含糊不得。至少每周看一个三方库源码，简单复杂都行。</p>
<p>Python ，至少每周做一个小实验，分析，并记录。</p>
<p>书，至少每周看一本，并写读后感。</p>
<p>电影，一个月至少不快进的看三部 8 分以上作品。</p>
<p>运动，每三天至少两次全身湿一次。</p>
<p>英语！重点项目！至少每两天打卡一次单词，一次口语，以及每天阅读必打卡。另外看完一部英文原著，暂定 <em>月亮与六便士</em> 。</p>
<blockquote>
<p><strong>不积跬步无以至千里</strong></p>
</blockquote>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;5 月结束了。&lt;/p&gt;
&lt;p&gt;我翻了一下 5 月初，自己定的小目标，发现说了非常多的废话，真正确定的，明确的东西很少。&lt;/p&gt;
    
    </summary>
    
      <category term="随笔" scheme="http://yoursite.com/categories/%E9%9A%8F%E7%AC%94/"/>
    
    
      <category term="小目标" scheme="http://yoursite.com/tags/%E5%B0%8F%E7%9B%AE%E6%A0%87/"/>
    
  </entry>
  
  <entry>
    <title>初恋</title>
    <link href="http://yoursite.com/2017/06/02/%E5%88%9D%E6%81%8B/"/>
    <id>http://yoursite.com/2017/06/02/初恋/</id>
    <published>2017-06-02T08:59:18.000Z</published>
    <updated>2017-06-18T11:56:06.000Z</updated>
    
    <content type="html"><![CDATA[<center><br><br><img src="http://on9hzfn6s.bkt.clouddn.com/s2941716.jpg" alt="s2941716"><br><br></center>

<p>好几篇小说合在一块的，重点说几篇印象深的。</p>
<a id="more"></a>
<p>(虽然时间是 6 月 2 日，但那只是创建时间，真正写的时间是 6 月 18 日，一把辛酸泪)</p>
<h4 id="阿霞"><a href="#阿霞" class="headerlink" title="阿霞"></a>阿霞</h4><p>名唤阿霞的女子，一开始我还以为她是个爱哥哥的奇怪女子（这里说的爱指的是爱情，不是情亲，否则我也不会觉得奇怪了），喜欢上了浪迹天涯的男主。</p>
<p>不过在最终表白的时候（女主要走了，约男主在阁楼相见），男主比较怂包的一脸懵逼，女主就跑了，终。</p>
<p>整体情节很简单，但是对于人物的刻画非常的细腻，女主的热情和害羞写的很生动。</p>
<p>但是，说实话，我不大是很喜欢看这种类型的小说，细节描写虽然很到位，可看多了会让我有种无趣的情绪，我想，这原因肯定是在我身上。</p>
<p>太急切了。我看书，更多的是追求情节的发展和构思的巧妙，迫切的想要看到结果，往往就会错过许多沿途的于我来说或许更加重要更加有意义的风景，没有办法更加投入的去思考和沉浸其中就不能深一层的与作者对话而从体会到更多他们想要传递的有价值的世界观。</p>
<h4 id="初恋"><a href="#初恋" class="headerlink" title="初恋"></a>初恋</h4><p>一些资料上是说这个故事的原型就是作者本人。哎，这故事有些地方我很难去舍身处理的理解，涉世尚浅啊，无奈。</p>
<p>小男主喜欢上了一个比较成熟的邻家女孩，她很美，很懂事，是许多小男生追求的对象。</p>
<p>小男主为其倾倒，茶不思，饭不想的。然而并没有什么软用，她喜欢的是小男主他爸爸。</p>
<p>知道真相的我，心中万只草泥马崩腾而过，这什么鬼。不过最后女主还是没和他们中的任何一个在一块就是了。</p>
<p>情节上也是比较简单，更多的笔墨都是花在描写场景和人物心理。</p>
<p>笔法真是好啊，如诗，如画，浪漫，细腻，真挚，深情。不过有点而过于古典了，以至于我这个现代人许多地方很难带入其中，估计是我境界不够。</p>
<p>整体还是比较喜欢的。</p>
<h4 id="春潮"><a href="#春潮" class="headerlink" title="春潮"></a>春潮</h4><p>书名是 <strong>初恋</strong> ， 貌似这篇 <strong>春潮</strong> 的篇幅更长些，给我的印象也是最深的，不知道是不是因为它是我最后一篇看的，哈哈。</p>
<p>又是一篇以作者部分自身经历为引子展开的小说（作者很棒棒啊，文中用了不少于四国语言，为翻译人员点赞）。</p>
<p>不得不说，屠格涅夫，笔下的女子性格都非常鲜明，而且而且，女主都好美啊。</p>
<p>全文最重要的一个地方居然省略了，就是男主和控制力超强女躲雨跑到林中小屋那段，一笔带过，以至于我非常难想象控制力超强女在小木屋中对男主做了什么事情，让他放弃了美美的女主，然后懊悔一生。</p>
<p>许多地方，人物之间的情感来的有些莫名奇怪，来也匆匆，去也匆匆的，有点摸不着头脑。</p>
<p>可仔细一想，现实生活中，不正是如此。感情的事情，比起潮水，更加不能够预测，潮起潮落，即使是沙滩上的那些或深或浅的痕迹都是转眼即逝。</p>
<hr>
<p>他的书，我想短时间我是不会主动看了，内容太少（指的是情节），但是看起来却一点都不轻松，古典的东西，啃起来费劲，而且往往收获和经历成正比（我想我还是太年轻），再则，我慢慢喜欢上看随笔和散文，能够随时拿起放下，这对于工作空忙不定的人来说，非常关键。</p>
]]></content>
    
    <summary type="html">
    
      &lt;center&gt;&lt;br&gt;&lt;br&gt;&lt;img src=&quot;http://on9hzfn6s.bkt.clouddn.com/s2941716.jpg&quot; alt=&quot;s2941716&quot;&gt;&lt;br&gt;&lt;br&gt;&lt;/center&gt;

&lt;p&gt;好几篇小说合在一块的，重点说几篇印象深的。&lt;/p&gt;
    
    </summary>
    
      <category term="阅读" scheme="http://yoursite.com/categories/%E9%98%85%E8%AF%BB/"/>
    
    
      <category term="读书笔记" scheme="http://yoursite.com/tags/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/"/>
    
  </entry>
  
  <entry>
    <title>我是猫</title>
    <link href="http://yoursite.com/2017/06/02/%E6%88%91%E6%98%AF%E7%8C%AB/"/>
    <id>http://yoursite.com/2017/06/02/我是猫/</id>
    <published>2017-06-02T08:14:21.000Z</published>
    <updated>2017-06-23T16:45:35.000Z</updated>
    
    <content type="html"><![CDATA[<center><br><br><img src="http://on9hzfn6s.bkt.clouddn.com/s6282827.jpg" alt="s6282827"><br><br></center>

<a id="more"></a>
<p>在公司书架上借的一本书，<a href="http://baike.baidu.com/link?url=6_ehaTo2GEFocsuBFe1lD0ajNZqbdM7VKeapyirGRtYc5FQ0htqJrPBjnbp9l_yK_kxfPfIjJiB6BDIgdxiEIszHzdzxpG-n4ar8pEhAS94T9RP_VhZYYFMDfAqAh5Kh" target="_blank" rel="noopener">作者</a>和<a href="http://baike.baidu.com/link?url=GwKFV6iW01esUWPMhxpgjHeiEcurRPmrUstbqyNp5CVU5rfkJ3aIWAQj7RlIMByg3rzpD9xIOW1ni2riT0Ql-AT9jjHrTGQUCqFiysdcySiUb9h8Cv4jvN33MXyK8sAD" target="_blank" rel="noopener">书名</a>早有耳闻。</p>
<p>在午休期间陆陆续续翻了百来页，有点坚持不下去了，今天拿去还了。</p>
<p>这书估计，会看我博客的人，不会有人会去看的，就像没几个青少年会去主动看什么 <em>狂人日记</em> 或者 <em>呐喊</em> 之类的书。</p>
<p>本书主要是以猫的角度来讽刺日本那个时代，文人墨客、资本家的虚伪迂腐之类的玩意。</p>
<p>给我的感觉是，和鲁迅有些方面很像，首先人长的有点像，哈哈。</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/屏幕快照 2017-06-02 下午4.39.27.jpg" alt="屏幕快照 2017-06-02 下午4.39.27"></p>
<p>接着是风格，这点真的给我感觉，神似。太多地方给我的感觉很像，特别是那种讽刺的口吻，额，这只能是只可意会不可言传了。</p>
<p>写到这里的时候，我突然想到，这两人有没有交集呢？</p>
<p>这一<a href="https://www.baidu.com/s?ie=utf-8&amp;f=8&amp;rsv_bp=1&amp;tn=64075107_1_dg&amp;wd=%E5%A4%8F%E7%9B%AE%E6%BC%B1%E7%9F%B3%E5%92%8C%E9%B2%81%E8%BF%85&amp;oq=%25E5%25A4%258F%25E7%259B%25AE%25E6%25BC%25B1%25E7%259F%25B3%25E5%25AF%25B9%25E9%25B2%2581%25E8%25BF%2585%25E7%259A%2584%25E5%25BD%25B1%25E5%2593%258D&amp;rsv_pq=ab52e7e0000205e2&amp;rsv_t=8fbd3wGMwJkLYvM8XA%2FehNXgNNdzl254%2BtAvVbDtZHBCaSoVX3kebd4HPwVztECpFunXng&amp;rqlang=cn&amp;rsv_enter=1&amp;inputT=3667&amp;rsv_sug3=9&amp;rsv_sug1=3&amp;rsv_sug7=000&amp;rsv_sug2=0&amp;rsv_sug4=4319&amp;rsv_sug=1" target="_blank" rel="noopener">搜索</a>，吓我一跳：</p>
<p>在<a href="https://www.zhihu.com/question/31936882" target="_blank" rel="noopener">知乎</a>上有人这么说：</p>
<p><em>鲁迅确实深受夏目漱石影响，鲁迅留日期间对其影响最大的作家就是夏目漱石。鲁迅在日本住的屋子就是漱石曾经居住过的。周作人讲，鲁迅非常喜欢夏目漱石的《我是猫》。夏目漱石文学中的讽刺影响了鲁迅的文学观。增田涉在《鲁迅在日本》一书中这样写到：“鲁迅后来所写的小说的作风，与漱石的作风也不相似。但那嘲讽之中的轻妙笔致，则是颇受漱石的影响。”</em></p>
<p>我百度了一下：</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/屏幕快照 2017-06-02 下午4.48.13.png" alt="屏幕快照 2017-06-02 下午4.48.13"></p>
<p>居然还有人专门去研究这个的，也是服了，算是涨姿势了。</p>
<p>关于本书，给我最大的收获除了知道鲁迅和作者有一腿之外，就是收留那只猫的那个所谓教师男主，他的虚伪和傻逼性格，让我印象深刻。怕不是那个时代很多日本人都那样啊。</p>
]]></content>
    
    <summary type="html">
    
      &lt;center&gt;&lt;br&gt;&lt;br&gt;&lt;img src=&quot;http://on9hzfn6s.bkt.clouddn.com/s6282827.jpg&quot; alt=&quot;s6282827&quot;&gt;&lt;br&gt;&lt;br&gt;&lt;/center&gt;
    
    </summary>
    
      <category term="阅读" scheme="http://yoursite.com/categories/%E9%98%85%E8%AF%BB/"/>
    
    
      <category term="读书笔记" scheme="http://yoursite.com/tags/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/"/>
    
  </entry>
  
  <entry>
    <title>Img2Word By Python</title>
    <link href="http://yoursite.com/2017/06/02/Img2Wordbypy/"/>
    <id>http://yoursite.com/2017/06/02/Img2Wordbypy/</id>
    <published>2017-06-02T03:02:49.000Z</published>
    <updated>2017-06-02T16:11:07.000Z</updated>
    
    <content type="html"><![CDATA[<p>将一张图片用字符表示。</p>
<p>效果图：</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/63DD1284-3477-4DDC-82BC-77D3B8B11A1A.jpg" alt="63DD1284-3477-4DDC-82BC-77D3B8B11A1A"></p>
<a id="more"></a>
<h4 id="包结构"><a href="#包结构" class="headerlink" title="包结构"></a>包结构</h4><p><img src="http://on9hzfn6s.bkt.clouddn.com/14963736807608.png" alt></p>
<p>第一个是 py 文件，第二个是想要转换成字符的图片，第三个输出字符的文档。</p>
<h4 id="导包"><a href="#导包" class="headerlink" title="导包"></a>导包</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> PIL <span class="keyword">import</span> Image</span><br><span class="line"><span class="keyword">import</span> argparse</span><br></pre></td></tr></table></figure>
<p>这两个包前者是 Python 中强大的图片处理工具库，后者是由 <a href="https://docs.python.org/2/library/optparse.html" target="_blank" rel="noopener">optparse</a> 驱动的用来管理命令行参数输入的工具：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">This module <span class="keyword">is</span> an optparse-inspired command-line parsing library that:</span><br><span class="line"></span><br><span class="line">    - handles both optional <span class="keyword">and</span> positional arguments</span><br><span class="line">    - produces highly informative usage messages</span><br><span class="line">    - supports parsers that dispatch to sub-parsers</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 可处理可选择的和指定位置的参数</span></span><br><span class="line">    <span class="comment"># 能够提取非常有用的信息</span></span><br><span class="line">    <span class="comment"># 支持解析部分参数</span></span><br></pre></td></tr></table></figure>
<h4 id="获取输入的参数"><a href="#获取输入的参数" class="headerlink" title="获取输入的参数"></a>获取输入的参数</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#命令行输入参数处理</span></span><br><span class="line">parser = argparse.ArgumentParser()</span><br><span class="line"></span><br><span class="line">parser.add_argument(<span class="string">'file'</span>)     <span class="comment">#输入文件</span></span><br><span class="line">parser.add_argument(<span class="string">'-o'</span>, <span class="string">'--output'</span>)   <span class="comment">#输出文件</span></span><br><span class="line">parser.add_argument(<span class="string">'--width'</span>, type = int, default = <span class="number">120</span>) <span class="comment">#输出字符画宽</span></span><br><span class="line">parser.add_argument(<span class="string">'--height'</span>, type = int, default = <span class="number">120</span>) <span class="comment">#输出字符画高</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#获取参数</span></span><br><span class="line">args = parser.parse_args()</span><br><span class="line"></span><br><span class="line">IMG = args.file</span><br><span class="line">WIDTH = args.width</span><br><span class="line">HEIGHT = args.height</span><br><span class="line">OUTPUT = args.output</span><br></pre></td></tr></table></figure>
<h4 id="字符集"><a href="#字符集" class="headerlink" title="字符集"></a>字符集</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ascii_char = list(<span class="string">"$@B%8&amp;WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1&#123;&#125;[]?-_+~&lt;&gt;i!lI;:,\"^`'. "</span>)</span><br></pre></td></tr></table></figure>
<p>这个字符集合可以自己来定义，一般情况下，越长越多，能表示颜色就越多，图片也就更清晰有层次感。</p>
<h4 id="关于灰度"><a href="#关于灰度" class="headerlink" title="关于灰度"></a>关于灰度</h4><p>将一张彩色的照片转换成黑白的，用一定的<a href="https://en.wikipedia.org/wiki/Grayscale" target="_blank" rel="noopener">算法</a>，这里用的计算方式：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gray = int(<span class="number">0.2126</span> * r + <span class="number">0.7152</span> * g + <span class="number">0.0722</span> * b)</span><br></pre></td></tr></table></figure>
<h4 id="映射"><a href="#映射" class="headerlink" title="映射"></a>映射</h4><p>将灰度一一对应到定义好的字符集中：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">get_char</span><span class="params">(r,g,b,alpha = <span class="number">256</span>)</span>:</span></span><br><span class="line">    <span class="keyword">if</span> alpha == <span class="number">0</span>:</span><br><span class="line">        <span class="keyword">return</span> <span class="string">' '</span></span><br><span class="line">    length = len(ascii_char)</span><br><span class="line">    gray = int(<span class="number">0.2126</span> * r + <span class="number">0.7152</span> * g + <span class="number">0.0722</span> * b)</span><br><span class="line"></span><br><span class="line">    unit = (<span class="number">256.0</span> + <span class="number">1</span>)/length</span><br><span class="line">    <span class="keyword">return</span> ascii_char[int(gray/unit)]</span><br></pre></td></tr></table></figure>
<h4 id="遍历像素并输出"><a href="#遍历像素并输出" class="headerlink" title="遍历像素并输出"></a>遍历像素并输出</h4><p>获取到对应图片，通过 <code>im.getpixel()</code> 方法获取到该图片中每个像素点的色值，再通过之前的灰度映射方法获取到对应的字符，输出到指定的文档中。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</span><br><span class="line"></span><br><span class="line">    im = Image.open(IMG)</span><br><span class="line">    im = im.resize((WIDTH,HEIGHT), Image.NEAREST)</span><br><span class="line"></span><br><span class="line">    txt = <span class="string">""</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> range(HEIGHT):</span><br><span class="line">        <span class="keyword">for</span> j <span class="keyword">in</span> range(WIDTH):</span><br><span class="line">            txt += get_char(*im.getpixel((j,i)))</span><br><span class="line">        txt += <span class="string">'\n'</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">print</span> txt</span><br><span class="line"></span><br><span class="line">    <span class="comment">#字符画输出到文件</span></span><br><span class="line">    <span class="keyword">if</span> OUTPUT:</span><br><span class="line">        <span class="keyword">with</span> open(OUTPUT,<span class="string">'w'</span>) <span class="keyword">as</span> f:</span><br><span class="line">            f.write(txt)</span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        <span class="keyword">with</span> open(<span class="string">"output.txt"</span>,<span class="string">'w'</span>) <span class="keyword">as</span> f:</span><br><span class="line">            f.write(txt)</span><br></pre></td></tr></table></figure>
<h4 id="运行"><a href="#运行" class="headerlink" title="运行"></a>运行</h4><p>到对应的目录下执行命令行就好了</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python ascii.py img.png</span><br></pre></td></tr></table></figure>
<p>记得要跟上图片的文件名(别的参数可选)</p>
<h4 id="完整代码"><a href="#完整代码" class="headerlink" title="完整代码"></a>完整代码</h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python</span></span><br><span class="line"><span class="comment"># -*- coding: utf-8 -*-</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> PIL <span class="keyword">import</span> Image</span><br><span class="line"><span class="keyword">import</span> argparse</span><br><span class="line"></span><br><span class="line"><span class="comment">#命令行输入参数处理</span></span><br><span class="line">parser = argparse.ArgumentParser()</span><br><span class="line"></span><br><span class="line">parser.add_argument(<span class="string">'file'</span>)     <span class="comment">#输入文件</span></span><br><span class="line">parser.add_argument(<span class="string">'-o'</span>, <span class="string">'--output'</span>)   <span class="comment">#输出文件</span></span><br><span class="line">parser.add_argument(<span class="string">'--width'</span>, type = int, default = <span class="number">120</span>) <span class="comment">#输出字符画宽</span></span><br><span class="line">parser.add_argument(<span class="string">'--height'</span>, type = int, default = <span class="number">120</span>) <span class="comment">#输出字符画高</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#获取参数</span></span><br><span class="line">args = parser.parse_args()</span><br><span class="line"></span><br><span class="line">IMG = args.file</span><br><span class="line">WIDTH = args.width</span><br><span class="line">HEIGHT = args.height</span><br><span class="line">OUTPUT = args.output</span><br><span class="line"></span><br><span class="line">ascii_char = list(<span class="string">"$@B%8&amp;WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1&#123;&#125;[]?-_+~&lt;&gt;i!lI;:,\"^`'. "</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 将256灰度映射到70个字符上</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">get_char</span><span class="params">(r,g,b,alpha = <span class="number">256</span>)</span>:</span></span><br><span class="line">    <span class="keyword">if</span> alpha == <span class="number">0</span>:</span><br><span class="line">        <span class="keyword">return</span> <span class="string">' '</span></span><br><span class="line">    length = len(ascii_char)</span><br><span class="line">    gray = int(<span class="number">0.2126</span> * r + <span class="number">0.7152</span> * g + <span class="number">0.0722</span> * b)</span><br><span class="line"></span><br><span class="line">    unit = (<span class="number">256.0</span> + <span class="number">1</span>)/length</span><br><span class="line">    <span class="keyword">return</span> ascii_char[int(gray/unit)]</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</span><br><span class="line"></span><br><span class="line">    im = Image.open(IMG)</span><br><span class="line">    im = im.resize((WIDTH,HEIGHT), Image.NEAREST)</span><br><span class="line"></span><br><span class="line">    txt = <span class="string">""</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> range(HEIGHT):</span><br><span class="line">        <span class="keyword">for</span> j <span class="keyword">in</span> range(WIDTH):</span><br><span class="line">            txt += get_char(*im.getpixel((j,i)))</span><br><span class="line">        txt += <span class="string">'\n'</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">print</span> txt</span><br><span class="line"></span><br><span class="line">    <span class="comment">#字符画输出到文件</span></span><br><span class="line">    <span class="keyword">if</span> OUTPUT:</span><br><span class="line">        <span class="keyword">with</span> open(OUTPUT,<span class="string">'w'</span>) <span class="keyword">as</span> f:</span><br><span class="line">            f.write(txt)</span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        <span class="keyword">with</span> open(<span class="string">"output.txt"</span>,<span class="string">'w'</span>) <span class="keyword">as</span> f:</span><br><span class="line">            f.write(txt)</span><br></pre></td></tr></table></figure>
<hr>
<p><a href="https://www.shiyanlou.com/courses/370" target="_blank" rel="noopener">代码来源</a></p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;将一张图片用字符表示。&lt;/p&gt;
&lt;p&gt;效果图：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://on9hzfn6s.bkt.clouddn.com/63DD1284-3477-4DDC-82BC-77D3B8B11A1A.jpg&quot; alt=&quot;63DD1284-3477-4DDC-82BC-77D3B8B11A1A&quot;&gt;&lt;/p&gt;
    
    </summary>
    
      <category term="python" scheme="http://yoursite.com/categories/python/"/>
    
    
      <category term="Python" scheme="http://yoursite.com/tags/Python/"/>
    
  </entry>
  
  <entry>
    <title>安卓图片模糊占位加载</title>
    <link href="http://yoursite.com/2017/06/01/%E5%AE%89%E5%8D%93%E5%9B%BE%E7%89%87%E6%A8%A1%E7%B3%8A%E5%8D%A0%E4%BD%8D%E5%8A%A0%E8%BD%BD/"/>
    <id>http://yoursite.com/2017/06/01/安卓图片模糊占位加载/</id>
    <published>2017-06-01T00:42:53.000Z</published>
    <updated>2017-06-01T02:30:16.000Z</updated>
    
    <content type="html"><![CDATA[<p>先看效果图：</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/Untitled1.gif" alt="Untitled1"></p>
<a id="more"></a>
<p>这个效果在<a href="https://www.zhihu.com/" target="_blank" rel="noopener">知乎</a>和 <a href="https://medium.com/" target="_blank" rel="noopener">Medium</a> 的 PC 端都有应用。</p>
<p>而且手机端和电脑端都可以通过相同的方式实现这个效果，核心逻辑都是先加载一张放大的缩略图，将其进行模糊处理，同时加载大图并添加一个监听，当大图加载完成的时候，将小图替换成大图。</p>
<p>这里我们直接使用 <a href="https://github.com/bumptech/glide" target="_blank" rel="noopener">Glide</a> 图片加载框架。</p>
<p>先简单的写个布局：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line">&lt;?xml version="1.0" encoding="utf-8"?&gt;</span><br><span class="line"><span class="tag">&lt;<span class="name">LinearLayout</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xmlns:android</span>=<span class="string">"http://schemas.android.com/apk/res/android"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xmlns:tools</span>=<span class="string">"http://schemas.android.com/tools"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:layout_width</span>=<span class="string">"match_parent"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:layout_height</span>=<span class="string">"match_parent"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:orientation</span>=<span class="string">"vertical"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">tools:context</span>=<span class="string">"com.zhanglf.badgenumberdemo.MainActivity"</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">ImageView</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:scaleType</span>=<span class="string">"fitCenter"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:id</span>=<span class="string">"@+id/iv_load"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_width</span>=<span class="string">"400dp"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_height</span>=<span class="string">"200dp"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_gravity</span>=<span class="string">"center"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_marginTop</span>=<span class="string">"40dp"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">ImageView</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:scaleType</span>=<span class="string">"fitCenter"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:id</span>=<span class="string">"@+id/iv_load2"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_width</span>=<span class="string">"400dp"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_height</span>=<span class="string">"200dp"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_gravity</span>=<span class="string">"center"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_marginTop</span>=<span class="string">"40dp"</span>/&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">LinearLayout</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_width</span>=<span class="string">"match_parent"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_height</span>=<span class="string">"wrap_content"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:gravity</span>=<span class="string">"center"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:orientation</span>=<span class="string">"horizontal"</span>&gt;</span></span><br><span class="line"></span><br><span class="line">        <span class="tag">&lt;<span class="name">Button</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:id</span>=<span class="string">"@+id/bt_load"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:layout_width</span>=<span class="string">"wrap_content"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:layout_height</span>=<span class="string">"wrap_content"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:layout_gravity</span>=<span class="string">"center"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:text</span>=<span class="string">"LOAD"</span>/&gt;</span></span><br><span class="line"></span><br><span class="line">        <span class="tag">&lt;<span class="name">Button</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:id</span>=<span class="string">"@+id/bt_clean"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:layout_width</span>=<span class="string">"wrap_content"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:layout_height</span>=<span class="string">"wrap_content"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:layout_marginLeft</span>=<span class="string">"40dp"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:text</span>=<span class="string">"CLEAN"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">LinearLayout</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">LinearLayout</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>单独封装一个 <code>BlurImageLoader</code> 类来实行图片模糊加载。（其实可以很简洁的，但是我看要传入的参数太多，再则为了试试之前的看的 Builder 设计模式，这里简单封装了一下，其实真的是画蛇添足，傻逼了，也不想改了 T T）</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BlurImageLoader</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> Context mContext;</span><br><span class="line">    <span class="keyword">private</span> String mBlurImageUrl;</span><br><span class="line">    <span class="keyword">private</span> String mNormalImageUrl;</span><br><span class="line">    <span class="keyword">private</span> ImageView mImageView;</span><br><span class="line"></span><br><span 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;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> Context mContext;</span><br><span class="line">        <span class="keyword">private</span> String mBlurImageUrl;</span><br><span class="line">        <span class="keyword">private</span> String mNormalImageUrl;</span><br><span class="line">        <span class="keyword">private</span> ImageView mImageView;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">Builder</span><span class="params">(Context context)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.mContext = context;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> Builder <span class="title">Loader</span><span class="params">(String blurImageUrl, String normalImageUrl)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.mBlurImageUrl = blurImageUrl;</span><br><span class="line">            <span class="keyword">this</span>.mNormalImageUrl = normalImageUrl;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> Builder <span class="title">into</span><span class="params">(ImageView targetImageView)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.mImageView = targetImageView;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> BlurImageLoader <span class="title">builder</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> BlurImageLoader(<span class="keyword">this</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">BlurImageLoader</span><span class="params">(Builder builder)</span> </span>&#123;</span><br><span class="line">        mContext = builder.mContext;</span><br><span class="line">        mBlurImageUrl = builder.mBlurImageUrl;</span><br><span class="line">        mNormalImageUrl = builder.mNormalImageUrl;</span><br><span class="line">        mImageView = builder.mImageView;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> context        Any context, will not be retained.</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> imageView      The target to load the resource into.</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> blurImageUrl   The thumbnail view of url.</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> normalImageUrl The normal view of url</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">Loader</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        Glide.with(mContext).load(mBlurImageUrl).bitmapTransform(<span class="keyword">new</span> BlurTransformation(mContext, <span class="number">5</span>)).into(<span class="keyword">new</span> GlideDrawableImageViewTarget(mImageView) &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onResourceReady</span><span class="params">(<span class="keyword">final</span> GlideDrawable resource, <span class="keyword">final</span> GlideAnimation&lt;? <span class="keyword">super</span> GlideDrawable&gt; animation)</span> </span>&#123;</span><br><span class="line">                <span class="keyword">super</span>.onResourceReady(resource, animation);</span><br><span class="line">                Glide.with(mContext).load(mNormalImageUrl).placeholder(resource).crossFade().into(mImageView);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>核心代码就是 <code>Loader()</code> 方法了，其中：</p>
<p><code>.bitmapTransform(new BlurTransformation(mContext, 5))</code> 这个新建类就是模糊的关键了。</p>
<p>他是我从 <a href="https://github.com/wasabeef/glide-transformations" target="_blank" rel="noopener">glide-transformations</a> 这个强大的 Glide 加载方式辅助工具中的<a href="https://github.com/wasabeef/glide-transformations/blob/master/transformations/src/main/java/jp/wasabeef/glide/transformations/BlurTransformation.java" target="_blank" rel="noopener">一个类中</a>摘取出来的。</p>
<p>这个类 <code>BlurTransformation</code> ：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Copyright (C) 2015 Wasabeef</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Licensed under the Apache License, Version 2.0 (the "License");</span></span><br><span class="line"><span class="comment"> * you may not use this file except in compliance with the License.</span></span><br><span class="line"><span class="comment"> * You may obtain a copy of the License at</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * http://www.apache.org/licenses/LICENSE-2.0</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Unless required by applicable law or agreed to in writing, software</span></span><br><span class="line"><span class="comment"> * distributed under the License is distributed on an "AS IS" BASIS,</span></span><br><span class="line"><span class="comment"> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span></span><br><span class="line"><span class="comment"> * See the License for the specific language governing permissions and</span></span><br><span class="line"><span class="comment"> * limitations under the License.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> android.content.Context;</span><br><span class="line"><span class="keyword">import</span> android.graphics.Bitmap;</span><br><span class="line"><span class="keyword">import</span> android.graphics.Canvas;</span><br><span class="line"><span class="keyword">import</span> android.graphics.Paint;</span><br><span class="line"><span class="keyword">import</span> android.os.Build;</span><br><span class="line"><span class="keyword">import</span> android.renderscript.RSRuntimeException;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.bumptech.glide.Glide;</span><br><span class="line"><span class="keyword">import</span> com.bumptech.glide.load.Transformation;</span><br><span class="line"><span class="keyword">import</span> com.bumptech.glide.load.engine.Resource;</span><br><span class="line"><span class="keyword">import</span> com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;</span><br><span class="line"><span class="keyword">import</span> com.bumptech.glide.load.resource.bitmap.BitmapResource;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BlurTransformation</span> <span class="keyword">implements</span> <span class="title">Transformation</span>&lt;<span class="title">Bitmap</span>&gt; </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> MAX_RADIUS = <span class="number">25</span>;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> DEFAULT_DOWN_SAMPLING = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> Context mContext;</span><br><span class="line">    <span class="keyword">private</span> BitmapPool mBitmapPool;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> mRadius;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> mSampling;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">BlurTransformation</span><span class="params">(Context context)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>(context, Glide.get(context).getBitmapPool(), MAX_RADIUS, DEFAULT_DOWN_SAMPLING);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">BlurTransformation</span><span class="params">(Context context, BitmapPool pool)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>(context, pool, MAX_RADIUS, DEFAULT_DOWN_SAMPLING);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">BlurTransformation</span><span class="params">(Context context, BitmapPool pool, <span class="keyword">int</span> radius)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>(context, pool, radius, DEFAULT_DOWN_SAMPLING);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">BlurTransformation</span><span class="params">(Context context, <span class="keyword">int</span> radius)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>(context, Glide.get(context).getBitmapPool(), radius, DEFAULT_DOWN_SAMPLING);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">BlurTransformation</span><span class="params">(Context context, <span class="keyword">int</span> radius, <span class="keyword">int</span> sampling)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>(context, Glide.get(context).getBitmapPool(), radius, sampling);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">BlurTransformation</span><span class="params">(Context context, BitmapPool pool, <span class="keyword">int</span> radius, <span class="keyword">int</span> sampling)</span> </span>&#123;</span><br><span class="line">        mContext = context.getApplicationContext();</span><br><span class="line">        mBitmapPool = pool;</span><br><span class="line">        mRadius = radius;</span><br><span class="line">        mSampling = sampling;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Resource&lt;Bitmap&gt; <span class="title">transform</span><span class="params">(Resource&lt;Bitmap&gt; resource, <span class="keyword">int</span> outWidth, <span class="keyword">int</span> outHeight)</span> </span>&#123;</span><br><span class="line">        Bitmap source = resource.get();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">int</span> width = source.getWidth();</span><br><span class="line">        <span class="keyword">int</span> height = source.getHeight();</span><br><span class="line">        <span class="keyword">int</span> scaledWidth = width / mSampling;</span><br><span class="line">        <span class="keyword">int</span> scaledHeight = height / mSampling;</span><br><span class="line"></span><br><span class="line">        Bitmap bitmap = mBitmapPool.get(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888);</span><br><span class="line">        <span class="keyword">if</span> (bitmap == <span class="keyword">null</span>) &#123;</span><br><span class="line">            bitmap = Bitmap.createBitmap(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        Canvas canvas = <span class="keyword">new</span> Canvas(bitmap);</span><br><span class="line">        canvas.scale(<span class="number">1</span> / (<span class="keyword">float</span>) mSampling, <span class="number">1</span> / (<span class="keyword">float</span>) mSampling);</span><br><span class="line">        Paint paint = <span class="keyword">new</span> Paint();</span><br><span class="line">        paint.setFlags(Paint.FILTER_BITMAP_FLAG);</span><br><span class="line">        canvas.drawBitmap(source, <span class="number">0</span>, <span class="number">0</span>, paint);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.JELLY_BEAN_MR2) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                bitmap = RSBlur.blur(mContext, bitmap, mRadius);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (RSRuntimeException e) &#123;</span><br><span class="line">                bitmap = FastBlur.blur(bitmap, mRadius, <span class="keyword">true</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            bitmap = FastBlur.blur(bitmap, mRadius, <span class="keyword">true</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> BitmapResource.obtain(bitmap, mBitmapPool);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span> <span class="function"><span class="keyword">public</span> String <span class="title">getId</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">"BlurTransformation(radius="</span> + mRadius + <span class="string">", sampling="</span> + mSampling + <span class="string">")"</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>他有多种构造方式，常用的就是上面用到的，第一个传入上下文，第二次传入一个 <code>int</code> 值，这个 <code>int</code> 值代表图片的模糊程度。</p>
<p>对模糊程度没有概念的可以看<a href="http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html" target="_blank" rel="noopener">这个网站</a>，自己调整感受一下。</p>
<p><code>BlurTransformation</code> 类中对 <code>VERSION_CODES</code> 进行判断，大于 18 的采用 <code>RSBlur</code> 进行模糊处理，也就是安卓自带的 <code>ScriptIntrinsicBlur</code> 类。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> android.annotation.TargetApi;</span><br><span class="line"><span class="keyword">import</span> android.content.Context;</span><br><span class="line"><span class="keyword">import</span> android.graphics.Bitmap;</span><br><span class="line"><span class="keyword">import</span> android.os.Build;</span><br><span class="line"><span class="keyword">import</span> android.renderscript.Allocation;</span><br><span class="line"><span class="keyword">import</span> android.renderscript.Element;</span><br><span class="line"><span class="keyword">import</span> android.renderscript.RSRuntimeException;</span><br><span class="line"><span class="keyword">import</span> android.renderscript.RenderScript;</span><br><span class="line"><span class="keyword">import</span> android.renderscript.ScriptIntrinsicBlur;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Copyright (C) 2017 Wasabeef</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Licensed under the Apache License, Version 2.0 (the "License");</span></span><br><span class="line"><span class="comment"> * you may not use this file except in compliance with the License.</span></span><br><span class="line"><span class="comment"> * You may obtain a copy of the License at</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * http://www.apache.org/licenses/LICENSE-2.0</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Unless required by applicable law or agreed to in writing, software</span></span><br><span class="line"><span class="comment"> * distributed under the License is distributed on an "AS IS" BASIS,</span></span><br><span class="line"><span class="comment"> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span></span><br><span class="line"><span class="comment"> * See the License for the specific language governing permissions and</span></span><br><span class="line"><span class="comment"> * limitations under the License.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">RSBlur</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@TargetApi</span>(Build.VERSION_CODES.JELLY_BEAN_MR2)</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Bitmap <span class="title">blur</span><span class="params">(Context context, Bitmap bitmap, <span class="keyword">int</span> radius)</span> <span class="keyword">throws</span> RSRuntimeException </span>&#123;</span><br><span class="line">        RenderScript rs = <span class="keyword">null</span>;</span><br><span class="line">        Allocation input = <span class="keyword">null</span>;</span><br><span class="line">        Allocation output = <span class="keyword">null</span>;</span><br><span class="line">        ScriptIntrinsicBlur blur = <span class="keyword">null</span>;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            rs = RenderScript.create(context);</span><br><span class="line">            rs.setMessageHandler(<span class="keyword">new</span> RenderScript.RSMessageHandler());</span><br><span class="line">            input = Allocation.createFromBitmap(rs, bitmap, Allocation.MipmapControl.MIPMAP_NONE,</span><br><span class="line">                    Allocation.USAGE_SCRIPT);</span><br><span class="line">            output = Allocation.createTyped(rs, input.getType());</span><br><span class="line">            blur = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));</span><br><span class="line"></span><br><span class="line">            blur.setInput(input);</span><br><span class="line">            blur.setRadius(radius);</span><br><span class="line">            blur.forEach(output);</span><br><span class="line">            output.copyTo(bitmap);</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (rs != <span class="keyword">null</span>) &#123;</span><br><span class="line">                rs.destroy();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (input != <span class="keyword">null</span>) &#123;</span><br><span class="line">                input.destroy();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (output != <span class="keyword">null</span>) &#123;</span><br><span class="line">                output.destroy();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (blur != <span class="keyword">null</span>) &#123;</span><br><span class="line">                blur.destroy();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> bitmap;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>小于 18 的采用被广为使用的 <code>FastBlur</code> 类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> android.graphics.Bitmap;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Copyright (C) 2015 Wasabeef</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Licensed under the Apache License, Version 2.0 (the "License");</span></span><br><span class="line"><span class="comment"> * you may not use this file except in compliance with the License.</span></span><br><span class="line"><span class="comment"> * You may obtain a copy of the License at</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * http://www.apache.org/licenses/LICENSE-2.0</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Unless required by applicable law or agreed to in writing, software</span></span><br><span class="line"><span class="comment"> * distributed under the License is distributed on an "AS IS" BASIS,</span></span><br><span class="line"><span class="comment"> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span></span><br><span class="line"><span class="comment"> * See the License for the specific language governing permissions and</span></span><br><span class="line"><span class="comment"> * limitations under the License.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FastBlur</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Bitmap <span class="title">blur</span><span class="params">(Bitmap sentBitmap, <span class="keyword">int</span> radius, <span class="keyword">boolean</span> canReuseInBitmap)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// Stack Blur v1.0 from</span></span><br><span class="line">        <span class="comment">// http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html</span></span><br><span class="line">        <span class="comment">//</span></span><br><span class="line">        <span class="comment">// Java Author: Mario Klingemann &lt;mario at quasimondo.com&gt;</span></span><br><span class="line">        <span class="comment">// http://incubator.quasimondo.com</span></span><br><span class="line">        <span class="comment">// created Feburary 29, 2004</span></span><br><span class="line">        <span class="comment">// Android port : Yahel Bouaziz &lt;yahel at kayenko.com&gt;</span></span><br><span class="line">        <span class="comment">// http://www.kayenko.com</span></span><br><span class="line">        <span class="comment">// ported april 5th, 2012</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">// This is a compromise between Gaussian Blur and Box blur</span></span><br><span class="line">        <span class="comment">// It creates much better looking blurs than Box Blur, but is</span></span><br><span class="line">        <span class="comment">// 7x faster than my Gaussian Blur implementation.</span></span><br><span class="line">        <span class="comment">//</span></span><br><span class="line">        <span class="comment">// I called it Stack Blur because this describes best how this</span></span><br><span class="line">        <span class="comment">// filter works internally: it creates a kind of moving stack</span></span><br><span class="line">        <span class="comment">// of colors whilst scanning through the image. Thereby it</span></span><br><span class="line">        <span class="comment">// just has to add one new block of color to the right side</span></span><br><span class="line">        <span class="comment">// of the stack and remove the leftmost color. The remaining</span></span><br><span class="line">        <span class="comment">// colors on the topmost layer of the stack are either added on</span></span><br><span class="line">        <span class="comment">// or reduced by one, depending on if they are on the right or</span></span><br><span class="line">        <span class="comment">// on the left side of the stack.</span></span><br><span class="line">        <span class="comment">//</span></span><br><span class="line">        <span class="comment">// If you are using this algorithm in your code please add</span></span><br><span class="line">        <span class="comment">// the following line:</span></span><br><span class="line">        <span class="comment">//</span></span><br><span class="line">        <span class="comment">// Stack Blur Algorithm by Mario Klingemann &lt;mario@quasimondo.com&gt;</span></span><br><span class="line"></span><br><span class="line">        Bitmap bitmap;</span><br><span class="line">        <span class="keyword">if</span> (canReuseInBitmap) &#123;</span><br><span class="line">            bitmap = sentBitmap;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            bitmap = sentBitmap.copy(sentBitmap.getConfig(), <span class="keyword">true</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (radius &lt; <span class="number">1</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> (<span class="keyword">null</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">int</span> w = bitmap.getWidth();</span><br><span class="line">        <span class="keyword">int</span> h = bitmap.getHeight();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">int</span>[] pix = <span class="keyword">new</span> <span class="keyword">int</span>[w * h];</span><br><span class="line">        bitmap.getPixels(pix, <span class="number">0</span>, w, <span class="number">0</span>, <span class="number">0</span>, w, h);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">int</span> wm = w - <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">int</span> hm = h - <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">int</span> wh = w * h;</span><br><span class="line">        <span class="keyword">int</span> div = radius + radius + <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">int</span> r[] = <span class="keyword">new</span> <span class="keyword">int</span>[wh];</span><br><span class="line">        <span class="keyword">int</span> g[] = <span class="keyword">new</span> <span class="keyword">int</span>[wh];</span><br><span class="line">        <span class="keyword">int</span> b[] = <span class="keyword">new</span> <span class="keyword">int</span>[wh];</span><br><span class="line">        <span class="keyword">int</span> rsum, gsum, bsum, x, y, i, p, yp, yi, yw;</span><br><span class="line">        <span class="keyword">int</span> vmin[] = <span class="keyword">new</span> <span class="keyword">int</span>[Math.max(w, h)];</span><br><span class="line"></span><br><span class="line">        <span class="keyword">int</span> divsum = (div + <span class="number">1</span>) &gt;&gt; <span class="number">1</span>;</span><br><span class="line">        divsum *= divsum;</span><br><span class="line">        <span class="keyword">int</span> dv[] = <span class="keyword">new</span> <span class="keyword">int</span>[<span class="number">256</span> * divsum];</span><br><span class="line">        <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">256</span> * divsum; i++) &#123;</span><br><span class="line">            dv[i] = (i / divsum);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        yw = yi = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">int</span>[][] stack = <span class="keyword">new</span> <span class="keyword">int</span>[div][<span class="number">3</span>];</span><br><span class="line">        <span class="keyword">int</span> stackpointer;</span><br><span class="line">        <span class="keyword">int</span> stackstart;</span><br><span class="line">        <span class="keyword">int</span>[] sir;</span><br><span class="line">        <span class="keyword">int</span> rbs;</span><br><span class="line">        <span class="keyword">int</span> r1 = radius + <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">int</span> routsum, goutsum, boutsum;</span><br><span class="line">        <span class="keyword">int</span> rinsum, ginsum, binsum;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (y = <span class="number">0</span>; y &lt; h; y++) &#123;</span><br><span class="line">            rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = <span class="number">0</span>;</span><br><span class="line">            <span class="keyword">for</span> (i = -radius; i &lt;= radius; i++) &#123;</span><br><span class="line">                p = pix[yi + Math.min(wm, Math.max(i, <span class="number">0</span>))];</span><br><span class="line">                sir = stack[i + radius];</span><br><span class="line">                sir[<span class="number">0</span>] = (p &amp; <span class="number">0xff0000</span>) &gt;&gt; <span class="number">16</span>;</span><br><span class="line">                sir[<span class="number">1</span>] = (p &amp; <span class="number">0x00ff00</span>) &gt;&gt; <span class="number">8</span>;</span><br><span class="line">                sir[<span class="number">2</span>] = (p &amp; <span class="number">0x0000ff</span>);</span><br><span class="line">                rbs = r1 - Math.abs(i);</span><br><span class="line">                rsum += sir[<span class="number">0</span>] * rbs;</span><br><span class="line">                gsum += sir[<span class="number">1</span>] * rbs;</span><br><span class="line">                bsum += sir[<span class="number">2</span>] * rbs;</span><br><span class="line">                <span class="keyword">if</span> (i &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                    rinsum += sir[<span class="number">0</span>];</span><br><span class="line">                    ginsum += sir[<span class="number">1</span>];</span><br><span class="line">                    binsum += sir[<span class="number">2</span>];</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    routsum += sir[<span class="number">0</span>];</span><br><span class="line">                    goutsum += sir[<span class="number">1</span>];</span><br><span class="line">                    boutsum += sir[<span class="number">2</span>];</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            stackpointer = radius;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">for</span> (x = <span class="number">0</span>; x &lt; w; x++) &#123;</span><br><span class="line"></span><br><span class="line">                r[yi] = dv[rsum];</span><br><span class="line">                g[yi] = dv[gsum];</span><br><span class="line">                b[yi] = dv[bsum];</span><br><span class="line"></span><br><span class="line">                rsum -= routsum;</span><br><span class="line">                gsum -= goutsum;</span><br><span class="line">                bsum -= boutsum;</span><br><span class="line"></span><br><span class="line">                stackstart = stackpointer - radius + div;</span><br><span class="line">                sir = stack[stackstart % div];</span><br><span class="line"></span><br><span class="line">                routsum -= sir[<span class="number">0</span>];</span><br><span class="line">                goutsum -= sir[<span class="number">1</span>];</span><br><span class="line">                boutsum -= sir[<span class="number">2</span>];</span><br><span class="line"></span><br><span class="line">                <span class="keyword">if</span> (y == <span class="number">0</span>) &#123;</span><br><span class="line">                    vmin[x] = Math.min(x + radius + <span class="number">1</span>, wm);</span><br><span class="line">                &#125;</span><br><span class="line">                p = pix[yw + vmin[x]];</span><br><span class="line"></span><br><span class="line">                sir[<span class="number">0</span>] = (p &amp; <span class="number">0xff0000</span>) &gt;&gt; <span class="number">16</span>;</span><br><span class="line">                sir[<span class="number">1</span>] = (p &amp; <span class="number">0x00ff00</span>) &gt;&gt; <span class="number">8</span>;</span><br><span class="line">                sir[<span class="number">2</span>] = (p &amp; <span class="number">0x0000ff</span>);</span><br><span class="line"></span><br><span class="line">                rinsum += sir[<span class="number">0</span>];</span><br><span class="line">                ginsum += sir[<span class="number">1</span>];</span><br><span class="line">                binsum += sir[<span class="number">2</span>];</span><br><span class="line"></span><br><span class="line">                rsum += rinsum;</span><br><span class="line">                gsum += ginsum;</span><br><span class="line">                bsum += binsum;</span><br><span class="line"></span><br><span class="line">                stackpointer = (stackpointer + <span class="number">1</span>) % div;</span><br><span class="line">                sir = stack[(stackpointer) % div];</span><br><span class="line"></span><br><span class="line">                routsum += sir[<span class="number">0</span>];</span><br><span class="line">                goutsum += sir[<span class="number">1</span>];</span><br><span class="line">                boutsum += sir[<span class="number">2</span>];</span><br><span class="line"></span><br><span class="line">                rinsum -= sir[<span class="number">0</span>];</span><br><span class="line">                ginsum -= sir[<span class="number">1</span>];</span><br><span class="line">                binsum -= sir[<span class="number">2</span>];</span><br><span class="line"></span><br><span class="line">                yi++;</span><br><span class="line">            &#125;</span><br><span class="line">            yw += w;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span> (x = <span class="number">0</span>; x &lt; w; x++) &#123;</span><br><span class="line">            rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = <span class="number">0</span>;</span><br><span class="line">            yp = -radius * w;</span><br><span class="line">            <span class="keyword">for</span> (i = -radius; i &lt;= radius; i++) &#123;</span><br><span class="line">                yi = Math.max(<span class="number">0</span>, yp) + x;</span><br><span class="line"></span><br><span class="line">                sir = stack[i + radius];</span><br><span class="line"></span><br><span class="line">                sir[<span class="number">0</span>] = r[yi];</span><br><span class="line">                sir[<span class="number">1</span>] = g[yi];</span><br><span class="line">                sir[<span class="number">2</span>] = b[yi];</span><br><span class="line"></span><br><span class="line">                rbs = r1 - Math.abs(i);</span><br><span class="line"></span><br><span class="line">                rsum += r[yi] * rbs;</span><br><span class="line">                gsum += g[yi] * rbs;</span><br><span class="line">                bsum += b[yi] * rbs;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">if</span> (i &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                    rinsum += sir[<span class="number">0</span>];</span><br><span class="line">                    ginsum += sir[<span class="number">1</span>];</span><br><span class="line">                    binsum += sir[<span class="number">2</span>];</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    routsum += sir[<span class="number">0</span>];</span><br><span class="line">                    goutsum += sir[<span class="number">1</span>];</span><br><span class="line">                    boutsum += sir[<span class="number">2</span>];</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">if</span> (i &lt; hm) &#123;</span><br><span class="line">                    yp += w;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            yi = x;</span><br><span class="line">            stackpointer = radius;</span><br><span class="line">            <span class="keyword">for</span> (y = <span class="number">0</span>; y &lt; h; y++) &#123;</span><br><span class="line">                <span class="comment">// Preserve alpha channel: ( 0xff000000 &amp; pix[yi] )</span></span><br><span class="line">                pix[yi] = (<span class="number">0xff000000</span> &amp; pix[yi]) | (dv[rsum] &lt;&lt; <span class="number">16</span>) | (dv[gsum] &lt;&lt; <span class="number">8</span>) | dv[bsum];</span><br><span class="line"></span><br><span class="line">                rsum -= routsum;</span><br><span class="line">                gsum -= goutsum;</span><br><span class="line">                bsum -= boutsum;</span><br><span class="line"></span><br><span class="line">                stackstart = stackpointer - radius + div;</span><br><span class="line">                sir = stack[stackstart % div];</span><br><span class="line"></span><br><span class="line">                routsum -= sir[<span class="number">0</span>];</span><br><span class="line">                goutsum -= sir[<span class="number">1</span>];</span><br><span class="line">                boutsum -= sir[<span class="number">2</span>];</span><br><span class="line"></span><br><span class="line">                <span class="keyword">if</span> (x == <span class="number">0</span>) &#123;</span><br><span class="line">                    vmin[y] = Math.min(y + r1, hm) * w;</span><br><span class="line">                &#125;</span><br><span class="line">                p = x + vmin[y];</span><br><span class="line"></span><br><span class="line">                sir[<span class="number">0</span>] = r[p];</span><br><span class="line">                sir[<span class="number">1</span>] = g[p];</span><br><span class="line">                sir[<span class="number">2</span>] = b[p];</span><br><span class="line"></span><br><span class="line">                rinsum += sir[<span class="number">0</span>];</span><br><span class="line">                ginsum += sir[<span class="number">1</span>];</span><br><span class="line">                binsum += sir[<span class="number">2</span>];</span><br><span class="line"></span><br><span class="line">                rsum += rinsum;</span><br><span class="line">                gsum += ginsum;</span><br><span class="line">                bsum += binsum;</span><br><span class="line"></span><br><span class="line">                stackpointer = (stackpointer + <span class="number">1</span>) % div;</span><br><span class="line">                sir = stack[stackpointer];</span><br><span class="line"></span><br><span class="line">                routsum += sir[<span class="number">0</span>];</span><br><span class="line">                goutsum += sir[<span class="number">1</span>];</span><br><span class="line">                boutsum += sir[<span class="number">2</span>];</span><br><span class="line"></span><br><span class="line">                rinsum -= sir[<span class="number">0</span>];</span><br><span class="line">                ginsum -= sir[<span class="number">1</span>];</span><br><span class="line">                binsum -= sir[<span class="number">2</span>];</span><br><span class="line"></span><br><span class="line">                yi += w;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        bitmap.setPixels(pix, <span class="number">0</span>, w, <span class="number">0</span>, <span class="number">0</span>, w, h);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> (bitmap);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>获取到了被模糊处理过后的缩略图之后，回到之前的 <code>Loader()</code> 方法中，我们重写了 <code>onResourceReady()</code> ，也就是当缩略图加载完成时，我们将该 <code>resoure</code> （注意这里的 <code>resource</code> 是已经被模糊处理过后的）放到再次调用 Glide图片加载的 <code>.placeholder(resource)</code> 中，当做是第二次加载图片的占位符。这里添加了一个 Glide 自带的过渡动画效果 <code>.crossFade()</code> 渐显。那么当大图加载完成的时候就会成功的替换之前的模糊小图了。</p>
<p>为了试验效果，我们给两个按钮添加点击事件：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">mIvLoad1 = (ImageView) findViewById(R.id.iv_load);</span><br><span class="line">       mIvLoad2 = (ImageView) findViewById(R.id.iv_load2);</span><br><span class="line"></span><br><span class="line">       findViewById(R.id.bt_load).setOnClickListener(<span class="keyword">new</span> View.OnClickListener() &#123;</span><br><span class="line">           <span class="meta">@Override</span></span><br><span class="line">           <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onClick</span><span class="params">(View v)</span> </span>&#123;</span><br><span class="line">               BlurImageLoader ivLoader1 = <span class="keyword">new</span> BlurImageLoader.Builder(MainActivity.<span class="keyword">this</span>).Loader(blurImageUrl1, normalImageUrl1).into(mIvLoad1).builder();</span><br><span class="line">               ivLoader1.Loader();</span><br><span class="line">               BlurImageLoader ivLoader2 = <span class="keyword">new</span> BlurImageLoader.Builder(MainActivity.<span class="keyword">this</span>).Loader(blurImageUrl2, normalImageUrl2).into(mIvLoad2).builder();</span><br><span class="line">               ivLoader2.Loader();</span><br><span class="line">           &#125;</span><br><span class="line">       &#125;);</span><br><span class="line"></span><br><span class="line">       findViewById(R.id.bt_clean).setOnClickListener(<span class="keyword">new</span> View.OnClickListener() &#123;</span><br><span class="line">           <span class="meta">@Override</span></span><br><span class="line">           <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onClick</span><span class="params">(View v)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">               Glide.clear(mIvLoad1);</span><br><span class="line">               Glide.clear(mIvLoad2);</span><br><span class="line">               mIvLoad1.setImageBitmap(<span class="keyword">null</span>);</span><br><span class="line">               mIvLoad2.setImageBitmap(<span class="keyword">null</span>);</span><br><span class="line">               clearCacheDiskSelf();</span><br><span class="line">               clearCacheMemory();</span><br><span class="line">           &#125;</span><br><span class="line">       &#125;);</span><br></pre></td></tr></table></figure>
<p>因为 Glide 自带的缓存效果，所以我们必须清除磁盘和内存的缓存：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">clearCacheDiskSelf</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (Looper.myLooper() == Looper.getMainLooper()) &#123;</span><br><span class="line">                <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">                    <span class="meta">@Override</span></span><br><span 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;</span><br><span class="line">                        Glide.get(getApplicationContext()).clearDiskCache();</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;).start();</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                Glide.get(getApplicationContext()).clearDiskCache();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">clearCacheMemory</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (Looper.myLooper() == Looper.getMainLooper()) &#123; <span class="comment">//只能在主线程执行</span></span><br><span class="line">                Glide.get(getApplicationContext()).clearMemory();</span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<p>哦，对了，我们要有图片来源才能实验啊，加载一张图片我们需要一张大图和一张小图，这里我的资源是随便打开了一个 Medium <a href="https://theringer.com/justin-bieber-despacito-forgetting-lyrics-breakdown-3646bfaf4cbd" target="_blank" rel="noopener">网站上的网页</a>使用浏览器的元素检查功能，然后直接复制了 <code>url</code> ：</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/屏幕快照 2017-06-01 上午10.03.32.png" alt="屏幕快照 2017-06-01 上午10.03.32"></p>
<p>我弄了两张图的资源，也就是四张图，为了加载快一点，将其放到了我自己的七牛云中，下面是资源地址：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> String blurImageUrl1 = <span class="string">"http://on9hzfn6s.bkt.clouddn.com/zhanglffffff.jpeg"</span>;</span><br><span class="line"><span class="keyword">private</span> String blurImageUrl2 = <span class="string">"http://on9hzfn6s.bkt.clouddn.com/1-_qd4EhIwH.jpeg"</span>;</span><br><span class="line"><span class="keyword">private</span> String normalImageUrl1 = <span class="string">"http://on9hzfn6s.bkt.clouddn.com/zhanglffffffbbb.jpeg"</span>;</span><br><span class="line"><span class="keyword">private</span> String normalImageUrl2 = <span class="string">"http://on9hzfn6s.bkt.clouddn.com/1-_qd4EhIwHbAjqzKPHu8-Ig.jpeg"</span>;</span><br></pre></td></tr></table></figure>
<p>然后就大功告成了（之前的效果图故意延时了一秒，这个是没有延时的）。</p>
<p><img src="http://on9hzfn6s.bkt.clouddn.com/Untitled.gif" alt="Untitled"></p>
]]></content>
    
    <summary type="html">
    
      &lt;p&gt;先看效果图：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://on9hzfn6s.bkt.clouddn.com/Untitled1.gif&quot; alt=&quot;Untitled1&quot;&gt;&lt;/p&gt;
    
    </summary>
    
      <category term="安卓" scheme="http://yoursite.com/categories/%E5%AE%89%E5%8D%93/"/>
    
    
      <category term="安卓" scheme="http://yoursite.com/tags/%E5%AE%89%E5%8D%93/"/>
    
  </entry>
  
</feed>
