Android適配器Adapter與ListView和RecycleView的簡(jiǎn)單使用
在使用ListView和RecycleView之前,我們得先了解適配器的概念。
適配器
具體來說,適配器Adapter是一個(gè)接口。
官方文檔中是這樣描述的:
An Adapter object acts as a bridge between an AdapterView and the underlying data for that view. The Adapter provides access to the data items. The Adapter is also responsible for making a android.view.View for each item in the data set.
簡(jiǎn)單來說,適配器充當(dāng)著數(shù)據(jù)與視圖之間交互的橋梁,將數(shù)據(jù)以合適的方式顯示出來。其屬于MVC模式(數(shù)據(jù)模式,控制器,視圖)的一種具體情況。
MVC模式:
Adapeter的繼承體系:
適配器中還有許多重要的方法:
getView(int position,View convertView,ViewGroup parent) :
這應(yīng)該是適配器中最重要的方法了,這個(gè)方法會(huì)在每個(gè)子項(xiàng)被滾動(dòng)到屏幕內(nèi)的時(shí)候被調(diào)用,用于加載視圖。
getItem(int positon):
用于獲取在數(shù)據(jù)集中第position位置的實(shí)例。
該方法也會(huì)在我們?cè)O(shè)置監(jiān)聽器后用來簡(jiǎn)單地獲取數(shù)據(jù)。
getItemId(int position)
用于獲取在數(shù)據(jù)集中第position位置的實(shí)例對(duì)應(yīng)的ID。
不同getItem的是,某些方法(如onclicklistener的onclick方法)有id這個(gè)參數(shù),而這個(gè)id參數(shù)就是取決于getItemId()這個(gè)返回值的。
getCount()
返回一共有幾項(xiàng)數(shù)據(jù)。
我們主要介紹的是ArrayAdapter類的使用,主要通過對(duì)該類進(jìn)行繼承重寫來實(shí)現(xiàn)我們自己的適配器。
ListView的簡(jiǎn)單用法
1.設(shè)計(jì)一個(gè)布局以顯示列表中的每一個(gè)子項(xiàng)
這里我簡(jiǎn)單地用一個(gè)圖片+文本的形式顯示一個(gè)子項(xiàng),在layout下新建一個(gè)布局:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="50dp"> <ImageView android:id="@+id/Image1" android:layout_width="50dp" android:layout_height="50dp" /> <TextView android:id="@+id/Text1" android:layout_width="0dp" android:layout_height="50dp" android:layout_weight="1" /> </LinearLayout>
2.創(chuàng)建一個(gè)中間類以在適配器中加載布局,由于僅有一個(gè)圖片和一個(gè)文本框,所以這里該類比較簡(jiǎn)單:
public class ItemOne { private int imageId; //用于存儲(chǔ)圖片的id值 private String text; //用于存儲(chǔ)文本框要顯示的內(nèi)容 public ItemOne(String text,int imageId) { this.text = text; this.imageId = imageId; } public String getText() { return text; } public int getImageId() { return imageId; } }
3.重點(diǎn):創(chuàng)建自己的適配器類:
public class MyAdapter extends ArrayAdapter<ItemOne> { private int layoutID;//僅僅用作一個(gè)中間變量,用于將構(gòu)造方法中的ResoruceId(即步驟一中創(chuàng)建的子項(xiàng)布局Id)傳遞給getView方法 public MyAdapter(Context context, int ResoruceId, List<ItemOne> data) { super(context,ResoruceId,data); //調(diào)用父類的一種構(gòu)造方法 layoutID = ResoruceId; } @Override public View getView(int position, View convertView, ViewGroup parent) { ItemOne itemOne = getItem(position); //獲取具體的中間類的實(shí)例, //這里的position其實(shí)就是itemOne在具體的List或者Array(構(gòu)造方法中傳入的List)中的索引 View view = LayoutInflater.from(getContext()).inflate(layoutID, parent,false); //此處是創(chuàng)建具體的子項(xiàng),調(diào)用靜態(tài)的LayoutInflater.from()從給定的上下文中獲取LayoutInflater實(shí)例,再調(diào)用其inflate方法將具體的子項(xiàng)布局加載進(jìn)來。 //inflate方法的第一個(gè)參數(shù)是子項(xiàng)布局的Id,第二個(gè)是父布局。第三個(gè)是是否給這個(gè)View添加父布局,這里我們傳入false就行了,因?yàn)橐坏¬iew有父布局,其就不能添加入ListView之中了。 ImageView imageView = (ImageView) view.findViewById(R.id.Image1); TextView textView = (TextView) view.findViewById(R.id.Text1); //從之前加載入的子項(xiàng)的布局中獲取具體的微件 imageView.setImageResource(itemOne.getImageId()); textView.setText(itemOne.getText()); //為微件設(shè)置圖片源和要顯示的文本,此處要顯示的內(nèi)容與之前的中間類相關(guān) return view; } }
4.在活動(dòng)中具體加載和使用ListView:
1.首先我們要在主布局中創(chuàng)建一個(gè)ListView
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ListView android:id="@+id/listview1" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
2.在主活動(dòng)中調(diào)用并加載ListView :
public class MainActivity extends AppCompatActivity { private ArrayList<ItemOne> myList = new ArrayList<>(); //一個(gè)數(shù)據(jù)列表,用于存儲(chǔ)具體的數(shù)據(jù) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initMyItem(); ListView listView = (ListView) findViewById(R.id.listview1); //獲取ListView實(shí)例 MyAdapter adapter = new MyAdapter(this,R.layout.item_layout,myList); //創(chuàng)建自定義的適配器 listView.setAdapter(adapter); //給listView設(shè)置適配器 } private void initMyItem()//初始化數(shù)據(jù)列表 { for(int i = 0; i < 20;i++) { ItemOne itemOne = new ItemOne("Item "+ i,R.drawable.qq1); myList.add(itemOne); } } }
這樣就能具體實(shí)現(xiàn)一個(gè)簡(jiǎn)單的ListView:
關(guān)于ListView性能的優(yōu)化
在上面的例子中其實(shí)ListView的運(yùn)行效率是很低的,因?yàn)間etView()方法每次都會(huì)將布局加載一遍,一旦數(shù)據(jù)量過大就會(huì)產(chǎn)生卡頓。 我們可以觀察getView方法的參數(shù)中有一個(gè)convertView參數(shù),該參數(shù)用于將之前加載好的布局進(jìn)行緩存。所以我們可以判斷convertView參數(shù)是否為空來決定是否加載布局以提升性能:
更改適配器中的getView方法 public View getView(int position, View convertView, ViewGroup parent) { ItemOne itemOne = getItem(position); View view; if(convertView != null) { view = convertView; }else{ view = LayoutInflater.from(getContext()).inflate(layoutID, parent,false); } ImageView imageView = (ImageView) view.findViewById(R.id.Image1); TextView textView = (TextView) view.findViewById(R.id.Text1); imageView.setImageResource(itemOne.getImageId()); textView.setText(itemOne.getText()); return view; }
既然我們能夠緩存之前的view,那我們還可以借助緩存的view繼續(xù)對(duì)性能進(jìn)行優(yōu)化。
public View getView(int position, View convertView, ViewGroup parent) { ItemOne itemOne = getItem(position); View view; ViewHolder viewHolder = new ViewHolder(); if(convertView != null) { view = convertView; viewHolder = (ViewHolder) view.getTag();//重新獲取viewHolder實(shí)例 }else{ view = LayoutInflater.from(getContext()).inflate(layoutID,parent,false); viewHolder.imageView= (ImageView) view.findViewById(R.id.Image1); viewHolder.textView = (TextView) view.findViewById(R.id.Text1); view.setTag(viewHolder); //將viewHolder存儲(chǔ)在view中 } viewHolder.imageView.setImageResource(itemOne.getImageId()); viewHolder.textView.setText(itemOne.getText()); return view; } class ViewHolder{ ImageView imageView; TextView textView; } }
在這里我們自建了一個(gè)內(nèi)部類ViewHolder用于存儲(chǔ)具體的微件,并將其存儲(chǔ)在view中,如果view已經(jīng)被緩存過,則說明其中的微件已經(jīng)綁定過,所以直接拿出來用就行了。
ListView的鼠標(biāo)監(jiān)聽事件
ListView的鼠標(biāo)監(jiān)聽事件與Button的監(jiān)聽事件十分相似,不同的點(diǎn)就在于具體實(shí)現(xiàn)的接口,調(diào)用的方法不同:
修改onCreate方法 protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initMyItem(); ListView listView = (ListView) findViewById(R.id.listview1); MyAdapter adapter = new MyAdapter(this,R.layout.item_layout,myList); listView.setAdapter(adapter); listView.setOnItemClickListener(new AdapterView. OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { ItemOne itemOne = myList.get(position); //獲取具體實(shí)例 Log.d("MainActivity",itemOne.getText()); } }); }
這里簡(jiǎn)單對(duì)ListView設(shè)置了一個(gè)適配器的監(jiān)聽器,每次點(diǎn)擊就獲取相應(yīng)實(shí)例并且將其text通過日志打印出來.
RecyclerView的簡(jiǎn)單用法
RecyclerView的用法和ListView十分相似:
1.創(chuàng)建具體的適配器
public class RecycleAdapter extends RecyclerView.Adapter<RecycleAdapter.ViewHolder> { private List<ItemOne> mList; static class ViewHolder extends RecyclerView.ViewHolder{ ImageView imageView; TextView textView; public ViewHolder(View view) { super(view); imageView = (ImageView) view.findViewById(R.id.Image1); textView = (TextView) view.findViewById(R.id.Text1); } } public RecycleAdapter(List<ItemOne> list) { mList = list; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent,int viewType) { View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_layout,parent,false); ViewHolder holder = new ViewHolder(view); return holder; } @Override public void onBindViewHolder(ViewHolder holder,int position) { ItemOne itemOne = mList.get(position); holder.imageView.setImageResource(itemOne.getImageId()); holder.textView.setText(itemOne.getText()); } @Override public int getItemCount(){ return mList.size(); } }
我們首先新創(chuàng)建一個(gè)適配器類繼承RecyclerView.Adapter。在適配器中我們創(chuàng)建了一個(gè)靜態(tài)內(nèi)部類ViewHolder繼承RecyclerView.ViewHold,這個(gè)類主要是在后面的方法中使用的。
由于繼承了RecyclerView.Adapter,該類需要重寫三個(gè)方法分別用于創(chuàng)建ViewHolder,綁定ViewHolder和返回?cái)?shù)據(jù)一共有多少項(xiàng).
2.在主活動(dòng)中配置適配器:
public class MainActivity extends AppCompatActivity { private ArrayList<ItemOne> myList = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initMyItem(); RecyclerView recyclerView = (RecyclerView) findViewById(R.id.Re1); LinearLayoutManager layoutManager = new LinearLayoutManager(this); //設(shè)置線性布局管理器 recyclerView.setLayoutManager(layoutManager); RecycleAdapter adapter = new RecycleAdapter(myList); recyclerView.setAdapter(adapter); } private void initMyItem() { for(int i = 0; i < 20;i++) { ItemOne itemOne = new ItemOne("Item "+ i,R.drawable.qq1); myList.add(itemOne); } } }
與ListView不同的可能就是RecyclerView還需要額外設(shè)置布局方式,這里我們創(chuàng)建的是最簡(jiǎn)單的線性布局,效果與ListView一樣。RecyclerView還有其他的布局模式,我們可以自行去體驗(yàn)。
到此這篇關(guān)于Android適配器Adapter與ListView和RecycleView的簡(jiǎn)單使用的文章就介紹到這了,更多相關(guān)Android適配器Adapter內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android Studio綁定下拉框數(shù)據(jù)詳解
這篇文章主要為大家詳細(xì)介紹了Android Studio綁定下拉框數(shù)據(jù),Android Studio綁定網(wǎng)絡(luò)JSON數(shù)據(jù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10Android實(shí)現(xiàn)保存QQ賬號(hào)與密碼功能(文件存儲(chǔ))
這篇文章主要介紹了Android保存QQ賬號(hào)與密碼,文件存儲(chǔ)是Android中最基本的一種數(shù)據(jù)存儲(chǔ)方式,它與Java中的文件存儲(chǔ)類似,都是通過I/O流形式把數(shù)據(jù)直接存儲(chǔ)到文件中,下面我們一起來看一下如何用Android實(shí)現(xiàn)文件存儲(chǔ)功能吧2022-04-04Flutter UI實(shí)現(xiàn)側(cè)拉抽屜菜單
這篇文章主要為大家詳細(xì)介紹了Flutter UI實(shí)現(xiàn)側(cè)拉抽屜菜單,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03Android使用Retrofit實(shí)現(xiàn)自定義Converter解析接口流程詳解
Retrofit是一個(gè)RESTful的HTTP網(wǎng)絡(luò)請(qǐng)求框架的封裝,網(wǎng)絡(luò)請(qǐng)求的工作本質(zhì)上是OkHttp完成,而Retrofit僅負(fù)責(zé)網(wǎng)絡(luò)請(qǐng)求接口的封裝2023-03-03Android開發(fā)TextView內(nèi)的文字實(shí)現(xiàn)自動(dòng)換行
這篇文章主要為大家介紹了Android開發(fā)TextView內(nèi)的文字實(shí)現(xiàn)自動(dòng)換行,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06viewpager實(shí)現(xiàn)自動(dòng)循環(huán)輪播圖
這篇文章主要為大家詳細(xì)介紹了viewpager實(shí)現(xiàn)自動(dòng)循環(huán)輪播圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-01-01Android 點(diǎn)擊ImageButton時(shí)有“按下”的效果的實(shí)現(xiàn)
這篇文章主要介紹了 Android 點(diǎn)擊ImageButton時(shí)有“按下”的效果的實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2017-03-03