Adapter之大資料滑動效率優化和分頁載入資料
阿新 • • 發佈:2019-01-06
在Android中如果要做到大資料分頁載入則需要我們的Activity實現OnScrollListener滾動條監聽介面。當如果要做的更加高大上。比如需要在使用者滑動至列表的底部,觸碰摸個區域,則需要實現OnTouchListener介面,等等。
這裡先講載入大資料
首先需要在main.xml申明一個ListView,存放資料
由於ListView試圖元件中,需要封裝每一個item,所以需要layout中申明:<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:paddingLeft="3dp" android:paddingRight="3dp"> <!-- 當ListActivity時,ListView中就需要@id/android:list,否則logCat會報錯 Android內建的名為list的id,因為我們後面要使用到ListActivity,我們的MainActivity繼承於它 --> <TextView android:id="@+id/txtView" android:text="編號" android:textSize="24dp" android:textColor="#ff00FF" android:background="#80D640" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_horizontal"/> <ListView android:id="@id/android:list" android:layout_width="fill_parent" android:layout_height="wrap_content"/> </LinearLayout>
list_item.xml
在加上我們的效果時,當滑動至列表的底部也就是應用程式窗體底部時,想要載入下一行,所以需要一個按鈕來觸發 load_more.xml<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <!-- 它是ListView中單個列表項的佈局檔案,從效果圖中可以看到,這裡只使用到了一個TextView元件 --> <!-- 在getView或者bindview裡面首先用一文字TextView顯示在本地,同時啟動執行緒去網上獲取圖片資源,一旦某TextView的資料得到就立馬重新整理將那張本地的TextView換掉 --> <TextView android:id="@+id/list_item_text" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center" android:textSize="20sp" android:paddingTop="10dp" android:paddingBottom="10dp"/> </LinearLayout>
在使用BaseAdapter介面卡載入大量資料<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="wrap_content"> <Button android:id="@+id/loadMoreButton" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="load more" android:onClick="loadMore"/> </LinearLayout>
package com.lol.huixin.adapter;
import java.util.List;
import java.util.Map;
import com.lol.huixin.loaddatamore.R;
import com.lol.huixin.views.ViewHolder;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class ListViewAdapter extends BaseAdapter {
private List<Map<String,Object>> items;
private LayoutInflater inflater;
public ListViewAdapter(Context context, List<Map<String,Object>> items) {
this.items = items;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
return items.size();
}
@Override
public Object getItem(int position) {
return items.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder=null;
if (convertView == null) {
holder=new ViewHolder();
convertView = inflater.inflate(R.layout.list_item, null);
holder.list_item_text=(TextView) convertView.findViewById(R.id.list_item_text);
convertView.setTag(holder);
} else{
holder=(ViewHolder)convertView.getTag();
}
holder.list_item_text.setText((String)items.get(position).get("bianhao"));
return convertView;
}
/**
* 新增列表項
* @param item
*/
public void addItem(Map<String,Object> listmap) {
items.add(listmap);
}
}
MainActivity.java中呼叫
package com.lol.huixin.loaddatamore;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.lol.huixin.adapter.ListViewAdapter;
import android.app.ListActivity;
import android.view.Menu;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.Button;
import android.widget.ListView;
//由於我們這裡模擬載入大量資料的樣本,所以就需要有個滾動條,所以需要實現滾動條的介面
public class MainActivity extends ListActivity implements OnScrollListener{
private ListView listView;
private int visibleLastIndex = 0; //最後的可視項索引
private int visibleItemCount; // 當前視窗可見項總數
private ListViewAdapter adapter; //資料介面卡
private View loadMoreView;
private Button loadMoreButton;
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//相當於例項化一個Layout,並在這個例項化的Layout中加一個按鈕
loadMoreView = getLayoutInflater().inflate(R.layout.load_more, null);
loadMoreButton = (Button) loadMoreView.findViewById(R.id.loadMoreButton);
listView = getListView(); //獲取id是list的ListView
listView.addFooterView(loadMoreView); //設定列表底部檢視
//初始化資料
initAdapter();
setListAdapter(adapter); //自動為id是list的ListView設定介面卡
listView.setOnScrollListener(this); //新增滑動監聽
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
/**
* 初始化介面卡
*/
private void initAdapter() {
List<Map<String,Object>> listMap=new ArrayList<Map<String,Object>>();
for (int i = 0; i < 10; i++) {
Map<String,Object> map=new HashMap<String,Object>();
map.put("bianhao",String.valueOf(i+1));
listMap.add(map);
}
adapter = new ListViewAdapter(this, listMap);
}
/**
* 滑動狀態改變時被呼叫
*/
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
int itemsLastIndex = adapter.getCount() - 1; //資料集最後一項的索引
int lastIndex = itemsLastIndex + 1; //加上底部的loadMoreView項
if (scrollState == OnScrollListener.SCROLL_STATE_IDLE && visibleLastIndex == lastIndex) {
//如果是自動載入,可以在這裡放置非同步載入資料的程式碼
Log.i("LOADMORE", "loading...");
}
}
/**
* 滑動時被呼叫
*/
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
this.visibleItemCount = visibleItemCount;
visibleLastIndex = firstVisibleItem + visibleItemCount - 1;
}
/**
* 點選按鈕事件
* @param view
*/
public void loadMore(View view) {
loadMoreButton.setText("loading..."); //設定按鈕文字loading
handler.postDelayed(new Runnable() {
@Override
public void run() {
loadData();
adapter.notifyDataSetChanged(); //資料集變化後,通知adapter
listView.setSelection(visibleLastIndex - visibleItemCount + 1); //設定選中項
loadMoreButton.setText("load more"); //恢復按鈕文字
}
}, 2000);
}
/**
* 模擬載入資料
*/
private void loadData() {
int count = adapter.getCount();
for (int i = count; i < count + 10; i++) {
Map<String,Object> map=new HashMap<String,Object>();
map.put("bianhao",String.valueOf(i+1));
adapter.addItem(map);
}
}
}
這個時候我們注意到了一個奇怪的現象:ViewHolder類
package com.lol.huixin.views;
import java.io.Serializable;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
@SuppressWarnings("serial")
public class ViewHolder implements Serializable{
public ImageView img;
//public TextView title;
public TextView list_item_text;
public TextView info;
public Button viewBtn;
}
專案結構:
執行效果:也是ok的。
然後我就在想為什麼這樣寫了?
1.首先ListViewAdapter中有一個有參構造方法,我們在MainActivity呼叫時傳入了兩個引數,引數一是需要裝載值ListView中的資料,引數二是當前上下文物件Context,
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)
從當前layout的上下文作用域中得到SystemService中的LAYOUT_INFLATER_SERVICE東東,那麼LAYOUT_INFLATER_SERVICE是什麼東東,Android官網給與瞭解釋:
String android.content.Context.LAYOUT_INFLATER_SERVICE = "layout_inflater"- See Also:
- Google說:使用帶有getSystemService檢索android.view.LayoutInflater進行充氣佈局資源於該上下文。
- 也就是說我們通過LayoutInflater這個類例項化一個layout,將我們load_more.xml中的按鈕給動態加至ListView中
- 2.我們知道Android中提高滑動效率,就意味著需要修改GetView方法,那麼我們那樣寫的目的何在
- 原因有兩點:
- 一>adapter每次載入時,都需要去建立一個item中的內容,也就是Layout和其中的元件,很影響效率,如果我們把元件進行封裝是不是會優化效率呢?在這,如果在記憶體中已經分配了使用LayoutInflater建立了一個Layout呢?我們是不是不需要在此建立
- 二>我們都知道在看書的時候,要想定位到上次看過的地方,最簡單的方法就是在書中做個標記,同樣的android也支援這樣一種寫法
- convertView.setTag(holder); //做資料標記