Android中,怎么优雅的生成代码?

前言

在前面的Android6.0权限处理不再复杂文章中,介绍过一个开源框架PermissionsDispatcher(权限调度者)框架,基于该框架的条件下,有了介绍注解以及注解APT的两篇文章,分别是:

Android进阶之Annotation(注解)的使用

Android编译时,怎么自动生成代码?

【Android编译时,怎么自动生成代码?】这篇文章的结尾中,提到过可以使用JavaPoet来优雅的生成代码。那今天我们的主要内容就是来介绍一下【JavaPoet】该开源框架。

环境的搭建

1,新建项目名为【myJavaPoet】的Android项目;
2,在其中新建Module名为【poet】的模块,选择【Java Library】,如下:

Java Library

PS:

JavaPoet必须在Java Library中使用,例如在rt.jar包中的javax包属于Android核心库中没有,所以不能直接在app Module和Android Library中使用,必须要创建一个Java Library,然后由Java Library导出jar包使用,如下图:

rt.jar

3,在【poet.build.gradle】中,添加如下信息:

dependencies {
    compile 'com.squareup:javapoet:1.8.0'
}

完成后的项目目录结构如下:

项目目录结构

下面开始讲例子,希望看例子的时候,注释切记一定要多注意看~~~

例子1,PoetHello

主要讲的是类、方法的生成,在其中添加修饰、返回类型、抽象方法,以及如何写入文件系统等等。。。

PoetHello的代码如下:

package com.example;


import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;

import java.io.File;

import javax.lang.model.element.Modifier;

/**
 * 使用JavaPoet写一个Hello 2017/4/24 11:01
 */
public class PoetHello {

    /**
     * 生成器 2017/4/24 14:49
     */
    public static void product() {
        try {

            // 创建方法 2017/4/24 14:26
            MethodSpec method = MethodSpec.methodBuilder("hello")
                    .addModifiers(Modifier.PUBLIC) // 修饰符
                    .returns(String.class) // 返回类型
                    .addParameter(String.class, "name", Modifier.FINAL) // 添加final参数 2017/4/25 09:03
                    .addStatement("String say") // 负责分号、换行 2017/4/24 14:52
                    .addStatement("say = $S + name", "Hello ")
                    .addStatement("return say")
                    .build();

            // 抽象方法 2017/4/24 17:03
            MethodSpec abstractMethod = MethodSpec.methodBuilder("abstractHello")
                    .addModifiers(Modifier.ABSTRACT, Modifier.PROTECTED)
                    .build();

            // 创建类
            TypeSpec hello = TypeSpec.classBuilder("Hello")
                    .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
                    .addMethod(method) // 添加方法
                    .addMethod(abstractMethod)
                    .build();

            // 写入文件系统 2017/4/24 14:27
            JavaFile javaFile = JavaFile.builder("com.example.all_product", hello)
                    .build();

            javaFile.writeTo(new File("poet/src/main/java")); // 指定文件路径
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        PoetHello.product();
    }

}

生成的Hello.java类,代码如下:

package com.example.all_product;

import java.lang.String;

public abstract class Hello {
  public String hello(String name) {
    String say;
    say = "Hello " + name;
    return say;
  }

  protected abstract void abstractHello();
}

例子2,PoetFor

主要讲的就是beginControlFlow() 、endControlFlow()的配合使用,提供换行符与缩进。以for循环为例子,其它使用方法类似,如if、while、switch等等。。。

其中还有$S、$T、$N、$L的使用,意思分别如下:

$S for Strings

顾名思义,$S代表的是String,将其看成是一个字符创即可。

$T for Types

这里的Type/类型,其实可以简单的理解成我们的Class类即可。

$N for Names

可以理解成引用另一个变量名即可。

$L for Literals

这个刚开始其实是比较不好理解,但场景使用多了就应该慢慢能理解了,在这里其实就可以简单的理解成【Formatter】即可。

PoetFor代码如下(切记看注释):

package com.example;

import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;

import java.io.File;

import javax.lang.model.element.Modifier;

/**
 * 生成for代码 2017/4/24 14:57
 */
public class PoetFor {

