<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                繼續上篇的博客《[Android官方數據綁定框架DataBinding(一)](http://blog.csdn.net/qibin0506/article/details/47393725)》我們繼續學習Data Binding的使用。 十、inflate 不知道大家注意沒有,上面的代碼我們都是在activity中通過`DataBindingUtil.setContentView`來加載的布局的,現在有個問題了,如果我們是在`Fragment`中使用呢?`Fragment`沒有`setContentView`怎么辦?不要著急,Data Binding也提供了`inflate`的支持! 使用方法如下,大家肯定會覺得非常眼熟。 ~~~ MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater); MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater, viewGroup, false); ~~~ 接下來,我們就嘗試著在`Fragment`中使用一下Data Binding吧。 首先還是那個學生類,`Student` ~~~ public class Student extends BaseObservable { private String name; private int age; public Student() { } public Student(int age, String name) { this.age = age; this.name = name; } @Bindable public int getAge() { return age; } public void setAge(int age) { this.age = age; notifyPropertyChanged(org.loader.app5.BR.age); } @Bindable public String getName() { return name; } public void setName(String name) { this.name = name; notifyPropertyChanged(org.loader.app5.BR.name); } } ~~~ 這里面代碼如果看不懂了,請翻看前一篇博客。 繼續,activity的布局 ~~~ <RelativeLayout 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" tools:context=".MainActivity"> <FrameLayout android:id="@+id/container" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </RelativeLayout> ~~~ activity的代碼, ~~~ public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); getSupportFragmentManager().beginTransaction() .replace(R.id.container, new MyFragment()).commit(); } } ~~~ 重點來了,我們這里data binding的操作都放在了fragment里,那么我們先來看看fragment的布局。 ~~~ <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data class=".Custom"> <import type="org.loader.app5.Student" /> <variable name="stu" type="Student" /> <variable name="frag" type="org.loader.app5.MyFragment" /> </data> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="@{frag.click}" android:text="@{stu.name}"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{String.valueOf(stu.age)}"/> </LinearLayout> </layout> ~~~ 如果你看過上篇博客,那么這里也很簡單,簡單說一下吧。兩個TextView分別綁定了Student的name和age字段,而且給name添加了一個點擊事件,點擊后會調用Fragment的click方法。我們來迫不及待的看一下Fragment怎么寫: ~~~ public class MyFragment extends Fragment { private Student mStu; @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { org.loader.app5.Custom binding = DataBindingUtil.inflate(inflater, R.layout.frag_layout, container, false); mStu = new Student(20, "loader"); binding.setStu(mStu); binding.setFrag(this); return binding.getRoot(); } public void click(View view) { mStu.setName("qibin"); mStu.setAge(18); } } ~~~ 在`onCreateView`中,不同于在Activity中,這里我們使用了DataBindingUtil.inflate方法,接受4個參數,第一個參數是一個LayoutInflater對象,正好,我們這里可以使用onCreateView的第一個參數,第二個參數是我們的布局文件,第三個參數是一個ViewGroup,第四個參數是一個boolean類型的,和在`LayoutInflater.inflate`一樣,后兩個參數決定了是否想`container`中添加我們加載進來的布局。 下面的代碼和我們之前寫的并無差別,但是有一點,`onCreateView`方法需要返回一個View對象,我們從哪獲取呢?`ViewDataBinding`有一個方法`getRoot`可以獲取我們加載的布局,是不是很簡單? 來看一下效果: ![](https://box.kancloud.cn/2016-02-18_56c55b3a63787.jpg "") 十一、 Data Binding VS RecyclerView 有了上面的思路,大家是不是也會在ListView和RecyclerView中使用了?我們僅以一個RecyclerView來學習一下。 首先來看看item的布局, ~~~ <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="stu" type="org.loader.app6.Student" /> </data> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{stu.name}" android:layout_alignParentLeft="true"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{String.valueOf(stu.age)}" android:layout_alignParentRight="true"/> </RelativeLayout> </layout> ~~~ 可以看到,還是用了那個Student實體,這樣得代碼,相信你也已經看煩了吧。 那我們來看看activity的。 ~~~ private RecyclerView mRecyclerView; private ArrayList<Student> mData = new ArrayList<Student>() { { for (int i=0;i<10;i++) add(new Student("loader" + i, 18 + i)); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mRecyclerView = (RecyclerView) findViewById(R.id.recycler); mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); mRecyclerView.setAdapter(new MyAdapter(mData)); } ~~~ 這里給`RecyclerView`設置了一個Adapter,相信最主要的代碼就在這個Adapter里。 ~~~ private class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { private ArrayList<Student> mData = new ArrayList<>(); private MyAdapter(ArrayList<Student> data) { mData.addAll(data); } @Override public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater .from(viewGroup.getContext()), R.layout.item, viewGroup, false); ViewHolder holder = new ViewHolder(binding.getRoot()); holder.setBinding(binding); return holder; } @Override public void onBindViewHolder(ViewHolder viewHolder, int i) { viewHolder.getBinding().setVariable(org.loader.app6.BR.stu, mData.get(i)); viewHolder.getBinding().executePendingBindings(); } @Override public int getItemCount() { return mData.size(); } class ViewHolder extends RecyclerView.ViewHolder { private ViewDataBinding binding; public ViewHolder(View itemView) { super(itemView); } public void setBinding(ViewDataBinding binding) { this.binding = binding; } public ViewDataBinding getBinding() { return this.binding; } } } ~~~ 果然,這個adapter的寫法和我們之前的寫法不太一樣,首先看看ViewHolder,在這個holder里,我們保存了一個`ViewDataBinding`對象,并給它提供了`Getter`和`Setter`方法, 這個`ViewDataBinding`是干嘛的?我們稍后去講。繼續看看`onCreateViewHolder`,在這里面,我們首先調用`DataBindingUtil.inflate`方法返回了一個`ViewDataBinding`的對象,這個`ViewDataBinding`是個啥?我們以前沒見過啊,這里告訴大家我們之前返回的那些都是`ViewDataBinding`的子類!繼續看代碼,我們new了一個holder,參數是肯定是我們的item布局了,繼續看,接著我們又把binding設置給了holder,最后返回holder。這時候,我們的holder里就保存了剛剛返回的`ViewDataBinding`對象,干嘛用呢?繼續看`onBindViewHolder`就知道了。 ~~~ @Override public void onBindViewHolder(ViewHolder viewHolder, int i) { viewHolder.getBinding().setVariable(org.loader.app6.BR.stu, mData.get(i)); viewHolder.getBinding().executePendingBindings(); } ~~~ 只有兩行代碼,但是都是我們沒有見過的,首先第一行,我們以前都是使用類似`binding.setStu`這樣方法去設置變量,那這個`setVariable`呢? 為什么沒有`setStu`,這里要記住,`ViewDataBinding`是我們之前用的那些binding的父類,只有自動生成的那些子類才會有`setXXX`方法,那現在我們需要在`ViewDataBinding`中設置變量咋辦?這個類為我們提供了`setVariable`去設置變量,第一個參數是我們的變量名的引用,第二個是我們要設置的值。第二行代碼,`executePendingBindings`的作用是干嘛的?官方的回答是: > 當數據改變時,binding會在下一幀去改變數據,如果我們需要立即改變,就去調用`executePendingBindings`方法。 所以這里的作用就是去讓數據的改變立即執行。 ok,現在看起來,我們的代碼更加簡潔了,而且不需要保存控件的實例,是不是很爽? 來看看效果: ![](https://box.kancloud.cn/2016-02-18_56c55b3a7689f.jpg "") 十二、 View with ID 在使用Data Binding的過程中,我們發現并沒有保存View的實例,但是現在我們有需求需要這個View的實例咋辦?難道走老路`findViewById`?當然不是啦,當我們需要某個view的實例時,我們只要給該view一個id,然后Data Binding框架就會給我們自動生成該view的實例,放哪了?當然是`ViewDataBinding`里面。 上代碼: ~~~ <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data class=".Custom"> <variable name="str" type="android.databinding.ObservableField&lt;String>" /> <variable name="handler" type="org.loader.app7.MainActivity" /> </data> <TextView android:id="@+id/textView" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@{str.get}" android:onClick="@{handler.click}"/> </layout> ~~~ xml中代碼沒有什么好說的,都是之前的代碼,如果在這有點迷糊,建議你還是回頭看看上篇博客。需要注意的是, 我們給`TextView`了一個id-`textView`。 activity, ~~~ public class MainActivity extends AppCompatActivity { private org.loader.app7.Custom mBinding; private ObservableField<String> mString; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main); mString = new ObservableField<String>(); mString.set("loader"); mBinding.setStr(mString); mBinding.setHandler(this); } public void click(View view) { mString.set("qibin"); mBinding.textView.setTextColor(Color.GREEN); } } ~~~ 主要還是來看`click`方法中,這里我們需要獲取TextView的實例,用來改變他的顏色,我們是通過`ViewDataBinding`類的實例直接去獲取的。 > 只要我們給了view一個id,那么框架就會在ViewDataBinding中自動幫我們保存這個view的實例,變量名就是我們設置的id。 十三、 自定義setter 想想這樣的一種情景,一個`ImageView`需要通過網絡去加載圖片,那我們怎么辦?看似好像使用DataBinding不行,恩,我們上面所學到東西確實不能夠解決這個問題,但是DataBinding框架給我們提供了很好的擴展,允許我們自定義setter,那該怎么做呢?這里就要引出另一個知識點——`BindingAdapter`,這是一個注解,參數是一個數組,數組中存放的是我們自定義的’屬性’。接下來就以一個例子學習一下`BindingAdapter`的使用。 ~~~ <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data class=".Custom"> <variable name="imageUrl" type="String" /> </data> <ImageView android:layout_width="match_parent" android:layout_height="wrap_content" app:image="@{imageUrl}"/> </layout> ~~~ 這里我們增加了一個命名空間`app`,并且注意ImageView的`app:image`屬性,這里和我們自定義view時自定義的屬性一樣,但是這里并不需要我們去重寫ImageView,這條屬性的值是我們上面定義的String類型的imageUrl,從名稱中看到這里我們可能會塞給他一個url。 activity, ~~~ public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); org.loader.app8.Custom binding = DataBindingUtil.setContentView(this, R.layout.activity_main); binding.setImageUrl("http://images.csdn.net/20150810/Blog-Image%E5%89%AF%E6%9C%AC.jpg"); } } ~~~ 果然在這里我們set了一個url,那圖片怎么加載呢?這里就要使用到我們剛才說的BindingAdapter注解了。 ~~~ public class Utils { @BindingAdapter({"bind:image"}) public static void imageLoader(ImageView imageView, String url) { ImageLoaderUtils.getInstance().displayImage(url, imageView); } } ~~~ 我們定義了一個`Utils`類,這個類你可以隨便起名,該類中只有一個**靜態**的方法imageLoader,該方法有兩個參數,一個是需要設置數據的view, 一個是我們需要的url。值得注意的是那個`BindingAdapter`注解,看看他的參數,是一個數組,內容只有一個`bind:image`,僅僅幾行代碼,我們不需要 手工調用Utils.imageLoader,也不需要知道imageLoader方法定義到哪了,一個網絡圖片加載就搞定了,是不是很神奇,這里面起關鍵作用的就是`BindingAdapter` 注解了,來看看它的參數怎么定義的吧,難道是亂寫?當然不是,這里要遵循一定的規則, > 以bind:開頭,接著書寫你在控件中使用的自定義屬性名稱。 這里就是`image`了,不信來看。 ~~~ <ImageView android:layout_width="match_parent" android:layout_height="wrap_content" app:image="@{imageUrl}"/> ~~~ 看看運行結果: ![](https://box.kancloud.cn/2016-02-18_56c55b3a91055.jpg "") 十四、 Converters Converter是什么呢?舉個例子吧:假如你的控件需要一個格式化好的時間,但是你只有一個`Date`類型額變量咋辦?肯定有人會說這個簡單,轉化完成后在設置,恩,這也是一種辦法,但是DataBinding還給我們提供了另外一種方式,雖然原理一樣,但是這種方式使用的場景更多,那就是——Converter。和上面的`BindingAdapter`使用方法一樣,這也是一個注解。下面還是以一段代碼的形式進行學習。 ~~~ <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data class=".Custom"> <variable name="time" type="java.util.Date" /> </data> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@{time}"/> </layout> ~~~ 看TextView的text屬性,我們需要一個String類型的值,但是這里確給了一個Date類型的,這就需要我們去定義Converter去轉換它, activity, ~~~ public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); org.loader.app9.Custom binding = DataBindingUtil.setContentView(this, R.layout.activity_main); binding.setTime(new Date()); } } ~~~ 去給這個Date類型的變量設置值。怎么去定義Converter呢? 看代碼: ~~~ public class Utils { @BindingConversion public static String convertDate(Date date) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); return sdf.format(date); } } ~~~ 和上面一樣,我們不需要關心這個convertDate在哪個類中,重要的是他的`@BindingConversion`注解,這個方法接受一個Date類型的變量,正好我們的android:text設置的就是一個Date類型的值,在方法內部我們將這個Date類型的變量轉換成String類型的日期并且返回。這樣UI上就顯示出我們轉化好的字符串。 看看效果: ![](https://box.kancloud.cn/2016-02-18_56c55b3aa4a08.jpg "") 好了,到這里DataBinding的知識我們就算學習完了,在學完之后發現這東西也沒什么難度,學會使用就ok了,而且android官網也有非常詳細的文檔, 這兩篇博客只是系統的去講解了DataBinding的使用,大家在以后使用的過程中發現忘記怎么用了,可以再來翻看博客或者直接去官方查看。 ok, 那就到這里吧,下次見。 參考鏈接:[https://developer.android.com/tools/data-binding/guide.html](https://developer.android.com/tools/data-binding/guide.html) 博客源碼下載:[代碼下載,戳這里](http://download.csdn.net/detail/qibin0506/9013513)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看