DataBinding學(xué)習(xí)與實踐

搞了搞DataBinding瘸洛,并在項目新模塊中進行了使用,感覺還是不錯的只损,這里記錄下使用過程及基本原理,方便以后查閱七咧。

干啥的啊

DataBinding是啥跃惫?
一個Google官方的數(shù)據(jù)綁定框架-Data Binding Library,是對MVVM在Android上的一種實現(xiàn)艾栋,可以直接綁定數(shù)據(jù)到xml中爆存,并實現(xiàn)自動刷新。

MVVM 又是啥蝗砾?
MVVM是 Model-View-ViewModel的縮寫先较。三部分分別是:Model – 代表你的基本業(yè)務(wù)邏輯;View – 顯示內(nèi)容悼粮;ViewModel – 將前面兩者聯(lián)系在一起的對象闲勺。MVVM 在使用當(dāng)中,通常還會利用雙向綁定技術(shù)即: Model 變化時扣猫,ViewModel 會自動更新菜循,而 ViewModel 變化時,View 也會自動變化苞笨。

1债朵、準備工作

在Module的build.gradle android模塊中添加

android {
 …
 dataBinding {
    enabled = true
 }
}

在布局Layout外面添加子眶,<layout></layout>標簽,示例如下:

<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

  <RelativeLayout
     android:id="@+id/activity_main"
     android:layout_width="match_parent"
     android:layout_height="match_parent">

     <TextView
         android:id="@+id/tvHelloWorld"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="Hello World!" />
  </RelativeLayout>
</layout>

好序芦,準備到這里呢臭杰,我們就可以在Activity或者Fragment中使用DataBinding了。

2谚中、在Activity渴杆、Fragment中如何初始化Binding類
 @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //setContentView(R.layout.activity_main);
    ActivityMainBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
}

 @Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    FragmentBinding inflate = DataBindingUtil.inflate(inflater, R.layout.fragment, container, false);
    return inflate.getRoot();
}

分別在Activity和Fragment中分別初始化了Binding類,可以看到宪塔,我們Binding類的生成是有規(guī)則的:activity_main-->ActivityMainBinding 磁奖、fragment-->FragmentBinding(不要忘記分別給這兩個布局加<layout>標簽),即:第一個單詞首字母大寫某筐,第二個單詞首字母大寫...最后都會拼上Binding就是生成的Binding類比搭。
如何自定義生成的Binding類名呢?如下:

<layout xmlns:android="http://schemas.android.com/apk/res/android">
 <data class="CustomBindingName">
 </data>
 ...
</layout>

然后我們在生成Binding類的時候就可以:

CustomBindingName inflate = DataBindingUtil.inflate(inflater, R.layout.fragment, container, false);

初始化完Binding類之后南誊,我們就可以直接使用該layout中定義了id的View身诺,如:

viewDataBinding.tvHelloWolrd.setText("厲害了");

為什么可以直接拿來操作呢,因為DataBinding已經(jīng)幫我們初始化好了(具體怎么初始化的下一篇再說抄囚,這篇就講基本使用啦)霉赡,這個已經(jīng)初始化好的View的命名和Binding類的生成命名規(guī)則相同,只是后面沒有加Binding了幔托。

3穴亏、數(shù)據(jù)綁定
3.1、基本數(shù)據(jù)綁定

修改activity_main.xml文件如下(注意:這里不用判斷bean重挑!=null嗓化,因為DataBinding會自動幫助我們進行空指針的避免,比如@{bean.name}谬哀,如果bean是null的話蟆湖,bean.name則會被賦默認值(null)。age的話玻粪,則是0):

<layout xmlns:android="http://schemas.android.com/apk/res/android">
 <data>
    <variable
        name="bean"
        type="com.thc.bindingdemo.BindingBean" />
 </data>
 <LinearLayout
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tvHelloWolrd"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />

    <TextView
        android:id="@+id/tvName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{bean.name}" />

    <TextView
        android:id="@+id/tvAge"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{String.valueOf(bean.age)}" />
 </LinearLayout>
</layout>

在java代碼中:

BindingBean bindingBean = new BindingBean("thc",18);
//viewDataBinding.setVariable(com.thc.bindingdemo.BR.bean,demoBean);
viewDataBinding.setBean(demoBean);