    /**
     * for循环生成器 2017/4/24 14:57
     */
    public static void product(int from, int to) {
        try {

            // 创建全局字段,并初始化 2017/4/25 09:15
            FieldSpec fieldSpec = FieldSpec.builder(String.class, "DESC")
                    .addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL)
                    .initializer("$S", "Sum is ")
                    .build();

            // 生成方法 2017/4/24 15:09
            MethodSpec methodSpec = MethodSpec.methodBuilder("forInteger")
                    .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                    .returns(void.class) // 无返回值
                    .addStatement("int sum = 0")

                    // beginControlFlow() + endControlFlow() 需要一起使用,提供换行符和缩进。 2017/4/24 15:09
                    // $L 占位符,类似于Formatter,替换int类型 2017/4/24 15:25
                    .beginControlFlow("for (int i = $L; i <= $L; i++)", from, to)
                    .addStatement("sum += i")
                    .endControlFlow()

                    // $T 替换类名   $S 替换字符串 2017/4/24 15:31
                    // 使用System会自动import使用 2017/4/24 15:34
                    .addStatement("$T.out.println($N + sum)", System.class, "DESC")
                    .build();

            // 类生成 2017/4/24 15:10
            TypeSpec typeSpec = TypeSpec.classBuilder("ForInteger")
                    .addModifiers(Modifier.PUBLIC)
                    .addMethod(methodSpec)
                    .addField(fieldSpec)
                    .build();

            // 文件生成 2017/4/24 15:10
            JavaFile javaFile = JavaFile.builder("com.example.all_product", typeSpec)
                    .addFileComment("JavaPoet生成For循环代码 2017/4/24 15:07")
                    .build();

            javaFile.writeTo(new File("poet/src/main/java"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        PoetFor.product(0, 10);
    }

}

生成的ForInteger.java类如下:

// JavaPoet生成For循环代码 2017/4/24 15:07
package com.example.all_product;

import java.lang.String;
import java.lang.System;

public class ForInteger {
  private static final String DESC = "Sum is ";

  public static void forInteger() {
    int sum = 0;
    for (int i = 0; i <= 10; i++) {
      sum += i;
    }
    System.out.println(DESC + sum);
  }
}

例子3,PoetList

主要讲的是ClassName的硬指定,以及引用指定;然后再讲了使用ParameterizedTypeName.get(ClassName, ClassName)创建List<Object>泛型的使用。

PoetList的代码如下:

package com.example;

import com.example.all_product.ForInteger;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;

import java.io.File;

import javax.lang.model.element.Modifier;

/**
 * 使用ClassName(重要),生成List代码 2017/4/24 16:04
 */
public class PoetList {

    /**
     * 生成器 2017/4/24 16:04
     */
    public static void product() {
        try {

            // list泛型的类型 2017/4/24 16:06
            ClassName type = ClassName.get("com.example.all_product", "ForInteger");

            // List类型
            ClassName list = ClassName.get("java.util", "List");

            // ArrayList类型
            ClassName arrayList = ClassName.get("java.util", "ArrayList");

            // 生成泛型类型,类型的名称、参数的名称 2017/4/24 16:08
            TypeName listType = ParameterizedTypeName.get(list, type);

            MethodSpec methodSpec = MethodSpec.methodBuilder("listType")
                    .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                    .returns(listType)
                    .addStatement("$T lstHello = new $T<>()", listType, arrayList)

                    // ClassName类的绝对路径,内部利用该路径进行反射获取实体类,使用场景是当该类也是生成类时,可以硬指定 2017/4/24 16:18
                    .addStatement("lstHello.add(new $T())", type) // ClassName指定
                    .addStatement("lstHello.add(new $T())", ForInteger.class) // 引用指定
                    .addStatement("return lstHello")
                    .build();

            TypeSpec typeSpec = TypeSpec.classBuilder("ListType")
                    .addModifiers(Modifier.PUBLIC)
                    .addMethod(methodSpec)
                    .build();

            JavaFile javaFile = JavaFile.builder("com.example.all_product", typeSpec)
                    .build();

            javaFile.writeTo(new File("poet/src/main/java"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        PoetList.product();
    }

}

生成的ListType.java类,代码如下:

package com.example.all_product;

import java.util.ArrayList;
import java.util.List;

public class ListType {
  public static List<ForInteger> listType() {
    List<ForInteger> lstHello = new ArrayList<>();
    lstHello.add(new ForInteger());
    lstHello.add(new ForInteger());
    return lstHello;
  }
}

例子4,PoetMap

上面例子3讲的是List<Object>的使用,那么下面再来讲一下Map<Key, Value>的创建使用。

PoetMap的代码如下:

package com.example;

import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;

import java.io.File;

import javax.lang.model.element.Modifier;

/**
 * 使用ClassName(重要),生成Map代码 2017/4/25 13:39
 */
public class PoetMap {

    /**
     * 生成器 2017/4/25 13:39
     */
    public static void product() {
        try {

            // list泛型的类型 2017/4/24 16:06
            ClassName type = ClassName.get("com.example.all_product", "ForInteger");

            // key 2017/4/25 13:38
            ClassName string = ClassName.get("java.land", "String");

            // map类型
            ClassName map = ClassName.get("java.util", "Map");

            // HashMap类型
            ClassName hashMap = ClassName.get("java.util", "HashMap");

            // 生成Map类型,类型的名称、Key、Value 2017/4/25 14:08
            TypeName listType = ParameterizedTypeName.get(map, string, type);

            MethodSpec methodSpec = MethodSpec.methodBuilder("listType")
                    .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                    .returns(listType)
                    .addStatement("$T mapHello = new $T<>()", listType, hashMap)
                    .addStatement("mapHello.put($S, new $T())", "key", type)
                    .addStatement("return mapHello")
                    .build();

            TypeSpec typeSpec = TypeSpec.classBuilder("MapType")
                    .addModifiers(Modifier.PUBLIC)
                    .addMethod(methodSpec)
                    .build();

            JavaFile javaFile = JavaFile.builder("com.example.all_product", typeSpec)
                    .build();

            javaFile.writeTo(new File("poet/src/main/java"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        PoetMap.product();
    }

}

生成的MapType.java,代码如下:

package com.example.all_product;

import java.util.HashMap;
import java.util.Map;

public class MapType {
  public static Map<String, ForInteger> listType() {
    Map<String, ForInteger> mapHello = new HashMap<>();
    mapHello.put("key", new ForInteger());
    return mapHello;
  }
}

例子5,PoetInterface

该例子讲的是利用JavaPoet来生成接口,使用的是TypeSpec.interfaceBuilder(InterfaceName)方法来创建接口类,也可以使用TypeSpec中的其它方法来创建枚举、注解等等。。。

PoetInterface的代码如下:

package com.example;

import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;

import java.io.File;

import javax.lang.model.element.Modifier;

/**
 * 生成接口 2017/4/25 09:16
 */
public class PoetInterface {

    /**
     * 生成器 2017/4/25 09:40
     */
    public static void product() {

        try {

            // 生成方法,必须有Modifier.ABSTRACT或STATIC 2017/4/25 09:25
            MethodSpec methodSpec = MethodSpec.methodBuilder("getName")
                    .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
                    .addJavadoc("获取名称\n") // 添加注释 2017/4/25 11:24
                    .returns(String.class)
                    .build();

            // 生成字段,必须同时有Modifier.STATIC, Modifier.FINAL 2017/4/25 09:31
            FieldSpec fieldSpec = FieldSpec.builder(String.class, "name")
                    .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
                    .initializer("$S", "CCB")
                    .build();

            // interfaceBuilder方法标志生成接口类 2017/4/25 09:25
            TypeSpec typeSpec = TypeSpec.interfaceBuilder("UserInterface")
                    .addModifiers(Modifier.PUBLIC)
                    .addMethod(methodSpec)
                    .addField(fieldSpec)
                    .build();

            // 写入文件
            JavaFile javaFile = JavaFile.builder("com.example.all_product", typeSpec)
                    .addFileComment("Poet生成接口 2017/4/25 09:24")
                    .build();

            javaFile.writeTo(new File("poet/src/main/java"));
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public static void main(String[] args) {
        PoetInterface.product();
    }

}

生成的UserInterface.java接口类,代码如下:

// Poet生成接口 2017/4/25 09:24
package com.example.all_product;

import java.lang.String;

public interface UserInterface {
  String name = "CCB";

  /**
   * 获取名称
   */
  String getName();
}

例子6,PoetSort

主要讲的就是怎么创建匿名类。该例子先自动创建一个实体,再引用该实体类做sort排序。

PoetSort的代码如下:

package com.example;

import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeSpec;

import java.io.File;
import java.util.Collections;

import javax.lang.model.element.Modifier;

/**
 * 写匿名类进行排序 2017/4/25 09:39
 */
public class PoetSort {

    public static void product() {
        try {

            // 生成实体 2017/4/25 09:41
            TypeSpec typeEntity = TypeSpec.classBuilder("UserEntity")
                    .addModifiers(Modifier.PUBLIC)
                    .addField(FieldSpec.builder(String.class, "name")
                            .addModifiers(Modifier.PRIVATE)
                            .build())
                    .addMethod(MethodSpec.methodBuilder("getName")
                            .addModifiers(Modifier.PUBLIC)
                            .returns(String.class)
                            .addStatement("return this.$N", "name")
                            .build())
                    .addMethod(MethodSpec.methodBuilder("setName")
                            .addModifiers(Modifier.PUBLIC)
                            .addParameter(String.class, "name")
                            .returns(void.class)
                            .addStatement("this.$N = $N", "name", "name")
                            .build())
                    .addField(FieldSpec.builder(int.class, "time")
                            .addModifiers(Modifier.PRIVATE)
                            .build())
                    .addMethod(MethodSpec.methodBuilder("getTime")
                            .addModifiers(Modifier.PUBLIC)
                            .returns(int.class)
                            .addStatement("return this.$N", "time")
                            .build())
                    .build();

            // 写入用户实体 2017/4/25 09:48
            JavaFile javaUserEntity = JavaFile.builder("com.example.all_product", typeEntity)
                    .build();

            javaUserEntity.writeTo(new File("poet/src/main/java"));

            // 生成排序匿名类 2017/4/25 09:49
            ClassName classComparator = ClassName.get("java.util", "Comparator"); // 指向Comparator
            ClassName classList = ClassName.get("java.util", "List"); // 指向List
            ClassName classUser = ClassName.get("com.example.all_product", "UserEntity"); // 指向User实体

            // 匿名比对类 2017/4/25 09:52
            TypeSpec typeCompare = TypeSpec.anonymousClassBuilder("")
                    .addSuperinterface(ParameterizedTypeName.get(classComparator, classUser))
                    .addMethod(MethodSpec.methodBuilder("compare")
                            .addAnnotation(Override.class) // 添加注解 2017/4/25 10:56
                            .addModifiers(Modifier.PUBLIC)
                            .addParameter(classUser, "obj1")
                            .addParameter(classUser, "obj2")
                            .returns(int.class)
                            .beginControlFlow("if ($N.$N() > $N.$N())",
                                    "obj1", "getTime", "obj2", "getTime")
                            .addStatement("return 1")
                            .endControlFlow()
                            .beginControlFlow("else if ($N.$N() < $N.$N())",
                                    "obj1", "getTime", "obj2", "getTime")
                            .addStatement("return -1")
                            .endControlFlow()
                            .beginControlFlow("else")
                            .addStatement("return 0")
                            .endControlFlow()
                            .build())
                    .build();

            // 外部类 2017/4/25 09:59
            TypeSpec typeSort = TypeSpec.classBuilder("UserSort")
                    .addModifiers(Modifier.PUBLIC)
                    .addMethod(MethodSpec.methodBuilder("sort")
                            .addModifiers(Modifier.PUBLIC)
                            .returns(void.class)
                            .addParameter(ParameterizedTypeName.get(classList, classUser), "lstUsers")
                            .addStatement("$T.sort($N, $L)", Collections.class, "lstUsers", typeCompare)
                            .build())
                    .build();

            // 写入排序类 2017/4/25 10:03
            JavaFile javaUserSort = JavaFile.builder("com.example.all_product", typeSort)
                    .build();

            javaUserSort.writeTo(new File("poet/src/main/java"));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        PoetSort.product();
    }

}

生成的UserEntity.java和UserSort.java类的代码如下:

package com.example.all_product;

import java.lang.String;

public class UserEntity {
  private String name;

  private int time;

  public String getName() {
    return this.name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public int getTime() {
    return this.time;
  }
}

package com.example.all_product;

import java.lang.Override;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class UserSort {
  public void sort(List<UserEntity> lstUsers) {
    Collections.sort(lstUsers, new Comparator<UserEntity>() {
      @Override
      public int compare(UserEntity obj1, UserEntity obj2) {
        if (obj1.getTime() > obj2.getTime()) {
          return 1;
        }
        else if (obj1.getTime() < obj2.getTime()) {
          return -1;
        }
        else {
          return 0;
        }
      }
    });
  }
}

例子7,PoetExtend

主要就讲一下怎么使用superclass(ClassName)的方法来创建继承的子类,同理,也可以使用addSuperinterface(ClassName)的方法来创建实现接口,实现接口后,怎么重写接口的方法,可参考例子5。。。

PoetExtend的代码如下:

package com.example;

import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;

import java.io.File;

import javax.lang.model.element.Modifier;

/**
 * 生成继承的子类 2017/4/25 14:48
 */
public class PoetExtend {

    public static void product() {
        try {

            // 生成实体 2017/4/25 14:48
            TypeSpec typeEntity = TypeSpec.classBuilder("SubUserEntity")
                    .addModifiers(Modifier.PUBLIC)

                    // 继承UserEntity类 2017/4/25 14:58
                    .superclass(ClassName.get("com.example.all_product", "UserEntity"))

                    // 实现UserInterface接口
                    .addSuperinterface(ClassName.get("com.example.all_product", "UserInterface"))
                    .addField(FieldSpec.builder(int.class, "id")
                            .addModifiers(Modifier.PRIVATE)
                            .build())
                    .addMethod(MethodSpec.methodBuilder("getId")
                            .addModifiers(Modifier.PUBLIC)
                            .returns(int.class)
                            .addStatement("return this.$N", "id")
                            .build())
                    .build();

            // 写入用户实体 2017/4/25 14:55
            JavaFile javaUserEntity = JavaFile.builder("com.example.all_product", typeEntity)
                    .build();

            javaUserEntity.writeTo(new File("poet/src/main/java"));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        PoetExtend.product();
    }

}

生成的SubUserEntity代码如下:

package com.example.all_product;

public class SubUserEntity extends UserEntity implements UserInterface {
  private int id;

  public int getId() {
    return this.id;
  }
}

总结

怎么动态的生成java代码,我们今天主要讲7个例子就好了,在我们写项目时,如果需要动态生成代码时,这应该足够应付80%的开发工作了,如果需要深入创建更复杂的代码,请移步参考JavaPoet开源框架。

结合前面几篇文章,就已经包含了创建注解、注解解析、代码生成,慢慢。。。慢慢。。。我们向自己写框架靠近。。。其实框架中经常使用的还有另一个检查工具,lint。我们可以自定义lint的检查规则,不过,我现在有一个地方卡住了,还没解决,后面如果解决了,有机会就一并讲一下。

今天就讲到这里了。。。

谢谢支持~~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • 撕裂的容颜下金黄的麦田 悬崖峭壁的掌换来汗珠融成的墙 黄泥画上的脸予我一生思恋与担忧
    一身污秽阅读 169评论 0 1
  • "我曾經很愛很愛過xxx…" 這句話不知道聽身邊多少個朋友說起過 然後有的人因無法忘懷導致自己無法自拔 也有的人比...
    2f6148dd3a94阅读 175评论 0 1
  • 自从好友问过我,生完娃最大的感受是什么? 我就一直在琢磨,除了生理上的变化,有什么看法和以前不同了呢? 我想来想去...
    余小头阅读 337评论 0 1