今天主要工做是將以前實現的各類ListView顯示所有信息,優化成了每次加載幾條數據,而後上滑的時候加載更多,底部顯示一個進度條和一個文字提示,而後加載完畢後,將提示信息隱藏。java
一邊看教學視頻一遍敲代碼,邊學習邊實踐,感受學到了不少東西。android
課程鏈接:http://www.imooc.com/learn/136web
好了,說說是怎麼作的吧,供之後學習參考。json
首先要定義一個footer.xml做爲進度條和提示加載中的底部佈局,代碼以下:服務器
<LinearLayout android:id="@+id/load_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:orientation="horizontal" android:paddingBottom="10dip" android:paddingTop="10dip" tools:ignore="UselessParent" > <ProgressBar style="?android:attr/progressBarStyleLargeInverse" android:layout_width="30dp" android:layout_height="30dp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="正在加載......" android:textSize="16sp" tools:ignore="HardcodedText" /> </LinearLayout>
這樣的顯示效果就是這樣的:網絡
而後自定義一個LoadListView,繼承自ListView,實現其三個構造方法:app
public LoadListView(Context context) { super(context); initView(context); } public LoadListView(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } public LoadListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initView(context); }
其中initView()是經過inflater初始化佈局的,代碼:less
private void initView(Context context){ LayoutInflater inflater = LayoutInflater.from(context); footer = inflater.inflate(R.layout.footer, null); footer.findViewById(R.id.load_layout).setVisibility(GONE); this.addFooterView(footer); this.setOnScrollListener(this); }
而後,實現實現它的滑動事件接口,(詳見代碼,這裏只說過程),目的是爲了監聽ListView上滑到底部的時候,顯示那個【加載更多...】提示信息,而後實現加載更多的函數運行,達到加載出更多數據。異步
那麼問題來了,加在了更多數據是從新設置數據適配器嗎?答案固然是不能夠從新設置,這裏咱們首先判斷adapter是否爲空,若是是空的,就setAdaper(),若是不是,其實就是加載更多之後,咱們不去從新設置,而是調用this.notifyDataSetChanged(); //當有數據變化的時候,ListView會自動刷新界面。這樣很好的保證了數據不會從新設置,效果還不錯。ide
if(adapter == null){ adapter = new FenleiAdapter(FenleiActivity.this, newsBeans); mListView.setAdapter(adapter); }else { adapter.onDateChange(newsBeans); }
public void onDateChange(List<FenleiBean> mList) { // TODO Auto-generated method stub this.mList = mList; this.notifyDataSetChanged(); //當有數據變化的時候,自動刷新界面 }
繼續,這個時候咱們會遇到一個問題,就是在自定義類LoadListView中,怎麼去調用MainActivity中的方法,答案是接口回調,大概的意思就是在LoadListView中定義一個接口,而後去MainActivity具體實現這個接口,調用的時候,經過ListView變量來調用,具體我也只是大體明白這個意思,若是不明白能夠再百度一下。
當ListView經過findViewById()找到控件id的時候,不要忘了將這個接口設置給ListView,代碼是mListView.setInterface(this);
最後的最後要在加載完數據以後,去把提示消息設置爲隱藏,這樣,整個就大功告成了!!!
最後的效果如圖:
[上滑效果] [加載更多之後的效果]
LoadListView.java源碼(具體還要根據你的項目去寫)
package com.tdyl.consult.fenlei; import com.tdyl.consult.R; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.AbsListView; import android.widget.AbsListView.OnScrollListener; import android.widget.ListView; public class LoadListView extends ListView implements OnScrollListener { View footer; int totalItemCount; int lastVisibleItem; boolean isLoading; ILoadListener2 iListener2; public LoadListView(Context context) { super(context); initView(context); } public LoadListView(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } public LoadListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initView(context); } private void initView(Context context){ LayoutInflater inflater = LayoutInflater.from(context); footer = inflater.inflate(R.layout.footer, null); footer.findViewById(R.id.load_layout).setVisibility(GONE); this.addFooterView(footer); this.setOnScrollListener(this); } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { this.lastVisibleItem = firstVisibleItem + visibleItemCount; this.totalItemCount = totalItemCount; } @Override public void onScrollStateChanged(AbsListView view, int scrollStatus) { if(totalItemCount == lastVisibleItem && scrollStatus == SCROLL_STATE_IDLE){ if(!isLoading){ isLoading = true; footer.findViewById(R.id.load_layout).setVisibility(VISIBLE); //加載更多數據 iListener2.onLoad(); } } } public void loadComplete(){ isLoading = false; footer.findViewById(R.id.load_layout).setVisibility(GONE); } public void setInterface(ILoadListener2 iListener2){ this.iListener2 = iListener2; } public interface ILoadListener2{ public void onLoad(); } }
MainActivity.java源碼(我這裏叫FenleiActivity.java,道理是同樣的)
package com.tdyl.consult.fenlei; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.ksoap2.SoapEnvelope; import org.ksoap2.SoapFault; import org.ksoap2.serialization.SoapObject; import org.ksoap2.serialization.SoapSerializationEnvelope; import org.ksoap2.transport.HttpTransportSE; import org.xmlpull.v1.XmlPullParserException; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.View; import android.view.Window; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ListView; import android.widget.TextView; import com.tdyl.consult.R; import com.tdyl.consult.fenlei.LoadListView.ILoadListener2; import com.tdyl.consult.otochat.ChatOtoActivity; public class FenleiActivity extends Activity implements ILoadListener2 { private LoadListView mListView; private String user_fenlei = ""; private TextView title_name; int number = 10; FenleiAdapter adapter = null; ArrayList <HashMap<String,Object>> list=new ArrayList<HashMap<String,Object>>(); //用來存放用戶信息 HashMap<String, Object> map = new HashMap<String, Object>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_fenlei); title_name = (TextView) findViewById(R.id.id_top_fenlei); mListView = (LoadListView) findViewById(R.id.lv_main); mListView.setInterface(this); Intent intent = getIntent(); user_fenlei = intent.getStringExtra("user_fenlei"); //----------------------------------------------------------------------------- title_name.setText(user_fenlei+"專家"); new NewsAsynkTask().execute(number); } /** * 將url對應的json格式數據轉化爲咱們縮封裝的NewsBean對象 * @param url * @return */ private List<FenleiBean> getJsonData(int number){ List<FenleiBean> newsBeanList = new ArrayList<FenleiBean>(); //----------------------------------------------------------------------------- searchTop10(number); FenleiBean newsBean; if(list.size() == 0) { new AlertDialog.Builder(this) .setIcon(R.drawable.icon_menu) .setTitle("舒適小提示") .setMessage("沒有要搜尋的專家分類") .setPositiveButton("馬上返回搜索界面...", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { finish(); } }).show(); } for(int i=0;i<list.size();i++) { newsBean = new FenleiBean(); HashMap<String, Object> map1 = new HashMap<String, Object>(); map1 = list.get(i); newsBean.newsIconUrl = map1.get("user_touxiangURL").toString(); newsBean.newTitle = map1.get("username").toString(); newsBean.newsContent = map1.get("user_qianming").toString(); newsBean.newsJifen = map1.get("user_jifen").toString(); newsBeanList.add(newsBean); } return newsBeanList; } /** * 實現網絡的異步訪問 * @author Lenovo * */ class NewsAsynkTask extends AsyncTask<Integer,Void, List<FenleiBean>>{ @Override protected List<FenleiBean> doInBackground(Integer... params) { return getJsonData(params[0]); } @Override protected void onPostExecute(List<FenleiBean> newsBeans) { // TODO Auto-generated method stub super.onPostExecute(newsBeans); if(adapter == null){ adapter = new FenleiAdapter(FenleiActivity.this, newsBeans); mListView.setAdapter(adapter); }else { adapter.onDateChange(newsBeans); } mListView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // TODO Auto-generated method stub HashMap<String, Object> map1 = list.get(position); Intent intent=new Intent(); intent.setClass(FenleiActivity.this,ChatOtoActivity.class); intent.putExtra("username", map1.get("username").toString()); //用戶名傳到另外一個界面 System.out.println("username"+map1.get("username").toString()); intent.putExtra("touxiang", map1.get("user_touxiangURL").toString()); //頭像地址 //啓動 startActivity(intent); //Toast.makeText(FenleiActivity.this, "點擊了"+newsBean.get("username"),Toast.LENGTH_SHORT).show(); } }); } } /** * 查詢用戶分類信息函數,放入list中,經過關鍵字key來取出 * */ public void searchTop10(int number) { //命名空間 String nameSpace = "http://wsServer.gnuhpc.org/"; //方法名字 String methodName = "SearchTeacherTop10"; // endPoint String endPoint = "http://10.0.2.2:8080/wsServerHello"; //soapAction String soapAction = "http://wsServer.gnuhpc.org/SearchTeacherTop10"; //指定調用方法命名空間和方法名字 SoapObject rpc = new SoapObject(nameSpace, methodName); //調用方法時須要傳入一個參數 //爲了與web service保持一致,須要設置爲arg0,由於web service會自動將其轉化爲arg0 arg1 rpc.addProperty("arg0",user_fenlei); rpc.addProperty("arg1",number); try { //wsdl地址 HttpTransportSE transport = new HttpTransportSE(endPoint); transport.debug= true; //生成調用WebService方法的SOAP請求信息,並指定SOAP的版本 SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); envelope.bodyOut = rpc; //設置是否調用的是dotNet開發的WebService,服務器是.net的須要設置爲true,java不用 envelope.dotNet = false; envelope.setOutputSoapObject(rpc); System.out.println("rpc:"+rpc); System.out.println("enevlope:"+envelope); System.out.println("---基本服務設置完畢,下面開始調用服務"); Log.v("---調用消息:", "開始call函數"); transport.call(soapAction, envelope); Log.v("---函數結果:", ""+envelope.getResponse()); if(envelope.getResponse()!=null) { // 獲取返回的數據 SoapObject object = (SoapObject) envelope.bodyIn; System.out.println("---object:"+object); System.out.println("---獲取數據成功!"); System.out.println("object.toString():"+object.toString()); // 獲取返回的結果 ,將結果存入到一個Map中 System.out.println(object.getProperty(0)); int count = object.getPropertyCount(); System.out.println("#######################"+count); for(int index = 0; index < count; index = index + 5) //表中有五個關鍵字,循環條件+5 { map = new HashMap<String, Object>(); map.put("username", object.getProperty(index).toString()); //用戶名 map.put("user_fenlei", object.getProperty(index+1).toString()); //分類 map.put("user_qianming", object.getProperty(index+2).toString()); //簽名 map.put("user_touxiangURL", object.getProperty(index+3).toString()); //在線狀態 map.put("user_jifen", object.getProperty(index+4).toString()); //積分 list.add(map); } System.out.println("list的值爲:"+list); } else{ Log.v("----鏈接消息:", "鏈接失敗"); } } catch (SoapFault e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (XmlPullParserException e) { e.printStackTrace(); } } @Override public void onLoad() { //獲取更多數據 Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { number=number+2; //每次多顯示兩條數據 new NewsAsynkTask().execute(number); //通知listView顯示更新,加載完畢 /** * 設置默認顯示爲Listview最後一行 */ mListView.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL); mListView.setStackFromBottom(true); //通知listView加載完畢,底部佈局消失 mListView.loadComplete(); } }, 1000); } }
感謝這門視頻課程,汲取養分,繼續努力......