(以上兩種方式都可以)這樣通過生成的Binding類給xml文件setBean就實現(xiàn)了View和Data的綁定。這樣只能夠?qū)崿F(xiàn)給xml進行設(shè)置數(shù)據(jù)诬垂,但是View如何實現(xiàn)根據(jù)Data的變化實時更新呢劲室?
就是讓我們的Model extends BaseObservable,如果想更新單個屬性就在該屬性set方法中使用

//更新單個屬性
notifyPropertyChanged(com.thc.bindingdemo.BR.school);
//更新所有的屬性
notifyChange();
//定義的Bean如下:
public class BindingDemoBean extends BaseObservable {
 private String name;
 private String school;
 private String className;
 public BindingDemoBean(String name, String school,String className) {
     this.name = name;
     this.school = school;
      this.className = className;
 }
 public String getName() {
    return name;
 }
 public void setName(String name) {
     this.name = name;
     //更新所有的屬性
     notifyChange();
 }
 @Bindable
 public String getSchool() {
     return school;
 }
 public void setSchool(String school) {
     this.school = school;
     //更新單個屬性
     notifyPropertyChanged(com.thc.bindingdemo.BR.school);
 }
 public String getClassName() {
     return className;
 }
 public void setClassName(String className) {
    this.className = className;
 }
}
3.2數(shù)據(jù)綁定特殊的幾個地方

1)集合(注意:需要判斷一下集合的長度结窘,否則有可能出現(xiàn)數(shù)組越界的錯誤)

 <variable
        name="beans"
        type="java.util.ArrayList<com.thc.bindingdemo.BindingDemoBean>" />

    <variable
        name="strings"
        type="java.util.ArrayList<String>" />

    <variable
        name="map"
        type="java.util.HashMap<String,String>" />

    <variable
        name="str"
        type="String" />

    <variable
        name="num"
        type="int" />

<!--需要注意的是很洋,給ArrayList<...> 的<>進行了轉(zhuǎn)義  < > -->
<variable
   name="beans"
   type="java.util.ArrayList<com.thc.bindingdemo.BindingDemoBean>" />
<!--取集合中的數(shù)據(jù),設(shè)置姓名-->
<TextView
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text="@{beans.size>0?beans.get(0).name:bean.name}" />

2)給TextView setText的時候既有動態(tài)又有寫死的隧枫。注意:方式2使用單引號&&字符個數(shù)>2喉磁,如果只有一個比如"寫"的話會報錯(待搞)谓苟。

<!--寫死的字符+動態(tài)字符 方式1-->
<TextView
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text="@{beans.get(0).name + @string/app_name}" />

<!--寫死的字符+動態(tài)字符 方式2-->
<TextView
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text='@{"寫死的"+beans.get(0).name}' />
4、事件綁定
 <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="@{presenter.listenBind}"
        android:text="單獨更新" />

<Button
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:onClick="@{()->presenter.lambda(bean)}"
   android:text="全部更新" />

//事件綁定
public class Presenter{
    /**
     * 實現(xiàn)單獨更新某個屬性
     * 方法綁定:這種方式要求协怒,自定義的方法要和 public void onClick(View v) {} 一樣涝焙,方法名可以不同,但是參數(shù)一定要有
     */
    public void listenBind(View view){
        demoBean.setSchool("北大");
        demoBean.setClassName("二班");
    }

    /**
     * 更新所有的屬性
     * lambda表達式綁定:這種就可以任意定義了孕暇,這里是把綁定到xml的bean仑撞,傳回來并show出來
     * 切記:如果使用lambda表達式綁定事件,在xml中調(diào)用它的方法的時候要加()妖滔,擦隧哮,吃了這里的虧
     */
    public void lambda(BindingDemoBean bean){
        demoBean.setName("很強勢");
        demoBean.setClassName("三班");
        Toast.makeText(MainActivity.this,bean.toString(),Toast.LENGTH_SHORT).show();
    }
  
    public void lambda1(){
          Log.e("result","切記lambda表達式調(diào)用的時候要加()");
    }
}
 viewDataBinding.setPresenter(new Presenter());//這一步要記得哦
5、使用include及給include中的控件設(shè)置數(shù)據(jù)座舍、綁定變量
<layout xmlns:android="http://schemas.android.com/apk/res/android">
 <data>
    <variable
        name="includeBean"
        type="com.thc.bindingdemo.BindingDemoBean" />

    <variable
        name="presenter"
        type="com.thc.bindingdemo.MainActivity.Presenter" />
 </data>

 <RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:gravity="center_vertical"
    android:padding="10dp">

    <TextView
        android:id="@+id/tvBack"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="@{presenter.finish}"
        android:text="返回" />

    <TextView
        android:id="@+id/tvTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:text="標題" />

    <TextView
        android:id="@+id/tvOperate"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:text="分享" />

 </RelativeLayout>
