在尋常的開發中經常會有很是多列表頁面。每作一個列表頁就需要建立這個佈局文件那個Adapter適配器文件等等一大堆與之相關的附屬的沒必要要的冗餘文件。java
假設版本號更新迭代比較頻繁,如此以往,就會使項目project變得無比龐大臃腫。git
假設看過這篇文章或者在使用過這樣的方式以後呢,所有的工做都可以被壓縮成僅僅有兩個文件,一個JAVA文件一個XML佈局文件。數據庫
而且代碼還少少的。json
我們來看看實際狀況:緩存
尋常的一個列表頁面的生成需要下面文件:安全
/** * 演示樣例代碼,將關鍵的部分放在fragment中。不論是viewpager仍是Activity。仍是其餘容器,都可以將fragment嵌入當中顯示 * * @author Sahadev * */ public class ExampleFragment extends SuperAbstListFragment<ExampleBean> { public static AbstListFragment getInstance(String requestUrl) { AbstListFragment fragment = new ExampleFragment(); Bundle bundle = new Bundle(); bundle.putString(AbstListFragment.URL, requestUrl); fragment.setArguments(bundle); return fragment; } @Override public Type getInstanceType() { // 返回需要實例化的對象類型 return new TypeToken<List<ExampleBean>>() { }.getType(); } /** * 需要實例化的類,這裏僅用一個屬性作樣例 * * @author Work * */ public static class ExampleBean implements Serializable { /** * */ private static final long serialVersionUID = 7624541082621792974L; @SerializedName("title") public String title; } //在這裏完畢數據綁定就可以了,支持鏈式調用 @Override public void setView(ViewHolder viewHolder, ExampleBean t) { viewHolder.setText(R.id.title, t.title); } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { } }
/** * 基本類。提供一些常用的主要的方法屬性供子類使用 * * @author Sahadev * */ public class BaseFragment extends Fragment { /** * 圖片載入工具 */ protected ImageLoader mImageLoader; /** * 等待對話框 */ private LoadingDialog mLoadingDialog; /** * 佈局填充器 */ protected LayoutInflater mInflater; /** * context */ protected Activity mContext; @Override public void onAttach(Activity activity) { super.onAttach(activity); mContext = activity; mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // 在此處初始化mImageLoader,mLoadingDialog等屬性 mLoadingDialog = LoadingDialog.getInstance(mContext); // imageLoader屬性可在本身定義的Application中設置全局的單例。由本身定義Application暴露接口獲取單例,比方 // mImageLoader = CustomApplication.getImageLoaderInstance(); } /** * 吐司 * * @param message */ protected void toast(String message) { Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show(); } /** * 顯示等待對話框。顯示默認文本 */ protected void showLoadingDialog() { if (mLoadingDialog != null) { mLoadingDialog.show(); } } /** * 顯示等待對話框,顯示傳入的文本 * * @param message */ public void showLoadingDialog(String message) { if (mLoadingDialog != null) { mLoadingDialog.setMessage(message); mLoadingDialog.show(); } } /** * 關閉等待對話框 */ protected void dismissLoadingDialog() { if (mLoadingDialog != null) { mLoadingDialog.dismiss(); } } @Override public void onDestroy() { super.onDestroy(); dismissLoadingDialog(); } }
/** * 含有ListView的Fragment * 抽取公共的含有ListView的Fragment。此Fragment已經包含主要的下拉刷新,網絡載入,分頁載入等公共功能,僅僅需要關心實現 推薦使用 * {@link #SuperAbstListFragment}實例化子類方式參見{@link #ExampleFragment} * * @author Sahadev * */ public abstract class AbstListFragment extends BaseFragment implements OnItemClickListener, OnClickListener, Listener<JSONObject>, ErrorListener, OnRefreshListener2<ListView> { protected PullToRefreshListView mListView; protected ImageView emptyView; private AnimationDrawable rocketAnimation; private View rootView; protected int page = 0; public static final String URL = "ABST_LIST_FRAGMENT_URL"; public static final String NEED_REFRESH_BROADCAST_RECEIVER = "NEED_REFRESH_BROADCAST_RECEIVER"; /** * 請求的連接地址 */ protected String requestUrl; /** * 由子類實現。安全傳參 * * @param requestUrl * @return */ public static AbstListFragment getInstance(String requestUrl) { return null; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if (rootView == null) { rootView = inflater.inflate(R.layout.activity_list_layout, container, false); emptyView = (ImageView) rootView.findViewById(R.id.empty_view); mListView = (PullToRefreshListView) rootView.findViewById(R.id.list); mListView.setEmptyView(emptyView); mListView.getRefreshableView().setLayoutTransition(new LayoutTransition()); mListView.setOnRefreshListener(this); mListView.setOnItemClickListener(this); mListView.getRefreshableView().setOnItemClickListener(this); emptyView.setOnClickListener(this); Bundle bundle = getArguments(); if (bundle != null) { requestUrl = getArguments().getString(AbstListFragment.URL); } } ViewGroup parent = (ViewGroup) rootView.getParent(); if (parent != null) { parent.removeView(rootView); } return rootView; } @Override public void onStart() { super.onStart(); if (mListView != null) { mListView.setRefreshing(false); } } @Override public void onPullDownToRefresh(PullToRefreshBase<ListView> refreshView) { page = 0; getData(requestUrl + "&p=" + page);// 這裏可以加入分頁和其餘請求server所需要的必要參數。比方token或者其餘什麼的,因此在傳入的地方僅僅用傳入必要的參數就OK } @Override public void onPullUpToRefresh(PullToRefreshBase<ListView> refreshView) { page++; getData(requestUrl + "&p=" + page); } protected void getData(String requestUrl) { if (isNeedLoadDataFromNet()) { if (page == 0) { // 可以在這裏設置載入動畫 emptyView.setImageResource(R.drawable.loading_animation);// R.drawable.loading_animation表明動畫資源 rocketAnimation = (AnimationDrawable) emptyView.getDrawable(); rocketAnimation.start(); } RequestUtils.requesGet(requestUrl, this, this); } } /** * 這種方法用於返回是不是從網絡載入,有些數據是需要從本地載入的。這個 方法就可以由子類來控制詳細是什麼 * * @return */ protected boolean isNeedLoadDataFromNet() { return true; } @Override public void onResponse(JSONObject response) { // 設置請求完成以後的狀態 rocketAnimation.stop(); emptyView.setImageResource(R.drawable.nocontent); mListView.onRefreshComplete(); } @Override public void onErrorResponse(VolleyError error) { // 設置請求完成以後的狀態 rocketAnimation.stop(); emptyView.setImageResource(R.drawable.nocontent); toast("咦?網絡情況貌似出了點問題."); mListView.onRefreshComplete(); } @Override public void onClick(View v) { switch (v.getId()) { // 當點擊無數據提示的時候又一次載入 case R.id.empty_view: mListView.setRefreshing(); break; default: break; } } private BroadcastReceiver receiver; @Override public void onResume() { super.onResume(); receiver = new NeedRefreshBroadcastReceiver(); IntentFilter filter = new IntentFilter(NEED_REFRESH_BROADCAST_RECEIVER); filter.addCategory(Intent.CATEGORY_DEFAULT); mContext.registerReceiver(receiver, filter); } @Override public void onPause() { super.onPause(); mContext.unregisterReceiver(receiver); } /** * 主動刷新廣播接收器,當數據發生改變的時候(比方加入或者刪除)主動刷新 * * @author Work * */ private class NeedRefreshBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { mListView.setCurrentMode(Mode.PULL_FROM_START); mListView.setRefreshing(false); } } }
/** * 抽象的AbstListFragment中間層,具備更強大的功能 * * @author Work * */ public abstract class SuperAbstListFragment<T> extends AbstListFragment { protected AbstBaseAdapter<T> adapter; @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); try { // 假設有些Adapter中不知足實際狀況的話,可以使用反射來實例化 // adapter = (AbstBaseAdapter<T>) // getAdapterClass().getConstructor(Context.class).newInstance(mContext); adapter = new SuperAdapter(mContext); mListView.setAdapter(adapter); } catch (IllegalArgumentException e) { e.printStackTrace(); } } /** * 萬能適配器,它僅僅是個中間件 * * @author Work * */ public class SuperAdapter extends AbstBaseAdapter<T> { public SuperAdapter(Context context) { super(context); } @Override public View getView(int position, View convertView, ViewGroup parent) { return SuperAbstListFragment.this.getView(position, convertView, parent); } } /** * * * @param position * @param convertView * @param parent * @return */ public View getView(int position, View convertView, ViewGroup parent) { // 這裏使用的是萬能的ViewHolder ViewHolder viewHolder = ViewHolder.get(mContext, convertView, parent, R.layout.fragment_list_item, position);// 這一行可以進一步的抽取到父類中 T t = adapter.getData().get(position); setView(viewHolder, t); return viewHolder.getConvertView(); } /** * 綁定數據,使用戶真正關心的僅僅有他們想要關心的 * * @param viewHolder * @param t */ public abstract void setView(ViewHolder viewHolder, T t); /** * 假設單單的getView方法不知足需求的話。可以經過本身定義Adapter的方法來實現,該方法用來返回需要實例化的Adapter的類名 * * @return */ public Class<?> getAdapterClass() { return null; } /** * 需要解析的數據類型是一個對象仍是對象的集合,由這個返回 * * @return */ public abstract Type getInstanceType(); /* * (non-Javadoc) * * @see * com.sahadev.general_assembly.base.AbstListFragment#onResponse(org.json * .JSONObject) 當網絡請求成功以後回調該方法,開始解析數據 */ @Override public void onResponse(JSONObject response) { super.onResponse(response); if (response != null && response.optBoolean("success")) { Gson gson = new Gson(); List<T> datas = gson.fromJson(response.optJSONArray("data").toString(), getInstanceType()); initAdapter(datas); } } /** * 數據解析完成以後刷新數據 * * @param list */ protected void initAdapter(List<T> list) { if (page == 0) { adapter.addFirstPageData(list); } else { adapter.addOtherPageData(list); } } }
/** * 含有ListFragment的Activity * * @author 尚斌 * */ public class IncludeListFragmentActivity extends FragmentActivity { private String mFragmentClass = "x.x.x.x.x.x"; private String mRequestUrl = "http://www.baidu.com"; private String title = "標題沒有定義"; public static final String TITLE = "TITLE"; public static final String CLASS = "CLASS"; public static final String URL = "URL"; /** * @param context * @param fragmentClass * 需要實例化的Fragment的包名 * @param requestUrl * 該Fragment內部的請求地址 * @return */ public static Intent getIntent(Context context, String fragmentClass, String requestUrl, String title) { Intent intent = new Intent(context, IncludeListFragmentActivity.class); Bundle bundle = new Bundle(); bundle.putString(TITLE, title); bundle.putString(CLASS, fragmentClass); bundle.putString(URL, requestUrl); intent.putExtras(bundle); return intent; } @SuppressWarnings("unchecked") @Override protected void onCreate(Bundle savedInstanceState) { requestWindowFeature(Window.FEATURE_NO_TITLE); super.onCreate(savedInstanceState); Intent intent = getIntent(); Bundle bundle = intent.getExtras(); mFragmentClass = bundle.getString(CLASS); mRequestUrl = bundle.getString(URL); title = bundle.getString(TITLE); // 設置標題 setTitle(title); // 設置佈局文件 setContentView(R.layout.activity_include_list_fragment); try { Class<BaseFragment> newInstance = (Class<BaseFragment>) Class.forName(mFragmentClass); Method method = null; BaseFragment fragment = null; method = newInstance.getMethod("getInstance", String.class); fragment = (BaseFragment) method.invoke(null, mRequestUrl); if (fragment != null) { getSupportFragmentManager().beginTransaction().add(R.id.container, fragment).commit(); } else { throw new Exception("You must be have a named getInstance method!"); } } catch (Exception e) { e.printStackTrace(); } }
public JsonRequest(int method, String url, Map<String, String> body, Listener<T> listener, ErrorListener errorListener, boolean isNeedCache, Type type) { super(method, url + "&token=token" + "&vid=vid"), errorListener); mListener = listener; mRequestBody = null; mType = type; if (isNeedCache && !(檢查網絡是否可用)) { url += "&token=token" + "&vid=vid"; try { //使用本身定義的方式去數據庫中查找,這裏使用的是xUtils舉例: List<Cache> datas = xUtils .getInstance() .getDbUtils() .findAll( Selector.from(Cache.class).where("requestUrl", "=", url).orderBy("time", false) .limit(1)); if (!netAccessed && datas != null & listener != null) { for (Cache cache : datas) { //假設查找成功就進行回調 listener.onResponse((T) new JSONObject(cache.jsonString)); } } } catch (DbException e) { e.printStackTrace(); } catch (JSONException e) { e.printStackTrace(); } } bodyMap = body; }網絡回調部分。將server數據存儲:
@Override protected void deliverResponse(final T response) { if (response != null && (response.getClass().equals(String.class) || response.getClass().equals(JSONObject.class))) { new Thread(new Runnable() { @Override public void run() { Cache cache = new Cache(mUrl, response.toString()); try { //使用xUtils進行存儲 xUtils.getInstance().getDbUtils().save(cache); } catch (DbException e) { e.printStackTrace(); } } }).start(); } netAccessed = true; if (mListener != null && (假設網絡可用)) { if (mType != null) { try { String simString1 = response.getClass().getName(); String simString2 = mType.toString(); //有多種類型回調,假設僅僅是回調String類。則調用下面 if (simString2.contains(simString1)) { mListener.onResponse(response); } else { mListener.onResponse(null); } } catch (Exception e1) { } } else { //另外一種是JsonObject類型,則調用下面 mListener.onResponse(response); } } }大夥可能實際狀況不是這個樣子。但是思路可能差點兒相同,僅供參考。
固然,在該項目中還集成了很多別的主要的東西,比方ImageLoader圖片載入。Volley請求工具,json解析工具等,假設是做爲一個新項目的話,本項目仍是可以做爲一個最主要的起始項目來用用。網絡