-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
90 lines (49 loc) · 56.8 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>小马哥Mark的博客</title>
<link href="/atom.xml" rel="self"/>
<link href="https://madongqiang2201.github.io/"/>
<updated>2018-12-02T10:15:00.152Z</updated>
<id>https://madongqiang2201.github.io/</id>
<author>
<name>小马哥Mark</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>Android两种序列化方式详解(一):Serializable</title>
<link href="https://madongqiang2201.github.io/2018/12/02/Android%E4%B8%A4%E7%A7%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%96%B9%E5%BC%8F%E8%AF%A6%E8%A7%A3-%E4%B8%80-%EF%BC%9ASerializable/"/>
<id>https://madongqiang2201.github.io/2018/12/02/Android两种序列化方式详解-一-:Serializable/</id>
<published>2018-12-02T06:35:54.000Z</published>
<updated>2018-12-02T10:15:00.152Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>在 Android 开发中,我们经常需要对对象进行序列化与反序列化操作,最常见的就是通过 Intent 传输数据时,Intent 只能传输基本数据类型、String 类型和可序列化与反序列化的对象类型,要想通过 Intent 传递对象类型,我们需要让该对象类型支持序列化和反序列化。</p><p>我们知道,Android 给我们提供了两种方式来完成序列化与反序列化过程:一种是 Serializable 方式,另一种是 Parcelable 方式;本篇文章将详细讲述使用 Serializable 方式实现序列化你所需要知道的一切。</p><p>你可能会疑问,使用 Serializable 实现序列化,不是只要让类实现 Serializable 接口就可以了吗,有什么好讲的?那你就 too naive 了少年!除了基础的直接实现 Serializable 接口之外,我们使用 Serializable 方式实现序列化的过程还有很多需要注意的细节,例如 serialVersionUID 是干什么的呢?如果我们想自定义实现序列化与反序列化过程该怎么办呢?本文将会详细介绍这些知识。</p><h2 id="目录"><a href="#目录" class="headerlink" title="目录"></a>目录</h2><p>本文讲述的知识点如下:</p><ol><li>怎样序列化与反序列化一个对象</li><li>serialVersionUID 的作用</li><li>如何自定义序列化和反序列化过程</li><li>总结</li></ol><h2 id="一、怎样序列化和反序列化一个对象"><a href="#一、怎样序列化和反序列化一个对象" class="headerlink" title="一、怎样序列化和反序列化一个对象"></a>一、怎样序列化和反序列化一个对象</h2><p>想要序列化和反序列化一个对象,首先要让对象支持序列化与反序列化,使用 Serializable 方式实现序列化相当简单,只需要让类实现 Serializable 接口就可以:</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"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">UserSerial</span> <span class="keyword">implements</span> <span class="title">Serializable</span> </span>{</span><br></pre></td></tr></table></figure><p>现在 UserSerial 类就支持序列化和反序列化了,那么我们应该怎么将 UserSerial 类的某个对象序列化到文件,然后再将其读取出来呢?当然是使用 <code>ObjectOutputStream</code> 和 <code>ObjectInputStream</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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">serial</span><span class="params">(UserSerial user)</span> </span>{</span><br><span class="line"> ObjectOutputStream out = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> out = <span class="keyword">new</span> ObjectOutputStream(<span class="keyword">new</span> FileOutputStream(<span class="string">"temp.txt"</span>));</span><br><span class="line"> out.writeObject(user);</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">if</span> (out != <span class="keyword">null</span>) {</span><br><span class="line"> out.close();</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>完整的反序列化流程如下,这里为了防止反序列化异常返回 null,默认我们返回了一个新构造的空 UserSerial 对象:</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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> UserSerial <span class="title">deserial</span><span class="params">()</span> </span>{</span><br><span class="line"> ObjectInputStream in = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> in = <span class="keyword">new</span> ObjectInputStream(<span class="keyword">new</span> FileInputStream(<span class="string">"temp.txt"</span>));</span><br><span class="line"> <span class="keyword">return</span> (UserSerial) in.readObject();</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (ClassNotFoundException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">if</span> (in != <span class="keyword">null</span>) {</span><br><span class="line"> in.close();</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> UserSerial();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>可能有人要吐槽我上面说的都是废话了,上面这些东西,稍微了解点 Java 的都知道啊~没事,且往下看,我们来说一些可能大家使用过程中没注意到的细节。</p><h2 id="二、serialVersionUID-的作用"><a href="#二、serialVersionUID-的作用" class="headerlink" title="二、serialVersionUID 的作用"></a>二、serialVersionUID 的作用</h2><p>我们在使用 Serializable 方式实现序列化时,除了实现 Serializable 接口之外,一般还需要声明一个 serialVersionUID 静态字段,当然我们也可以选择不声明这个字段,那么我们在使用过程中,要不要指定这个字段呢?如果指定了,这个字段的值又是干什么用的呢?</p><p>其实 serialVersionUID 这个字段,是序列化和反序列化过程中,用来校验类是否发生了变动的依据,序列化的时候系统会把当前类的 serialVersionUID 字段写入序列化的文件中,当反序列化的时候,系统会去检测文件中的 serialVersionUID,看它是否和当前类的 serialVersionUID 一致,如果一致就说明序列化时类的版本和当前类的版本是相同的,这个时候可以成功反序列化,否则就说明当前类和序列化时的类相比发生了某些变换,比如增删了某些成员变量等,这个时候是无法正常的反序列化的,并且会报 <code>InvalidClassException</code>。</p><p>一般来讲,我们都应该手动指定 serialVersionUID 的值,可以随意指定一个数字,或者根据编辑器提示自动根据当前类的结构生成 hash 值,这样如果我们不手动修改,序列化和反序列化过程中 serialVersionUID 字段的值一直都会是一致的,可以最大限度的保证反序列化过程的成功,就算类结构发生了变动,我们也可以保证那些没有发生变动的成员变量被成功的反序列化。如果我们不手动指定 serialVersionUID 字段的值,那么如果反序列化时相比序列化时的类结构发生了变动,比如增删了成员变量等,那么系统就会重新计算当前类的 hash 值,并将其赋值给 serialVersionUID,导致序列化时的类和当前类的 serialVersionUID 值不一致,导致反序列化失败,从而 crash。</p><p>最后要说明的是,如果类结构发生了毁灭性的变化,如类名发生了改变,这个时候就算 serialVersionUID 值一致,也是不能被正常反序列化的,这一点后面还会提到。</p><h2 id="三、如何自定义序列化和反序列化过程"><a href="#三、如何自定义序列化和反序列化过程" class="headerlink" title="三、如何自定义序列化和反序列化过程"></a>三、如何自定义序列化和反序列化过程</h2><p>现在我们知道如果一个类,实现了 Serializable 接口,那么在需要的时候,自动完成该类的序列化,与反序列化过程;那么如果我们想自定义序列化过程与反序列化过程该怎么办呢?例如我在版本 1 的时候,将 User 对象的 name 序列化了,但是反序列化的时候,我想把这个这个字段的值赋值给 nameNew,该怎么做到呢?</p><p>第一部分我们我们提到,使用 Serializable 方式实现序列化是,对象的序列化和反序列化过程是通过 <code>ObjectOutputStream.writeObject</code> 和 <code>ObjectInputStream.readObject</code> 实现的,这里以 <code>ObjectOutputStream.writeObject</code> 为例分析,追踪 <code>writeObject</code> 方法代码,发现其内部调用了 writeObject0 方法:</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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">writeObject</span><span class="params">(Object obj)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"><span class="comment">// ...</span></span><br><span class="line">writeObject0(obj, <span class="keyword">false</span>);</span><br><span class="line"><span class="comment">//...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>进入 <code>writeObject0</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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">writeObject0</span><span class="params">(Object obj, <span class="keyword">boolean</span> unshared)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> <span class="keyword">if</span> (obj <span class="keyword">instanceof</span> Class) {</span><br><span class="line"> writeClass((Class) obj, unshared);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (obj <span class="keyword">instanceof</span> ObjectStreamClass) {</span><br><span class="line"> writeClassDesc((ObjectStreamClass) obj, unshared);</span><br><span class="line"> <span class="comment">// END Android-changed</span></span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (obj <span class="keyword">instanceof</span> String) {</span><br><span class="line"> writeString((String) obj, unshared);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (cl.isArray()) {</span><br><span class="line"> writeArray(obj, desc, unshared);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (obj <span class="keyword">instanceof</span> Enum) {</span><br><span class="line"> writeEnum((Enum<?>) obj, desc, unshared);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (obj <span class="keyword">instanceof</span> Serializable) {</span><br><span class="line"> writeOrdinaryObject(obj, desc, unshared);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">if</span> (extendedDebugInfo) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NotSerializableException(</span><br><span class="line"> cl.getName() + <span class="string">"\n"</span> + debugInfoStack.toString());</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NotSerializableException(cl.getName());</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>因为我们的对象是 Serializable,所以最终会走到 <code>writeOrdinaryObject</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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">writeOrdinaryObject</span><span class="params">(Object obj,ObjectStreamClass desc,<span class="keyword">boolean</span> unshared)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"><span class="comment">// ...</span></span><br><span class="line"><span class="keyword">if</span> (desc.isExternalizable() && !desc.isProxy()) {</span><br><span class="line"> writeExternalData((Externalizable) obj);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> writeSerialData(obj, desc);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>我们看到 <code>writeOrdinaryObject</code> 方法内部做了判断,看当前类是实现的 <code>Externalizable</code> 接口还是 <code>Serializable</code> 接口,因为我们是实现的 <code>Serializable</code> 接口,所以最终走到了 <code>writeSerialData</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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">writeSerialData</span><span class="params">(Object obj, ObjectStreamClass desc)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < slots.length; i++) {</span><br><span class="line"> ObjectStreamClass slotDesc = slots[i].desc;</span><br><span class="line"> <span class="keyword">if</span> (slotDesc.hasWriteObjectMethod()) {</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> curContext = <span class="keyword">new</span> SerialCallbackContext(obj, slotDesc);</span><br><span class="line"> bout.setBlockDataMode(<span class="keyword">true</span>);</span><br><span class="line"> slotDesc.invokeWriteObject(obj, <span class="keyword">this</span>);</span><br><span class="line"> bout.setBlockDataMode(<span class="keyword">false</span>);</span><br><span class="line"> bout.writeByte(TC_ENDBLOCKDATA);</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> curPut = oldPut;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> defaultWriteFields(obj, slotDesc);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">``` </span><br><span class="line"></span><br><span class="line">走到这里就很明确了,我们发现,在 `ObjectOutputStream.writeObject` 过程中,最终会判断,当前类本身是否 `hasWriteObjectMethod()`。</span><br><span class="line"></span><br><span class="line">如果 `hasWriteObjectMethod()` 为 <span class="keyword">true</span>,就通过反射,调用类自带的方法 `slotDesc.invokeWriteObject(obj, <span class="keyword">this</span>);`,点进 `invokeWriteObject` 方法,我们发现内部是通过反射调用的 `writeObjectMethod`,这是一个 `Method` 类型的字段,而给该字段初始化的代码如下:</span><br><span class="line"></span><br><span class="line">```java</span><br><span class="line">writeObjectMethod = getPrivateMethod(cl, <span class="string">"writeObject"</span>, <span class="keyword">new</span> Class<?>[]{ ObjectOutputStream.class }, Void.TYPE);</span><br></pre></td></tr></table></figure><p>最后我们发现,是通过反射调用的实现 Serializable 接口的类的 <code>writeObject</code> 方法,而参数类型是 <code>ObjectOutputStream</code> 类型。</p><p>而如果 <code>hasWriteObjectMethod()</code> 为 false,就使用 <code>defaultWriteFields</code> 完成序列化,也就是系统默认的序列化方法,想了解系统默认序列化方法的可以点进源码自己查看。</p><p>通过同样的步骤,我们可以发现 <code>ObjectInputStream.readObject</code> 方法内部,也判断了类是否有 <code>readObject</code> 方法,有就使用类自己的,没有就使用默认的。</p><p>所以如果我们在使用 Serializable 实现序列化与反序列化是,想实现自定义的序列化和反序列化过程,只需要给当前类添加 <code>writeObject</code> 和 <code>readObject</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></pre></td><td class="code"><pre><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><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">writeObject</span><span class="params">(ObjectOutputStream out)</span> </span>{</span><br><span class="line"> ObjectOutputStream.PutField putFields = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> putFields = out.putFields();</span><br><span class="line"> putFields.put(<span class="string">"name"</span>, name);</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</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><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">readObject</span><span class="params">(ObjectInputStream in)</span> </span>{</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> ObjectInputStream.GetField readFields = in.readFields();</span><br><span class="line"> name = (String) readFields.get(<span class="string">"name"</span>, <span class="string">""</span>);</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (ClassNotFoundException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>认真的同学可能还会有一个疑问,那就是为啥你这自己写的 <code>readObject</code> 方法没有返回值呢?这个方法不应该返回一个当前类对象吗,像 <code>ObjectInputStream.readObject</code> 方法一样?这个问题的答案也可以通过查看源码得到解答,其实反序列化过程可以分为两步,一步是通过反射创建类对象的过程,一个是给创建的对象内的变量赋值的过程,而我们重写的方法只是完成了给当前创建的对象复制的过程,是赋给自身变量的,所以没有返回值,对象创建的过程在 <code>ObjectInputStream.readObject</code> 方法内,可通过源码验证,这也印证了我们上面所说,如果类名发生了变化,那么反序列化是不可能成功的,因为找不到类了。</p><h2 id="四、总结"><a href="#四、总结" class="headerlink" title="四、总结"></a>四、总结</h2><p>经过以上分析,我们可以得出一下结论:</p><ol><li>我们总应该给使用 Serializable 方式实现序列化与反序列化的类指定 serialVersionUID</li><li>我们可以通过给类添加 <code>writeObject(ObjectOutputStream out)</code> 和 <code>readObject(ObjectInputStream in)</code> 方法的方式自定义序列化和反序列化过程</li><li>静态变量和 transient 关键字标注的字段是不参与序列化与反序列化过程的,但是我们仍然可以通过自定义序列化和反序列化的过程打破这个限制,当然也可以通过 Java 提供的另一个序列化接口 <code>Externalizable</code> 来打破这个限制,内部原理差不多</li></ol>]]></content>
<summary type="html">
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>在 Android 开发中,我们经常需要对对象进行序列化与反序列化操作,最常见的就是通过 Intent 传输数据时,Intent 只能传输基
</summary>
</entry>
<entry>
<title>Activity的生命周期和启动模式</title>
<link href="https://madongqiang2201.github.io/2018/10/14/Activity%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E5%92%8C%E5%90%AF%E5%8A%A8%E6%A8%A1%E5%BC%8F/"/>
<id>https://madongqiang2201.github.io/2018/10/14/Activity的生命周期和启动模式/</id>
<published>2018-10-14T06:01:44.000Z</published>
<updated>2018-10-14T07:07:41.902Z</updated>
<content type="html"><![CDATA[<h1 id="Activity-的生命周期和启动模式"><a href="#Activity-的生命周期和启动模式" class="headerlink" title="Activity 的生命周期和启动模式"></a>Activity 的生命周期和启动模式</h1><p>ActivityThread#performLaunchActivity - oncreate、onstart、onrestoreinstancestate、onpostCreate(Called when activity start-up is complete (after {@link #onStart} and {@link #onRestoreInstanceState} have been called). Applications will generally not implement this method; it is intended for system classes to do final initialization after application code has run.)</p><p>Activity 启动过程中最重要的几个类:Instrumentation、ActivityThread、Activity</p>]]></content>
<summary type="html">
<h1 id="Activity-的生命周期和启动模式"><a href="#Activity-的生命周期和启动模式" class="headerlink" title="Activity 的生命周期和启动模式"></a>Activity 的生命周期和启动模式</h1><p>Ac
</summary>
<category term="Android" scheme="https://madongqiang2201.github.io/categories/Android/"/>
<category term="Android" scheme="https://madongqiang2201.github.io/tags/Android/"/>
</entry>
<entry>
<title>Mac搭建Hexo博客及NexT主题配置优化</title>
<link href="https://madongqiang2201.github.io/2016/07/21/Mac%E4%B8%8BHexo%EF%BC%8Bgithub-pages%E6%90%AD%E5%BB%BA%E9%9D%99%E6%80%81%E5%8D%9A%E5%AE%A2/"/>
<id>https://madongqiang2201.github.io/2016/07/21/Mac下Hexo+github-pages搭建静态博客/</id>
<published>2016-07-21T02:59:31.000Z</published>
<updated>2016-07-22T03:06:03.000Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>最近看到<a href="https://www.aswifter.com/" target="_blank" rel="noopener">阳春面</a>的博客,感觉非常漂亮,正好最近也想自己搭个博客,记录一下自己的学习经历和生活感悟,给自己留下点回忆,同时整理一下自己的思路,于是就想仿照着弄一个类似的静态博客网站,正好最近有时间,而且内心搭博客的念头越来越汹涌,所以,说干就干!</p><h2 id="主要内容"><a href="#主要内容" class="headerlink" title="主要内容"></a>主要内容</h2><p>拉到阳春面博客的最下方,发现他的静态博客是Hexo驱动,使用的NexT.Mist主题,而且我非常喜欢这个主题,所以我完全就是冲着阳春面的博客效果去的,所以这片文章主要介绍:</p><p><strong>1. 基于Hexo和github pages搭建静态博客</strong></p><p><strong>2. Next主题配置及优化</strong></p><p>最终目标是实现阳春面博客那样的效果!另外,因为我用的电脑是Mac Pro,所以这篇文章所说的方法都是在mac下才有用的,windows下基本步骤类似,可能只是依赖工具安装方法不同。最后,我还没有申请和绑定自己的域名,所以域名注册和绑定都没有介绍,我认为,在自己真正开始经营博客之前,没有必要花钱注册域名,所以这部分工作留在博客小有名气,有一定流量之后再做!</p><h2 id="基础准备"><a href="#基础准备" class="headerlink" title="基础准备"></a>基础准备</h2><p>好,下面正式开始搭建博客!首先要想使用Hexo和github pages搭建博客,需要以下环境:</p><ol><li>Github账号一枚,并创建一个指定名字的repo</li><li>Homebrew套件管理器,主要用来安装git和node.js</li><li>Git版本管理工具</li><li>node.js</li><li>配置SSH key(可忽略)</li><li>安装Hexo</li><li>同步Hexo博客到github</li><li>NexT主题配置及优化(如果你喜欢别的主题,请忽略)</li></ol><p>这些东西都不熟悉没关系,下面都会详细介绍。</p><h2 id="注册Github账号并创建repo"><a href="#注册Github账号并创建repo" class="headerlink" title="注册Github账号并创建repo"></a>注册Github账号并创建repo</h2><p>因为我们的博客是基于github pages的,也就是博客内容都托管在github pages,所以需要有一个github账号,并且创建一个公开库(repo),用来存放你的博客。Github账号大家应该都有了,俗话说,没有Github 账号的程序员,不是好段子手,身为程序员,不加入这个全球最大的技术(搞基)社区怎么说的过去呢。如果还没有github账号,去<a href="https://github.com/join?source=header-home" target="_blank" rel="noopener">这里</a>申请一个就好了,申请步骤很简单,不再详述,记住选免费服务就可以。在github上创建public库是免费的,也就是传说中的创建开源库。创建private库是要付费的,我们使用github主要就是为了拥抱开源,如果没有特殊需求,创建public库就可以,我们一会儿要创建的博客仓库就是public库。</p><p>申请完账号,登陆之后,就可以创建repo了,点击<code>New repository</code>,会跳转到这个界面:<br><img src="http://oam0f3ifh.bkt.clouddn.com/new_repo.png-bs" alt=""></p><p>需要注意的地方,我都在图上做了标注,这些标注里最需要注意的就是新创建的库的名字,必须是<code>username.github.io</code>,等你创建库的时候,把<code>username</code>换成你的用户名就可以,例如我的用户名是madongqiang2201,那库名就是<code>madongqiang2201.github.io</code>。信息填写完毕,点击<code>create repository</code>就可以把库创建出来。</p><p>要想进一步深入了解github,可以阅读这些资料:</p><p><a href="https://github.com/tiimgreen/github-cheat-sheet/blob/master/README.zh-cn.md" target="_blank" rel="noopener">Github秘籍</a></p><p><a href="http://www.worldhello.net/gotgithub/" target="_blank" rel="noopener">GotGithub</a></p><p><a href="http://stormzhang.com/github/2016/06/19/learn-github-from-zero-summary/" target="_blank" rel="noopener">stormzhang 从0开始学习github系列</a></p><h2 id="安装Homebrew套件管理器"><a href="#安装Homebrew套件管理器" class="headerlink" title="安装Homebrew套件管理器"></a>安装Homebrew套件管理器</h2><p>Homebrew并不是必须的,你也可以通过其他途径安装git和node.js,但是,个人认为Homebrew相当nice,而且在mac下管理安装包特别方便,所以在这里强行安利一波,Homebrew需要你的mac安装了Xcode,很多其他mac应用也需要,所以建议先安装一下,appstore里就有。装完Xcode之后,剩下的步骤就特别简单了,打开mac terminal终端,输入以下命令</p><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/usr/bin/ruby -e <span class="string">"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"</span></span><br></pre></td></tr></table></figure><p>就可以自动完成该工具的安装,如果这条命令失效了,可能是Homebrew更新了安装方式,可以去<a href="http://brew.sh/index_zh-cn.html" target="_blank" rel="noopener">这里</a>查看最新安装命令以及Homebrew的简要介绍。Homebrew安装完成之后,安装git和node.js简直简单的不要不要的。</p><p>Homebrew一些常用命令可以阅读以下资料,深度应用请自行检索:</p><p><a href="http://www.qetee.com/exp/other/homebrew/" target="_blank" rel="noopener">Homebrew常用命令</a></p><p><a href="https://github.com/Homebrew/brew/blob/master/share/doc/homebrew/FAQ.md" target="_blank" rel="noopener">常见问题</a></p><h2 id="安装Git版本管理工具"><a href="#安装Git版本管理工具" class="headerlink" title="安装Git版本管理工具"></a>安装Git版本管理工具</h2><p>Git是一个强大的版本管理工具,Github的版本管理就是基于Git的,现在svn基本过时了,使用Git进行版本管理才是王道。安装完Homebrew之后,安装Git几乎零成本,还是在terminal终端,输入以下命令:</p><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">brew install git</span><br></pre></td></tr></table></figure><p>然后等一段时间就ok了,Homebrew会自动去帮你完成下载安装。</p><p>Git使用教程,可以参考以下资料:</p><p><a href="http://stormzhang.com/github/2016/06/19/learn-github-from-zero-summary/" target="_blank" rel="noopener">stormzhang Git快速应用系列</a></p><p><a href="http://git.oschina.net/progit/" target="_blank" rel="noopener">Pro Git中文版</a></p><h2 id="安装node-js"><a href="#安装node-js" class="headerlink" title="安装node.js"></a>安装node.js</h2><p>Hexo是基于node.js的,所以要让Hexo运行,node.js环境是必不可少的。使用Homebrew安装node.js也特别简单,在terminal终端输入如下命令:</p><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">brew install node</span><br></pre></td></tr></table></figure><p>然后等着Homebrew帮你完成下载安装就可以了,舒爽到爆炸!安装完node.js就可以使用常见的npm命令了。</p><h2 id="配置SSH-key"><a href="#配置SSH-key" class="headerlink" title="配置SSH key"></a>配置SSH key</h2><p>这一步可以忽略,配置SSH key与否,并不影响博客的搭建和使用,只是配置了之后,更新博客方便一点,不用每次都输用户名和密码。</p><h3 id="检查本机上是否存在SSH-key"><a href="#检查本机上是否存在SSH-key" class="headerlink" title="检查本机上是否存在SSH key"></a>检查本机上是否存在SSH key</h3><p>打卡终端,输入如下命令:</p><figure class="highlight ruby"><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">cd .ssh</span><br><span class="line">ls -la</span><br></pre></td></tr></table></figure><p>检查终端输出的文件列表中是否已经存在id_rsa.pub 或 id_dsa.pub 文件,如果文件已经存在,那么你可以跳过步骤2,直接进入步骤3.</p><h3 id="创建一个SSH-key"><a href="#创建一个SSH-key" class="headerlink" title="创建一个SSH key"></a>创建一个SSH key</h3><p>在终端输入以下命令:</p><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ ssh-keygen -t rsa -C <span class="string">"[email protected]"</span></span><br></pre></td></tr></table></figure><p>回车,接着会提示你,让你输入文件名,直接回车会创建使用默认文件名的文件(推荐使用默认文件名);然后会提示你输入两次密码(输入密码之后没有反馈,显示还是空白,但是你确实已经输入了),当然密码也可以不输,直接回车,如果这里没有输入密码,以后提交博客更新的时候就不需要输入密码了。</p><h3 id="添加SSH-key到github"><a href="#添加SSH-key到github" class="headerlink" title="添加SSH key到github"></a>添加SSH key到github</h3><p>经过第二步,如果你没有指定文件名(也就是使用的默认文件名),那么你的.ssh文件夹下,应该有一个id_rsa.pub文件了,打开该文件,复制里面的文本。然后登陆github,点击右上角头像右边的三角图标,点击Settings,然后在左边菜单栏点击SSH and GPG keys,点击new ssh key,title 随便填一个,在key 栏填入你复制的内容,点击add ssh key,就可以添加一个ssh key了,如下图:<br><img src="http://oam0f3ifh.bkt.clouddn.com/ssh_key.png-bs" alt=""></p><h3 id="验证SSH-key是否配置成功"><a href="#验证SSH-key是否配置成功" class="headerlink" title="验证SSH key是否配置成功"></a>验证SSH key是否配置成功</h3><p>在终端输入以下命令:</p><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh -T [email protected]</span><br></pre></td></tr></table></figure><p>如果你创建的key没有设密码的话,直接一顿回车,到最后提示你<br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Hi yourusername! You<span class="string">'ve successfully authenticated, but GitHub does not provide shell access.</span></span><br></pre></td></tr></table></figure></p><p>说明你的ssh key添加成功了。如果过程中提示你perimission deny相关错误,就在命令前加上<code>sudo</code> 然后执行命令的时候输入你的appleid密码应该就可以了。<code>sudo</code>用来说明用管理员权限运行。</p><p>以上简略介绍了怎么配置SHH key,如果想知道命令里面参数的含义,或者配置过程不顺利的话,可以看<a href="http://www.cnblogs.com/ayseeing/p/3572582.html" target="_blank" rel="noopener">这里</a>的详细教程。</p><h2 id="安装Hexo"><a href="#安装Hexo" class="headerlink" title="安装Hexo"></a>安装Hexo</h2><p>经过以上步骤的铺垫,终于到了Hexo安装了,前面我们安装了node.js,装完node之后,我们就可以使用npm命令了,而Hexo安装就是使用npm,在终端输入以下命令:</p><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install -g hexo</span><br></pre></td></tr></table></figure><p>然后等待一会儿,hexo会自动完成下载安装。Hexo安装完成之后,在你喜欢的位置随意创建一个文件夹,这个文件夹以后就是你存放本地博客的地方了,通过<code>cd filepath</code>(filepath替换成你创建的文件夹目录)命令,进入到你创建的文件夹目录,然后执行以下命令:</p><figure class="highlight ruby"><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">hexo init</span><br><span class="line">npm install</span><br></pre></td></tr></table></figure><p>这样Hexo会在该文件夹创建本地博客所需的一切资源。这样本地博客就搭建好了,输入以下命令:</p><figure class="highlight ruby"><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">hexo g /<span class="regexp">/ 全拼是:hexo generate,可以简写成 hexo g</span></span><br><span class="line"><span class="regexp">hexo s /</span><span class="regexp">/ 全拼是:hexo server,可以简写成 hexo s</span></span><br></pre></td></tr></table></figure><p>这样就开启了一个本地博客服务器,打开浏览器,在地址栏输入<code>localhost:4000</code>,就可以查看本地博客了,hexo默认生成了一片hello world博客。注意,以上hexo开头的命令,执行目录必须是你创建的博客文件夹目录。</p><h2 id="同步Hexo博客到Github"><a href="#同步Hexo博客到Github" class="headerlink" title="同步Hexo博客到Github"></a>同步Hexo博客到Github</h2><p>现在你已经可以在本机查看你的博客了,但是要想让别人通过网络可以查看你的博客,还需要一步,那就是将你的博客发布到github仓库。在terminal终端,将当前目录切换到你的本地博客目录,执行以下命令:</p><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install hexo-deployer-git --save</span><br></pre></td></tr></table></figure><p>安装完成之后,打开本地博客目录的<code>_config.yml</code>文件,编辑其中的deploy节点:</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></pre></td><td class="code"><pre><span class="line">deploy:</span><br><span class="line"> type: git</span><br><span class="line"> repo: [email protected]:yourusername/youusername.github.io.git</span><br><span class="line"> branch: master</span><br></pre></td></tr></table></figure><p>将上面<code>yourusername</code>替换成你的github用户名即可,你也可以去你开始的时候创建的名为<code>yourusername.github.io</code>的仓库去直接复制完整的地址,如下图:<br><img src="http://oam0f3ifh.bkt.clouddn.com/clone_address.png-bs" alt=""><br>当前复制出来的值,就是通过SSH方式clone的地址,配置完成后,以后提交博客更新不用输用户名和密码(如果你ssh key没有设置密码的话);点击上图右上角<code>Use HTTPS</code>,复制出来的clone地址也可以配置到repo,但是这样,提交更新的时候,就需要输入用户名和密码了。</p><p>保存配置之后,在本地博客目录执行以下命令:</p><figure class="highlight ruby"><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">hexo clean /<span class="regexp">/ clean本地项目,防止缓存</span></span><br><span class="line"><span class="regexp">hexo g /</span><span class="regexp">/ 根据你编辑的md格式的博客,生成静态网页</span></span><br><span class="line"><span class="regexp">hexo d /</span><span class="regexp">/ 将本地博客发布到github</span></span><br></pre></td></tr></table></figure><p>然后,在浏览器地址栏输入<code>yourusername.github.io</code>就可以访问你的博客了,别人也可以通过这个地址访问你的博客。</p><p>如果想了解Hexo常用命令可以点击<a href="https://hexo.io/zh-cn/docs/commands.html" target="_blank" rel="noopener">这里</a>,Hexo常用命令没几个,常用的有创建新博客、clean、生成静态文件、发布等,上述官方文档有详细介绍,这里记录几个我经常用到的:</p><figure class="highlight ruby"><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">hexo init /<span class="regexp">/在指定目录执行该命令,会将当前目录初始化为hexo站点,生成hexo站点所需的一切文件</span></span><br><span class="line"><span class="regexp">hexo new “my new blog title” /</span><span class="regexp">/新建一篇文章。如果没有设置 layout 的话,默认使用 _config.yml 中的 default_layout 参数代替。如果标题包含空格的话,请使用引号括起来。</span></span><br><span class="line"><span class="regexp">hexo clean /</span><span class="regexp">/ 清除缓存,如果对本地文件做了修改,同步到远程验证修改的效果之前,先clean,清除缓存</span></span><br><span class="line"><span class="regexp">hexo generate /</span><span class="regexp">/ 可以简写成hexo g 根据markdown文件生成静态文件</span></span><br><span class="line"><span class="regexp">hexo server /</span><span class="regexp">/ 或者简写成hexo s 启动本地hexo 服务器,默认localhost:4000可以访问</span></span><br><span class="line"><span class="regexp">hexo deploy /</span><span class="regexp">/ 或者简写成hexo d 将本地修改,部署到远端</span></span><br><span class="line"><span class="regexp">hexo version /</span><span class="regexp">/ 显示hexo版本</span></span><br></pre></td></tr></table></figure><h2 id="NexT主题配置及优化"><a href="#NexT主题配置及优化" class="headerlink" title="NexT主题配置及优化"></a>NexT主题配置及优化</h2><p>NexT主题是一套简约的主题,设置完成之后,就像<a href="https://madongqiang2201.github.io/">我的博客</a>现在的样子,NexT主题的详细配置请看<a href="http://theme-next.iissnan.com/getting-started.html" target="_blank" rel="noopener">这里</a>,这个是NexT主题作者维护的配置文档,作者是国人,所以文档是中文的,而且写的非常详细,对照文档,所有功能都能轻松实现。等你配置完成后,你的博客将拥有评论系统,访问次数统计,站内搜索,代码高亮,百度统计,社交分享(分享到微博,微信,qq等)等等强大的功能。官方文档很详细,我就不再赘述了。</p><h2 id="其他遗漏的点"><a href="#其他遗漏的点" class="headerlink" title="其他遗漏的点"></a>其他遗漏的点</h2><p><strong>1.如何删除一篇博文</strong></p><p>当然,我们辛辛苦苦写了博文,一般是不会删除的,最多修改一下,但是我们搭建的过程中或者刚搭建好个人博客站点,可能一激动就发了好多测试博文,如果想删除这类文章,在Finder中,找到本地博客所在目录,找到<code>/source/_posts</code>文件夹,里面放了所有我们写的博客,想删除哪篇,直接在这里删除,然后再重新发布到github,这篇博文就不见了</p><p><strong>2.fork me on github</strong></p><p>如果你访问<a href="https://madongqiang2201.github.io/">我的个人博客</a>,你会发现右上角有一个倾斜的<code>fork me on github</code> 图标,想要集成这个图标,只需要去<a href="https://github.com/blog/273-github-ribbons" target="_blank" rel="noopener">这里</a>挑选你喜欢的样式,把样式代码复制过来,然后打开你本地博客目录下的<code>themes/next/layout/layout.swig</code>文件,然后把你复制过来的样式代码粘贴到如下位置:</p><figure class="highlight html"><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="tag"><<span class="name">body</span> <span class="attr">itemscope</span> <span class="attr">itemtype</span>=<span class="string">"http://schema.org/WebPage"</span> </span></span><br><span class="line"><span class="tag"> // <span class="attr">...</span></span></span><br><span class="line"><a href="https://github.com/madongqiang2201"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://camo.githubusercontent.com/a6677b08c955af8400f44c6298f40e7d19cc5b2d/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f677261795f3664366436642e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png"></a></span><br><span class="line"> <span class="tag"><<span class="name">header</span> <span class="attr">id</span>=<span class="string">"header"</span> <span class="attr">class</span>=<span class="string">"header"</span> <span class="attr">itemscope</span> <span class="attr">itemtype</span>=<span class="string">"http://schema.org/WPHeader"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"header-inner"</span>></span> {%- include '_partials/header.swig' %} <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">header</span>></span></span><br><span class="line"> // ...</span><br></pre></td></tr></table></figure><p>其中哪个超链接就是复制的样式代码,粘贴位置在body内<code>header</code>标签之上。</p><p><strong>3.给博文添加tag和分类</strong><br>使用如下命令:</p><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo new <span class="string">"blog title"</span></span><br></pre></td></tr></table></figure><p>创建的新博文文件,打开之后顶部会有一段自动生成的文本,在其中加入tag和category标签即可指定tag和分类。</p><figure class="highlight html"><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></pre></td><td class="code"><pre><span class="line">---</span><br><span class="line">title: blog title</span><br><span class="line">date: 2016-07-20 10:59:31</span><br><span class="line">tag: hexo // 指定本篇文章tag标签</span><br><span class="line">category: hexo // 指定本片文章分类</span><br><span class="line">---</span><br></pre></td></tr></table></figure><p><strong>4.手动实现某条博文置顶</strong><br>Next主题没有博文置顶相关设置(或许这个功能Hexo应该提供,但我分不清),但是我发现发布的博文是根据发布日期倒序排序的,即:越早发布的,排的越靠后!而发布日期,我们可以通过博文的头部<code>date</code>字段指定:</p><figure class="highlight html"><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></pre></td><td class="code"><pre><span class="line">---</span><br><span class="line">title: blog title</span><br><span class="line">date: 2016-07-20 10:59:31 // 指定发布日期</span><br><span class="line">tag: hexo </span><br><span class="line">category: hexo </span><br><span class="line">---</span><br></pre></td></tr></table></figure><p>所以我们可以给想要置顶的博文,指定一个将来的日期,这样就可以让这篇博文一直排在别的博文前面,达到手工置顶的目的!但是要注意:对于已经发布的博文,发布日期和文件名称(不是title字段的值,而是md文件名)是该文章访问url的组成部分,也就意味着,已经发布的文章如果改了发布日期,针对这篇文章的链接就都不能用了,而且浏览统计等信息都会受到影响,所以手工置顶应该慎重使用!</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>Hexo博客至此搭建完毕,并且应用了简约美丽的NexT.Mist主题,但是仍有一些不足之处,例如没有通过正常渠道博文置顶功能;该主题的主页过于简单,没有边栏,导致主页展示的有效信息减少,不利于访客浏览,也不利于推广自己的其它渠道,这可能就是简约付出的代价,主题作者以后可能也会改进吧!如果不喜欢这个主题,可以参看一下<a href="http://www.kymjs.com/" target="_blank" rel="noopener">开源实验室</a>或者<a href="http://stormzhang.com/" target="_blank" rel="noopener">stormzhang</a>的个人博客主题,我感觉这两个都不错。但是最重要的还是博客要有内容,没有内容,再好的个人站点也没有意义!所以样式先这样吧,这段时间先写技术文章,如果以后自己开始认真经营博客了,再绑定域名和优化样式。最后,如果大家有什么问题,欢迎留言讨论!</p><h2 id="关于我"><a href="#关于我" class="headerlink" title="关于我"></a>关于我</h2><p><a href="https://github.com/madongqiang2201" target="_blank" rel="noopener">我的Github</a></p><p><a href="https://madongqiang2201.github.io/">我的个人博客</a></p><p><a href="http://www.jianshu.com/users/a5a6afe1c044/timeline" target="_blank" rel="noopener">我的简书</a></p><p><a href="http://blog.csdn.net/u011172283" target="_blank" rel="noopener">我的CSDN</a></p>]]></content>
<summary type="html">
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>最近看到<a href="https://www.aswifter.com/" target="_blank" rel="noopener"
</summary>
<category term="hexo" scheme="https://madongqiang2201.github.io/categories/hexo/"/>
<category term="hexo" scheme="https://madongqiang2201.github.io/tags/hexo/"/>
</entry>
</feed>