</layout>

 viewDataBinding.includeBar.setPresenter(new Presenter());
 viewDataBinding.includeBar.setIncludeBean(demoBean);

使用Include還可以直接從外層布局傳值到Include布局中去沮翔,如下所示:

   <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.thc.myzhihu.bindingdemo.BindingIncludeActivity">

    <!--將傳入外層布局的值,直接傳入Include的布局中曲秉,-->
    <include
        layout="@layout/include_binding_test1"
        bind:includeBean="@{outterLayoutBean}"
        bind:presenter="@{outterPresenter}" />
</LinearLayout>
6采蚀、表達式 & 表達式鏈
6.1、表達式

這里只是說明下經(jīng)常用的運算符:
注意:第一個三元運算符使用的時候要做如下操作

<data>
   ...
   <import type="android.view.View"/>
</data>

<!--三元運算符-->
<ImageView
   android:visibility="@{bean.age>10?View.VISIBLE:View.GONE}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:src="@mipmap/ic_launcher"/>
<!--空合并運算符 取兩個中不為null的數(shù)據(jù)-->
<TextView
   android:text="@{beans.get(0).name??bean.name}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content" />
6.2岸浑、表達式鏈
<!--表達式鏈搏存,就比如iv1、iv2的顯示隱藏都和 bean的age大小有關(guān)矢洲,那么可以簡化為如下方式-->
    <ImageView
        android:id="@+id/iv1"
        android:visibility="@{bean.age>10?View.VISIBLE:View.GONE}"
        android:src="@mipmap/ic_launcher"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <ImageView
        android:id="@+id/iv2"
        android:visibility="@{iv1.visibility}"
        android:src="@mipmap/img2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
7璧眠、自定義BindAdapter
public class BindAdapter {
/**
 * 加載網(wǎng)絡(luò)圖片
 */
@BindingAdapter({"app:imageUrl","app:placeholderDraw"})
public static void setNetImg(ImageView ivNet, String imgUrl, Drawable placeHodler){
    Glide.with(ivNet.getContext()).load(imgUrl).placeholder(placeHodler).into(ivNet);
}
/**
 * 給將第一個字符變成紅色
 */
@BindingAdapter("app:text")
public static void setSpannelText(TextView textView,String text){
    SpannableString spannableString = new SpannableString(text);
    ForegroundColorSpan colorSpan = new ForegroundColorSpan(Color.RED);
    spannableString.setSpan(colorSpan,0,1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    textView.setText(spannableString);
}
}

在xml中的應(yīng)用:

<!--自定義BindAdapter placeholderDraw和imageUrl必須和你的定義的靜態(tài)方法中的參數(shù)一樣的-->
<ImageView
    android:layout_width="100dp"
    android:layout_height="100dp"
    app:imageUrl="@{str}"
    app:placeholderDraw="@{@drawable/img2}" />
<!--自定義BindAdapter text必須和你的定義的靜態(tài)方法中的參數(shù)一樣的-->
<TextView
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  app:text='@{map.get("key")}' />
注意:在使用app:placeholderDraw="@{@drawable/img2}" 的時候,不能使用@mipmap/哦
8读虏、自定Setter

針對自定義View

public class MyImageView extends ImageView {
 private String imgUrl;
 public MyImageView(Context context, AttributeSet attrs) {
    super(context, attrs);
 }
 public void setImgUrl(String imgUrl) {
    this.imgUrl = imgUrl;
    Glide.with(getContext()).load(imgUrl).into(this);
 }
}

<com.thc.bindingdemo.MyImageView
   app:imgUrl="@{myImageUrl}"
   android:layout_width="100dp"
   android:layout_height="100dp"/>
9责静、BindingConversion

用于時間轉(zhuǎn)化,即我們傳一個Date格式的數(shù)據(jù)給TextView盖桥,通過BindingConversion轉(zhuǎn)化為你想要的時間格式灾螃,并設(shè)置給TextView,如下:

@BindingConversion
public static String convertTime(Date date) {
    SimpleDateFormat time = new SimpleDateFormat("yyyy-MM-dd");
    return time.format(date);
 }
<!--BindingConversion-->
<TextView
  android:text="@{time}"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"/>
 //設(shè)置數(shù)據(jù)
 viewDataBinding.setTime(new Date());
10揩徊、雙向綁定
10.1 直接根據(jù)輸入內(nèi)容修改bean對象

如下:根據(jù)用戶輸入的學(xué)校腰鬼,動態(tài)改變bean的學(xué)校值,同時上面tvSchool的顯示值也變化了塑荒,挺好熄赡。

