第一階段:基礎(chǔ)ListView的使用(包含重用和ViewHolder)
-
首先是兩個(gè)xml布局文件,由于極其簡(jiǎn)單勒极,所以不做解釋
activity_main.xml<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ListView android:id="@+id/list_view" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
listview_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <TextView android:id="@+id/text1" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1"/> <TextView android:id="@+id/text2" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1"/> </LinearLayout>
-
一般情況下,listView需要三個(gè)類例如
- Fruit (用于封裝item中的各個(gè)信息的類)
- FruitAdapter (用于綁定xml中控件和item資源信息)
- MainActivity (綁定Adapter和listView)
①M(fèi)ainActivity
public class MainActivity extends AppCompatActivity {
//用于存放listView資源信息
ArrayList<Fruit> arrayList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView = findViewById(R.id.list_view);
Fruit fruit1 = new Fruit("apple","abcde");
Fruit fruit2 = new Fruit("banana","sadad");
Fruit fruit3 = new Fruit("orange","fdgdf");
arrayList.add(fruit1);
arrayList.add(fruit2);
arrayList.add(fruit3);
//聲明并綁定Adapter和listView
FruitAdapter adapter = new FruitAdapter(this,R.layout.listview_item,arrayList);
listView.setAdapter(adapter);
//點(diǎn)擊事件
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Fruit fruit = arrayList.get(i);
Toast.makeText(MainActivity.this,fruit.getName()+"被點(diǎn)擊了",Toast.LENGTH_SHORT).show();
}
});
}
}
②FruitAdapter最重要的類T墼病s镎隆倒庵!
- ViewHolder的使用結(jié)合了viewitem的回收機(jī)制耘纱,達(dá)到減少高消耗的findById的效果
public class FruitAdapter extends ArrayAdapter {
private int resourse;
public FruitAdapter(Context context, int resource , List<Fruit> objects) {
super(context, resource,objects);
this.resourse = resource;
}
@Override
public View getView(int position, View convertView,ViewGroup parent) {
Fruit fruit = (Fruit) getItem(position);
ViewHolder viewHolder;
if (convertView == null){
convertView = LayoutInflater.from(getContext()).inflate(resourse,null);
viewHolder = new ViewHolder();
viewHolder.text1 = convertView.findViewById(R.id.text1);
viewHolder.text2 = convertView.findViewById(R.id.text2);
convertView.setTag(viewHolder);
}else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.text1.setText(fruit.getName());
viewHolder.text2.setText(fruit.getDiscription());
return convertView;
}
class ViewHolder{
TextView text1;
TextView text2;
}
}
Fruit
public class Fruit {
private String name ;
private String discription;
public Fruit(String name,String discription){
this.name = name;
this.discription = discription;
}
public String getName() {
return name;
}
public String getDiscription() {
return discription;
}
}
第二階段:listView結(jié)合DataBinding的使用
-
什么是DataBinding扣猫?
早在2015谷歌 I/O大會(huì)上殴玛,就介紹了一個(gè)新的框架DataBinding钠惩,從名字就可以看出 來(lái),這是一個(gè)數(shù)據(jù)綁定框架族阅。我們?yōu)槭裁匆褂肈ataBinding篓跛? 1.再也不需要編寫(xiě)findViewById了,有人會(huì)說(shuō)坦刀,已經(jīng)有butterknife了愧沟,很好用。 2.更新UI數(shù)據(jù)需切換至UI線程鲤遥,也有人說(shuō)沐寺,有rxjava了。 但是DataBinding盖奈,不僅僅能解決這2個(gè)問(wèn)題混坞,它的核心優(yōu)勢(shì)在于,它解決了將數(shù)據(jù)分解映 射到各個(gè)view的問(wèn)題。什么個(gè)意思究孕?具體來(lái)說(shuō)啥酱,就是針對(duì)每個(gè)Activity或者Fragment的 布局,在編譯階段厨诸,會(huì)生成一個(gè)ViewDataBinding類的對(duì)象镶殷,該對(duì)象持有Activity要展 示的數(shù)據(jù)和布局中的各個(gè)view的引用。同時(shí)還有如下優(yōu)勢(shì):將數(shù)據(jù)分解到各個(gè)view微酬、在UI 線程上更新數(shù)據(jù)绘趋、監(jiān)控?cái)?shù)據(jù)的變化,實(shí)時(shí)更新颗管,這樣一來(lái)陷遮,你要展示的數(shù)據(jù)已經(jīng)和展示它的 布局緊緊綁定在了一起。我認(rèn)為這才是DataBinding真正的魅力所在垦江。
-
在build.gradle android模塊中添加如下配置
android { dataBinding { enabled = true } }
-
創(chuàng)建一個(gè)JavaBean對(duì)象
public class UserBean { private String name; private int age; public UserBean(String name , int age){ this.name = name; this.age = age; } public int getAge() { return age; } public String getName() { return name; } }
-
xml文件
這里和以前使用的xml不同帽馋,根節(jié)點(diǎn)變成了layout,里面包括了data節(jié)點(diǎn)和傳統(tǒng)的布局疫粥。這里的data節(jié)點(diǎn)作用是連接 View 和 Modle 的橋梁茬斧。在這個(gè)data節(jié)點(diǎn)中聲明一個(gè)variable變量腰懂,那值就可以輕松傳到布局文件中來(lái)了梗逮。而且TextView中沒(méi)有給控件定義id,而是在text的時(shí)候用了@{ }的方法绣溜,在括號(hào)里面直接引用UserBean對(duì)象的屬性即可完成賦值慷彤。 <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="user" type="com.example.mvvmdeme.UserBean" /> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@{user.name}"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@{String.valueOf(user.age)}"/> </LinearLayout> </layout>
-
MainActivity
這個(gè)activity很簡(jiǎn)潔,沒(méi)有了控件的初始化的findViewById或者butterknife的那一堆注解(這個(gè)butterknife是啥意思我暫時(shí)還不知道)怖喻,也沒(méi)有了TextView的setText(),也就2行代碼而已底哗。大家應(yīng)該已經(jīng)看見(jiàn)了,這里用DataBindingUtil.setContentView代替了setContentView锚沸,然后創(chuàng)建一個(gè) UserBean 對(duì)象跋选,通過(guò) binding.setUser(userBean) 與 variable 進(jìn)行綁定。注意:這個(gè)ActivityMainBinding 是如何生成的呢哗蜈?他是繼承ViewDataBinding前标,這個(gè)類的生成是有規(guī)則的,它是根據(jù)對(duì)應(yīng)的布局文件的名字生成的距潘,可以直接使用的炼列,比如:activity_main-->ActivityMainBinding 、fragment-->FragmentBinding即:第一個(gè)單詞首字母大寫(xiě)音比,第二個(gè)單詞首字母大寫(xiě)俭尖,最后都會(huì)拼上Binding就是生成的Binding類,
<b>注意:在配置dataBinding = true之后生成的文件根節(jié)點(diǎn)才會(huì)是layout,所以之前生成的文件需要手動(dòng)修改,只有根節(jié)點(diǎn)為layout的xml文件系統(tǒng)才會(huì)生成對(duì)應(yīng)的Binding類稽犁。</b>
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//系統(tǒng)生成的類
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
UserBean bean = new UserBean("張三",25);
binding.setUser(bean);
//setContentView(R.layout.activity_main);
}
}
第三階段:RecyclerView的使用
RecyclerView是什么焰望?
從Android 5.0開(kāi)始,谷歌公司推出了一個(gè)用于大量數(shù)據(jù)展示的新控件RecylerView缭付,可以用來(lái)代替?zhèn)鹘y(tǒng)的ListView柿估,更加強(qiáng)大和靈活。RecyclerView的官方定義如下:
A flexible view for providing a limited window into a large data set.
從定義可以看出陷猫,flexible(可擴(kuò)展性)是RecyclerView的特點(diǎn)秫舌。
RecyclerView是support-v7包中的新組件,是一個(gè)強(qiáng)大的滑動(dòng)組件绣檬,與經(jīng)典的ListView相比足陨,同樣擁有item回收復(fù)用的功能,這一點(diǎn)從它的名字Recyclerview即回收view也可以看出娇未。
一些簡(jiǎn)單使用
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
LinearLayoutManager layoutManager = new LinearLayoutManager(this );
//設(shè)置布局管理器
recyclerView.setLayoutManager(layoutManager);
//設(shè)置為垂直布局墨缘,這也是默認(rèn)的
layoutManager.setOrientation(OrientationHelper. VERTICAL);
//設(shè)置Adapter
recyclerView.setAdapter(recycleAdapter);
//設(shè)置分隔線
recyclerView.addItemDecoration( new DividerGridItemDecoration(this ));
//設(shè)置增加或刪除條目的動(dòng)畫(huà)
recyclerView.setItemAnimator( new DefaultItemAnimator());
簡(jiǎn)單使用
-
在build.gradle文件中引入該類。
在Android Gradle Plugin 3.0.0 以前零抬,你可以使用以下進(jìn)行配置
compile 'com.android.support:recyclerview-v7:23.4.0'
但是在3.0.0之后镊讼,棄用了compile,具體依賴配置項(xiàng)可以參閱官方文檔
https://developer.android.com/studio/build/dependencies?utm_source=android-studio#dependency_configurations
3.0.0之后的依賴配置
implementation 'com.android.support:recyclerview-v7:28.0.0'
布局
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/RecycleView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
item_1.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/text1"
android:layout_width="0dp"
android:layout_height="120dp"
android:layout_weight="1"
android:textAlignment="center"
android:gravity="center"/>
<TextView
android:id="@+id/text2"
android:layout_width="0dp"
android:layout_height="120dp"
android:layout_weight="1"
android:textAlignment="center"
android:gravity="center"/>
</LinearLayout>
-
同樣是來(lái)一個(gè)JavaBean文件
public class Fruit { private String name; private String description; public Fruit(String name,String description){ this.name = name; this.description = description; } public String getName() { return name; } public String getDescription() { return description; } }
-
最重要的一個(gè)適配器類平夜,以RecycleviewAdapter為例
適配器類需要繼承自RecyclerView.Adapter<VH>蝶棋,VH為你的ViewHolder的類名
public class RecyclerviewAdapter extends RecyclerView.Adapter <RecyclerviewAdapter.ViewHolder> { List<Fruit> list; public RecyclerviewAdapter(List<Fruit> list){ this.list = list; } @NonNull @Override public RecyclerviewAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_1, viewGroup, false); return new ViewHolder(v); } @Override public void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) { final int position = i; viewHolder.textView1.setText(list.get(position).getName()); viewHolder.textView2.setText(list.get(position).getDescription()); // viewHolder.itemView.setOnClickListener(new View.OnClickListener() { // @Override // public void onClick(View view) { // Log.d("com.", "onClick: "+list.get(position).getName()); // } // }); } @Override public int getItemCount() { return list.size(); } public static class ViewHolder extends RecyclerView.ViewHolder{ private TextView textView1; private TextView textView2; public ViewHolder(@NonNull View itemView) { super(itemView); textView1 = itemView.findViewById(R.id.text1); textView2 = itemView.findViewById(R.id.text2); } } }
-
MainActivity
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); RecyclerView recyclerView = findViewById(R.id.RecycleView); List<Fruit> list = initData(); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setAdapter(new RecyclerviewAdapter(list)); //添加分割線 recyclerView.addItemDecoration(new DividerItemDecoration(this,1)); } private List<Fruit> initData(){ List<Fruit> list = new ArrayList<>(); Fruit fruit1 = new Fruit("apple","first"); Fruit fruit2 = new Fruit("orange","second"); Fruit fruit3 = new Fruit("pear","third"); Fruit fruit4 = new Fruit("banana","firth"); Fruit fruit5 = new Fruit("saf","fifth"); Fruit fruit6 = new Fruit("dsfsd","sixth"); Fruit fruit7 = new Fruit("nbm","seventh"); list.add(fruit1); list.add(fruit2); list.add(fruit3); list.add(fruit4); list.add(fruit5); list.add(fruit6); list.add(fruit7); return list; } }
其他更詳細(xì)可以參考博客,我覺(jué)得寫(xiě)的挺全的
http://www.reibang.com/p/4f9591291365
階段四:在RecyclerView中使用DataBinding
本階段是在RecyclerView中使用DataBinding忽妒,所以兩者結(jié)合的時(shí)候玩裙,Adapter中方法略有不不同,個(gè)人理解是要將ViewHolder和DataBinding結(jié)合段直,所以方法有所差異
- 整體結(jié)構(gòu)可以看成四項(xiàng)
- Activity
- Adapter
- BaseAdapter(幫助我們有效管理Adapter)
- JavaBean
先來(lái)看一下最重要的Adapter
基類(用于管理的父類):
public abstract class BaseBindRecyclerViewAdapter<T> extends RecyclerView.Adapter {
public List<Fruit> mList; //數(shù)據(jù)源
//這個(gè)inflater我個(gè)人感覺(jué)是用于提供子類進(jìn)行xml綁定時(shí)需要的參數(shù)吃溅,所以在父類中統(tǒng)一實(shí)現(xiàn)聲明
public LayoutInflater inflater;
public BaseBindRecyclerViewAdapter(Context context, List<Fruit> mList) {
this.mList = mList;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getItemCount() {
return mList.size();
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return onCreateMyViewHolder(parent,viewType);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
onBindMyViewHolder(holder, position);
}
//獲取Item布局
public abstract RecyclerView.ViewHolder onCreateMyViewHolder(ViewGroup parent, int viewType);
//綁定數(shù)據(jù)
public abstract void onBindMyViewHolder(RecyclerView.ViewHolder holder, int position);
}
再來(lái)看看具體實(shí)現(xiàn)的子類,此處以RecyclerviewAdapter.java為例
public class RecyclerviewAdapter extends BaseBindRecyclerViewAdapter<RecyclerviewAdapter.ViewHolder> {
//數(shù)據(jù)集
List<Fruit> list;
public RecyclerviewAdapter(Context context,List<Fruit> list){
super(context,list);
this.list = list;
}
//這個(gè)方法有所不同鸯檬,綁定xml的方式轉(zhuǎn)為用Binding進(jìn)行綁定决侈,然后把binding當(dāng)做參數(shù)用于返回一個(gè)ViewHolder
@Override
public RecyclerView.ViewHolder onCreateMyViewHolder(ViewGroup parent, int viewType) {
Item1Binding binding = DataBindingUtil.inflate(inflater,R.layout.item_1,parent,false);
return new ViewHolder(binding);
}
//這個(gè)方法也不一樣,設(shè)置Bean的方式改為在binding中設(shè)置
@Override
public void onBindMyViewHolder(RecyclerView.ViewHolder holder, int position) {
Fruit fruitBean = list.get(position);
((ViewHolder) holder).getBinding().setFruit(fruitBean);
((ViewHolder) holder).getBinding().executePendingBindings(); //解決databinding閃爍問(wèn)題
}
@Override
public int getItemCount() {
return list.size();
}
//ViewHolder類有不同喧务,不在進(jìn)行繁瑣的findById的綁定赖歌,綁定工作由DataBinding進(jìn)行,DataBinding作為ViewHolder的參數(shù)蹂楣。
public static class ViewHolder extends RecyclerView.ViewHolder{
private Item1Binding binding;
public Item1Binding getBinding() {
return binding;
}
public ViewHolder(Item1Binding binding) {
super(binding.getRoot());
this.binding = binding;
}
}
}
MainActivity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//改為DataBinding綁定xml的方式
ActivityMainBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
List<Fruit> list = initData();
//以下設(shè)置項(xiàng)唯一差別就是不是直接在RecyclerView設(shè)置,而是轉(zhuǎn)為在binding下的RecycleView中設(shè)置俏站。
binding.RecycleView.setLayoutManager(new LinearLayoutManager(this));
binding.RecycleView.setAdapter(new RecyclerviewAdapter(this,list));
binding.RecycleView.addItemDecoration(new DividerItemDecoration(this,1));
}
xml以及Bean和以上DataBing代碼中一樣。
階段五:使用MVVM架構(gòu)+DataBinding實(shí)現(xiàn)RecyclerView
既然提到了MVVM就不得不總結(jié)一下android三個(gè)框架:MVC,MVP,MVVM
-
MVC
-
視圖層(View)
對(duì)應(yīng)于xml布局文件
-
控制層(Controller)
Android的控制層是由Activity來(lái)承擔(dān)的痊土,Activity本來(lái)主要是作為初始化頁(yè)面肄扎,展示數(shù)據(jù)的操作,但是因?yàn)閄ML視圖功能太弱,所以Activity既要負(fù)責(zé)視圖的顯示又要加入控制邏輯犯祠,承擔(dān)的功能過(guò)多旭等,在復(fù)雜一點(diǎn)的頁(yè)面Activity代碼量達(dá)到1000+也就不足為奇了。
-
模型層(Model)
我們針對(duì)業(yè)務(wù)模型衡载,建立的數(shù)據(jù)結(jié)構(gòu)和相關(guān)的類搔耕,它主要負(fù)責(zé)網(wǎng)絡(luò)請(qǐng)求,數(shù)據(jù)庫(kù)處理痰娱,I/O的操作弃榨。
-
-
MVP
在Android開(kāi)發(fā)中,Activity并不是一個(gè)標(biāo)準(zhǔn)的MVC模式中的Controller梨睁,本來(lái)它的首要職責(zé)是加載應(yīng)用的布局和初始化用戶界面鲸睛,接受并處理來(lái)自用戶的操作請(qǐng)求,進(jìn)而作出響應(yīng)坡贺。在MVC模式下隨著界面及其邏輯的復(fù)雜度不斷提升官辈,Activity類的職責(zé)不斷增加,以致變得龐大臃腫遍坟。
-
視圖層(View)
負(fù)責(zé)繪制UI元素拳亿、與用戶進(jìn)行交互,對(duì)應(yīng)于xml愿伴、Activity肺魁、Fragment、Adapter
-
模型層(Model)
負(fù)責(zé)存儲(chǔ)公般、檢索万搔、操縱數(shù)據(jù)胡桨,一般包含網(wǎng)絡(luò)請(qǐng)求官帘,數(shù)據(jù)庫(kù)處理,I/O流昧谊。
-
控制層(Presenter)
Presenter是整個(gè)MVP體系的控制中心刽虹,作為View與Model交互的中間紐帶,處理View于Model間的交互和業(yè)務(wù)邏輯呢诬。
從去年到現(xiàn)在涌哲,MVP的設(shè)計(jì)思想在項(xiàng)目中用得比較多,它的具體實(shí)現(xiàn)就是接收到View的請(qǐng)求尚镰,從Model層獲取數(shù)據(jù)阀圾,將數(shù)據(jù)進(jìn)行處理,通過(guò)View層的接口回調(diào)給Activity或者Fragment狗唉。MVP能夠讓Activity成為真正的View初烘,只做UI相關(guān)的事。它的優(yōu)點(diǎn)還是很多的,不然也不會(huì)有這么多人喜歡它的肾筐,
-
-
優(yōu)點(diǎn)如下:
1哆料、模型與視圖完全分離,我們可以修改視圖而不影響模型吗铐;
2东亦、項(xiàng)目代碼結(jié)構(gòu)(文件夾)清晰,一看就知道什么類干什么事情唬渗;
3典阵、我們可以將一個(gè)Presenter用于多個(gè)視圖,而不需要改變Presenter的邏輯镊逝。這個(gè)特性非常的有用萄喳,因?yàn)橐晥D的變化總是比模型的變化頻繁
4、協(xié)同工作(例如在設(shè)計(jì)師沒(méi)出圖之前可以先寫(xiě)一些業(yè)務(wù)邏輯代碼或者其他人接手代碼改起來(lái)比較容易)
-
盡管這樣蹋半,MVP模式也有不足之處他巨,不然也不會(huì)推出MVVM了,缺點(diǎn)如下:
Presente層與View層是通過(guò)接口進(jìn)行交互的减江,View層可能會(huì)有大量的接口染突,因?yàn)橛锌赡芎脦讉€(gè)Activity都是去實(shí)現(xiàn)同一個(gè)View接口,那么所有用到的Activity都要去實(shí)現(xiàn)所有的方法(不管你是否用到)辈灼,而且如果后面有些方法要?jiǎng)h改份企,Presenter和Activity都要改動(dòng),比較麻煩巡莹;
MVP把Activity相當(dāng)?shù)囊徊糠重?zé)任放到了Presenter來(lái)處理司志,復(fù)雜的業(yè)務(wù)同時(shí)也可能會(huì)導(dǎo)致P層太大,一旦業(yè)務(wù)邏輯越來(lái)越多降宅,View定義的方法越來(lái)越多骂远,會(huì)造成Activity和Fragment實(shí)現(xiàn)的方法越來(lái)越多,依然臃腫腰根。
-
MVVM
Model :負(fù)責(zé)數(shù)據(jù)實(shí)現(xiàn)和邏輯處理激才,類似MVP。
View : 對(duì)應(yīng)于Activity和XML额嘿,負(fù)責(zé)View的繪制以及與用戶交互瘸恼,類似MVP。
ViewModel : 創(chuàng)建關(guān)聯(lián)册养,將model和view綁定起來(lái),如此之后东帅,我們model的更改,通過(guò) viewmodel反饋給view,從而自動(dòng)刷新界面球拦。
-
對(duì)于各個(gè)架構(gòu)要更詳細(xì)了解可以參考博客:
http://www.reibang.com/p/4830912f5162
實(shí)戰(zhàn)
我自己又敲了一個(gè)思路清晰的簡(jiǎn)易版MVVM Demo,助于了解MVVM項(xiàng)目結(jié)構(gòu)靠闭。(以下言論基于自己理解)
首先MVVM項(xiàng)目分為幾個(gè)部分:(但是我分成了6個(gè)類比不代表只需要6個(gè)java就完事了邓夕!)
View
Activity、xml阎毅、Fragment等等Model
ViewModal
Adapter
implement
JavaBean
先來(lái)總結(jié)一下我在敲代碼過(guò)程中體會(huì)到的每個(gè)角色的作用
-
View-如MainActivity
這部分主要是編寫(xiě)界面焚刚,可以進(jìn)行一些和數(shù)據(jù)無(wú)關(guān)的UI的修改和設(shè)計(jì)
實(shí)例化Bing,綁定xml
實(shí)例化Adapter
實(shí)例化ViewModel(需要時(shí)把自身注入作為ViewModel的參數(shù))
實(shí)現(xiàn)一些響應(yīng)或者操作扇调,具體實(shí)現(xiàn)調(diào)用ViewModel實(shí)現(xiàn)(所以需要聲明一個(gè)接口用來(lái)規(guī)范ViewModel)
Model (用于加載新數(shù)據(jù))- 繼承自一個(gè)Model的專用的接口來(lái)實(shí)現(xiàn)所需方法
-
ViewModel (綁定來(lái)自Model的數(shù)據(jù)和Adapter) - 繼承自一個(gè)ViewModel的專用的接口來(lái)實(shí)現(xiàn)所需方法
這個(gè)VM參數(shù)相對(duì)來(lái)說(shuō)就比較多矿咕,需要在構(gòu)造時(shí)傳入Adapter用于數(shù)據(jù)更新,需要Model的實(shí)例化,在ViewModel實(shí)現(xiàn)的方法需要Model的參與狼钮,把自身作為響應(yīng)者注入Model碳柱,然后Model數(shù)據(jù)變化后調(diào)用響應(yīng)者的其他方法進(jìn)行實(shí)現(xiàn)。
-
Adapter
Adapter的作用沒(méi)有大差異熬芜,還是用來(lái)管理itemView的綁定和數(shù)據(jù)綁定莲镣,提供給ViewModel用于相應(yīng)數(shù)據(jù)變化的接口。
上代碼
Bean代碼和從前一樣就不記錄了
-
MainActivity
public class MainActivity extends AppCompatActivity implements View.OnClickListener { ViewModel viewModel ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //setContentView(R.layout.activity_main); ActivityMainBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_main); //RecyclerView recyclerView = findViewById(R.id.RecycleView); List<Fruit> list = initData(); RecyclerviewAdapter adapter =new RecyclerviewAdapter(this,list); viewModel = new ViewModel(this,list,adapter); binding.RecycleView.setLayoutManager(new LinearLayoutManager(this)); binding.RecycleView.setAdapter(adapter); binding.RecycleView.addItemDecoration(new DividerItemDecoration(this,1)); //O牙H鹞辍!這里不可以寫(xiě)成binding.btn.OnClickListener(this);寫(xiě)成這樣無(wú)效 binding.setClick(this); } //其實(shí)這部分不應(yīng)該寫(xiě)在這里鼓拧,但是偷個(gè)懶半火,寫(xiě)一下初始數(shù)據(jù) private List<Fruit> initData(){ List<Fruit> list = new ArrayList<>(); Fruit fruit1 = new Fruit("apple","first"); Fruit fruit2 = new Fruit("orange","second"); Fruit fruit3 = new Fruit("pear","third"); Fruit fruit4 = new Fruit("banana","firth"); Fruit fruit5 = new Fruit("saf","fifth"); Fruit fruit6 = new Fruit("dsfsd","sixth"); Fruit fruit7 = new Fruit("nbm","seventh"); list.add(fruit1); list.add(fruit2); list.add(fruit3); list.add(fruit4); list.add(fruit5); list.add(fruit6); list.add(fruit7); return list; } @Override public void onClick(View view) { switch (view.getId()){ case R.id.btn: Log.d("com.example.mvvm", "onClick: 點(diǎn)擊了"); //通過(guò)ViewModel實(shí)現(xiàn)具體邏輯 viewModel.ToRefresh(); default: Log.d("com.example.mvvm", "onClick: 點(diǎn)擊了"); } } }
-
Adapter:
BaseBindRecyclerViewAdapter
public abstract class BaseBindRecyclerViewAdapter<T> extends RecyclerView.Adapter { public List<Fruit> mList; //數(shù)據(jù)源 public LayoutInflater inflater; public BaseBindRecyclerViewAdapter(Context context, List<Fruit> mList) { this.mList = mList; //這個(gè)是為了子類綁定xml文件傳參使用,上面也提到了 inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public int getItemCount() { return mList.size(); } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return onCreateMyViewHolder(parent,viewType); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { onBindMyViewHolder(holder, position); } //獲取Item布局 public abstract RecyclerView.ViewHolder onCreateMyViewHolder(ViewGroup parent, int viewType); //綁定數(shù)據(jù) public abstract void onBindMyViewHolder(RecyclerView.ViewHolder holder, int position); //這個(gè)方法就是用于相應(yīng)數(shù)據(jù)變化的,最好是把這個(gè)方法寫(xiě)進(jìn)接口里 public void addData(List<Fruit> list){ this.mList.addAll(list); //一定要調(diào)用這個(gè)方法不然數(shù)據(jù)不會(huì)更新 notifyDataSetChanged(); } }
子類RecyclerviewAdapter
public class RecyclerviewAdapter extends BaseBindRecyclerViewAdapter<RecyclerviewAdapter.ViewHolder> { List<Fruit> list; public RecyclerviewAdapter(Context context,List<Fruit> list){ super(context,list); this.list = list; } @Override public RecyclerView.ViewHolder onCreateMyViewHolder(ViewGroup parent, int viewType) { Item1Binding binding = DataBindingUtil.inflate(inflater,R.layout.item_1,parent,false); return new ViewHolder(binding); } @Override public void onBindMyViewHolder(RecyclerView.ViewHolder holder, int position) { Fruit fruitBean = list.get(position); ((ViewHolder) holder).getBinding().setFruit(fruitBean); ((ViewHolder) holder).getBinding().executePendingBindings(); //解決databinding閃爍問(wèn)題 } //這方法暫時(shí)用不到 // @Override // public int getItemViewType(int position) { // return list.get(position).getItemViewType(); // } @Override public int getItemCount() { return list.size(); } public static class ViewHolder extends RecyclerView.ViewHolder{ private Item1Binding binding; public Item1Binding getBinding() { return binding; } public ViewHolder(Item1Binding binding) { super(binding.getRoot()); this.binding = binding; } } }
-
Model接口
public interface ModelImp { public void NewData(VMImp listener); }
-
Model
public class Model implements ModelImp { List<Fruit> list; public Model(List<Fruit> list){ this.list = list; } //這個(gè)方式用于實(shí)現(xiàn)數(shù)據(jù)變化季俩,把實(shí)現(xiàn)了VMImp接口的VM作為響應(yīng)者注入钮糖,然后調(diào)用相應(yīng)者的方法 @Override public void NewData(VMImp listener) { List<Fruit> list = new ArrayList<>(); Fruit fruit1 = new Fruit("NEW","first"); Fruit fruit2 = new Fruit("NEW","second"); Fruit fruit3 = new Fruit("NEW","third"); Fruit fruit4 = new Fruit("NEW","firth"); Fruit fruit5 = new Fruit("NEW","fifth"); Fruit fruit6 = new Fruit("NEW","sixth"); Fruit fruit7 = new Fruit("NEW","seventh"); list.add(fruit1); list.add(fruit2); list.add(fruit3); list.add(fruit4); list.add(fruit5); list.add(fruit6); list.add(fruit7); listener.succeed(list); } }
-
ViewModel的接口
public interface VMImp { //MainActivity調(diào)用 public void ToRefresh(); //用于Model回調(diào) public void succeed(List<Fruit> list); }
-
ViewModel
public class ViewModel implements VMImp{ private AppCompatActivity view; private Model model; private RecyclerviewAdapter adapter; public ViewModel(AppCompatActivity view, List<Fruit> list,RecyclerviewAdapter adapter){ model = new Model(list); this.view = view; this.adapter = adapter; } //MainActivity調(diào)用 @Override public void ToRefresh() { model.NewData(this); } //用于Model回調(diào) public void succeed(List<Fruit> list){ adapter.addData(list); } }
-
activity_main.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="click" type="android.view.View.OnClickListener" /> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <Button android:id="@+id/btn" android:layout_width="match_parent" android:layout_height="100dp" android:text="更新" android:onClick="@{click}"/> <android.support.v7.widget.RecyclerView android:id="@+id/RecycleView" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> </layout>
-
item_1.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="fruit" type="com.example.recyclerviewwithdatabinding.Fruit" /> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:layout_width="0dp" android:layout_height="120dp" android:layout_weight="1" android:textAlignment="center" android:gravity="center" android:text="@{fruit.name}"/> <TextView android:layout_width="0dp" android:layout_height="120dp" android:layout_weight="1" android:textAlignment="center" android:gravity="center" android:text="@{fruit.description}"/> </LinearLayout> </layout>
可參考文檔
http://www.reibang.com/p/4f9591291365