 <!--雙向綁定,動態(tài)修改學(xué)校 這里注意 @={bean.school} @后面有個=號哦 -->
 <EditText
     android:layout_width="match_parent"
     android:layout_height="50dp"
    android:text="@={bean.school}"/>
10.2 監(jiān)聽輸入內(nèi)容(即addTextChanged效果)
<layout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools">

  <data>
      <variable
          name="inputText"
          type="String" />
      <variable
          name="presenter"
          type="com.thc.dialogfragmentdemo.MainActivity.MainPresenter" />
  </data>

  <LinearLayout
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:orientation="vertical"
      tools:context="com.thc.dialogfragmentdemo.MainActivity">
      <EditText
          android:id="@+id/edtTest"
          android:layout_width="match_parent"
          android:layout_height="50dp"
          android:afterTextChanged="@{()->presenter.afterTextChanged1(inputText)}"
          android:beforeTextChanged="@{()->presenter.beforeTextChanged(inputText)}"
          android:onTextChanged="@{()->presenter.onTextChanged(inputText)}"
          android:text="@={inputText}" />
          <!--同樣-->
    </LinearLayout>
</layout>

Presenter代碼如下:

  public class MainPresenter {
    public void onTextChanged(String s) {
        LogUtil.loge("MainPresenter+onTextChanged:" + s);
    }

    public void afterTextChanged1(String s) {
        LogUtil.loge("MainPresenter+afterTextChanged:" + s);
    }

    public void beforeTextChanged(String s) {
        LogUtil.loge("MainPresenter+beforeTextChanged:" + s);
    }
  }
11齿税、RecyclerView中應(yīng)用

示例如下:

customBindingName.recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
customBindingName.recyclerView.setAdapter(new MyAdapter(getActivity(),initDatas()));
//適配器代碼如下
class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyHolder>{
    Context mContext;
    List<BindingDemoBean> mDatas;
    public MyAdapter(Context conetxt,List<BindingDemoBean> list){
        this.mContext = conetxt;
        this.mDatas = list;
    }
    @Override
    public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflate = LayoutInflater.from(mContext);
        ViewDataBinding binding = DataBindingUtil.inflate(inflate, R.layout.item_recyclerview, parent, false);
        return new MyHolder(binding);
    }
    @Override
    public void onBindViewHolder(MyHolder holder, int position) {
        ViewDataBinding binding = holder.getBinding();
        BindingDemoBean bindingDemoBean = mDatas.get(position);
        //執(zhí)行一下executePendingBindings,及時刷新
        binding.executePendingBindings();
        binding.setVariable(com.thc.bindingdemo.BR.item,bindingDemoBean);
    }
    @Override
    public int getItemCount() {
        return mDatas.size();
    }
    class MyHolder extends RecyclerView.ViewHolder{
        private ViewDataBinding mBinding;
        public MyHolder(ViewDataBinding mBinding) {
            super(mBinding.getRoot());
            this.mBinding = mBinding;
        }
        public ViewDataBinding getBinding(){
            return mBinding;
        }
    }
}

ViewHolder抽取出來:

public class BindingViewHolder<T extends ViewDataBinding> extends RecyclerView.ViewHolder {

 protected final T mBinding;

 public BindingViewHolder(T binding) {
    super(binding.getRoot());
    mBinding = binding;
 }

 public T getBinding() {
    return mBinding;
 }
}
13彼硫、自定義Component

問:我們都知道可以通過自定義BindingAdapter 提供View沒有的setter方法或者,在執(zhí)行View自身的setter之前進行一些操作。但是拧篮,系統(tǒng)是如何找到我們自定義的BindingAdapter并調(diào)用它內(nèi)部的static靜態(tài)方法的呢词渤?

答:在build/intermediates/classes下面,可以找到DataBindingComponent類串绩,包名為android.databinding缺虐,全局只會有一個該類——此接口在編譯時生成,包含了所有用到的實例BindingAdapters的getter方法赏参。
當(dāng)一個BindingAdapter是一個實例方法(instance method)志笼,一個實現(xiàn)該方法的類的實例必須被實例化。這個生成的接口會包含每個聲明BindingAdapter的類/接口的get方法把篓。命名沖突會簡單地加一個數(shù)字前綴到get方法前來解決纫溃。

使用步驟如下:

(1)比如我們這里需要實現(xiàn)一件換膚操作需要定義兩個組件:DayComponent 和 NightComponent ,在自定義組件內(nèi)部進行初始化對應(yīng)的BindingAdapter韧掩,如下:

  /**
   * 白天組件
 */
 public class DayComponent implements android.databinding.DataBindingComponent {
    public MyBindingAdapter myBindingAdapter = new DayBindingAdapter();

    @Override
    public MyBindingAdapter getMyBindingAdapter() {
        return myBindingAdapter;
    }
}

(2)MyBindingAdapter是DayBindingAdapter紊浩,NightBindingAdapter的父類,來實現(xiàn)具體的換膚操作疗锐,DayBindingAdapter如下:

/**
 * 日間Adapter
 */
public class DayBindingAdapter extends MyBindingAdapter{

  @Override
  public void setBgColor(LinearLayout layout, int llBgColor) {
    layout.setBackgroundColor(layout.getResources().getColor(R.color.pop_bgcolor));
  }
  @Override
  public void setTvColor(TextView tv, int tvColor) {
      tv.setTextColor(tv.getResources().getColor(R.color.white));
  }

}
(3)首先在Application中設(shè)置默認的Component坊谁,setComponent(DayComponent),點擊換膚的時候進行Day和Night的切換

Application中:
DataBindingUtil.setDefaultComponent(new DayComponent());

public void btn5(View v){
     if(MyApplication.isDay){
            DataBindingUtil.setDefaultComponent(new DayComponent());
     }else{
         DataBindingUtil.setDefaultComponent(new NightComponent());
     }
     MyApplication.isDay = !MyApplication.isDay;
     recreate();
}

Demo地址:https://github.com/Number-1024/DataBindingDemo

接下來總結(jié)一下滑臊,DataBinding是如何初始化View口芍,及與數(shù)據(jù)綁定實時刷新,及BindingAdapter原理等雇卷。
嗯鬓椭,可以的!

感謝巨人:
大帥
亓斌

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末关划,一起剝皮案震驚了整個濱河市小染,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌贮折,老刑警劉巖裤翩,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異调榄,居然都是意外死亡踊赠,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門每庆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來臼疫,“玉大人,你說我怎么就攤上這事扣孟。” “怎么了荣赶?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵凤价,是天一觀的道長鸽斟。 經(jīng)常有香客問我,道長利诺,這世上最難降的妖魔是什么富蓄? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮慢逾,結(jié)果婚禮上立倍,老公的妹妹穿的比我還像新娘。我一直安慰自己侣滩,他們只是感情好口注,可當(dāng)我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著君珠,像睡著了一般寝志。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上策添,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天材部,我揣著相機與錄音,去河邊找鬼唯竹。 笑死乐导,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的浸颓。 我是一名探鬼主播物臂,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼猾愿!你這毒婦竟也來了鹦聪?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤蒂秘,失蹤者是張志新(化名)和其女友劉穎泽本,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體姻僧,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡规丽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了撇贺。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赌莺。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖松嘶,靈堂內(nèi)的尸體忽然破棺而出艘狭,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布巢音,位于F島的核電站遵倦,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏官撼。R本人自食惡果不足惜梧躺,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望傲绣。 院中可真熱鬧掠哥,春花似錦、人聲如沸秃诵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽顷链。三九已至目代,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間嗤练,已是汗流浹背榛了。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留煞抬,地道東北人霜大。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像革答,于是被迫代替她去往敵國和親战坤。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理残拐,服務(wù)發(fā)現(xiàn)途茫,斷路器,智...
    卡卡羅2017閱讀 134,651評論 18 139
  • 作者: weiyf時間: 2016-10-31 21:35:33原文鏈接:https://developer.an...
    衛(wèi)裕發(fā)閱讀 4,643評論 2 15
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,075評論 25 707
  • DataBinding 庫是 Google 公司 Android Framework UI 工具團隊開發(fā)出來的一款...
    bravian閱讀 5,420評論 2 16
  • 她最近養(yǎng)的花越來越好了溪食,好像也越來越有經(jīng)驗了囊卜,會發(fā)現(xiàn)她查各種資料,學(xué)會了薄荷的水培错沃,學(xué)會了如何照料月季栅组,終于也開花...
    Ermao閱讀 190評論 0 1