GooglePlayNotes Day02

#Day02 #

#首页布局实现 ##

使用ListView加载假数据

	HomeFragment.java

	@Override

	public View onCreateSuccessView() {

		ListView view = new ListView(UIUtils.getContext());

		initData();

		view.setAdapter(new HomeAdapter());

		return view;

	}



	private void initData() {

		for (int i = 0; i < 50; i++) {

			mList.add("测试数据" + i);

		}

	}



	class HomeAdapter extends BaseAdapter {



		@Override

		public int getCount() {

			return mList.size();

		}



		@Override

		public String getItem(int position) {

			return mList.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) {

				convertView = View.inflate(UIUtils.getContext(),

						R.layout.list_item_home, null);

				holder = new ViewHolder();

				holder.tvContent = (TextView) convertView

						.findViewById(R.id.tv_content);

				convertView.setTag(holder);

			} else {

				holder = (ViewHolder) convertView.getTag();

			}



			holder.tvContent.setText(getItem(position));



			return convertView;

		}

	}



	static class ViewHolder {

		public TextView tvContent;

	}

BaseAdapter抽取

	/**
  • 数据适配器的基类
     *

  • @author Kevin
     * 
     */
     public class MyBaseAdapter extends BaseAdapter {

      	private ArrayList<T> list;
    
      
    
      	public MyBaseAdapter(ArrayList<T> list) {
    
      		this.list = list;
    
      	}
    
      
    
      	@Override
    
      	public int getCount() {
    
      		return list.size();
    
      	}
    
      
    
      	@Override
    
      	public T getItem(int position) {
    
      		return list.get(position);
    
      	}
    
      
    
      	@Override
    
      	public long getItemId(int position) {
    
      		return position;
    
      	}
    
      
    
      	@Override
    
      	public View getView(int position, View convertView, ViewGroup parent) {
    
      		return null;
    
      	}
    
      }
    

BaseHolder抽取

	/**
  • ViewHolder的基类
     *

  • 此类实现了以下功能

    1. 初始化item布局
    1. findViewById方法(由子类在初始化布局时实现)
    1. 给view设置tag
    1. 刷新界面
       *
  • 此类相当于是对getView方法的封装
     *

  • @author Kevin
     * 
     */
     public abstract class BaseHolder {

      	private View mRootView;// item的布局对象
    
      	private T data;// item对应的数据
    
      
    
      	public BaseHolder() {
    
      		mRootView = initView();// 初始化布局
    
      		mRootView.setTag(this);// 给view设置tag
    
      	}
    
      
    
      	// 初始化布局的方法必须由子类实现
    
      	public abstract View initView();
    
      
    
      	// 返回布局对象
    
      	public View getRootView() {
    
      		return mRootView;
    
      	};
    
      
    
      	// 设置数据
    
      	public void setData(T data) {
    
      		this.data = data;
    
      		refreshView(data);
    
      	}
    
      
    
      	// 获取数据
    
      	public T getData() {
    
      		return data;
    
      	}
    
      
    
      	// 刷新界面,更新数据,子类必须实现
    
      	public abstract void refreshView(T data);
    
      }
    
    
    
      -------------------------------------------
    
      MyBaseAdapter.java
    
    
    
      @Override
    
      public View getView(int position, View convertView, ViewGroup parent) {
    
      	BaseHolder<T> holder = null;
    
      	if (convertView == null) {
    
      		// 在初始化holder的同时,已经对布局进行了加载,也给view设置了tag
    
      		holder = getHolder(position);
    
      	} else {
    
      		holder = (BaseHolder<T>) convertView.getTag();
    
      	}
    
      	// 刷新界面,更新数据
    
      	holder.setData(getItem(position));
    
    
    
      	return holder.getRootView();
    
      }
    
    
    
      // 返回BaseHolder的子类,必须实现
    
      public abstract BaseHolder<T> getHolder(int position);
    
    
    
      ----------------------------------------------
    
    
    
      /**
    
  • 首页holder
     *

  • @author Kevin
     * 
     */
     public class HomeHolder extends BaseHolder {

      	private TextView tvContent;
    
      
    
      	@Override
    
      	public View initView() {
    
      		View view = View.inflate(UIUtils.getContext(), R.layout.list_item_home,
    
      				null);
    
      		tvContent = (TextView) view.findViewById(R.id.tv_content);
    
      		return view;
    
      	}
    
      
    
      	@Override
    
      	public void refreshView(String data) {
    
      		tvContent.setText(data);
    
      	}
    
      }
    
    
    
      ---------------------------------------------
    
    
    
      class HomeAdapter extends MyBaseAdapter<String> {
    
    
    
      	public HomeAdapter(ArrayList<String> list) {
    
      		super(list);
    
      	}
    
    
    
      	@Override
    
      	public BaseHolder<String> getHolder(int position) {
    
      		return new HomeHolder();
    
      	}
    
      }
    

加载更多抽取 ##

加载更多的布局作为listview最后一个item来展现

MyBaseAdapter

	private static final int ITEM_LORD_MORE = 0;// 更多布局类型

	private static final int ITEM_LIST_VIEW = 1;// 普通布局类型



	@Override

	public int getCount() {

		return list.size() + 1;// 加载更多布局也占一个位置,所以数量加1

	}

	

	@Override

	public int getViewTypeCount() {

		return 2;// 两种布局类型,一种普通布局,一种加载更多的布局

	}



	@Override

	public int getItemViewType(int position) {

		if (position == getCount() - 1) {

			// 最后一个条目

			return ITEM_LORD_MORE;

		} else {

			// 返回普通布局类型

			return getInnerType(position);

		}

	}



	// 普通布局也有可能返回多种类型, 重写改方法,可以返回更多普通布局的类型

	public int getInnerType(int position) {

		return ITEM_LIST_VIEW;

	}



	@Override

	public View getView(int position, View convertView, ViewGroup parent) {

		BaseHolder holder = null;

		if (convertView == null) {

			//根据当前item的类型来初始化不同的Holder对象

			if (getItemViewType(position) == ITEM_LORD_MORE) {

				// 返回加载更多Holder对象

				// 因为所有界面加载更多的UI显示效果都是一致的,所以加载更多的业务逻辑可以做详细处理

				holder = new MoreHolder();

			} else {

				// 在初始化holder的同时,已经对布局进行了加载,也给view设置了tag

				holder = getHolder(position);

			}

		} else {

			holder = (BaseHolder) convertView.getTag();

		}



		if (getItemViewType(position) != ITEM_LORD_MORE) {

			// 刷新界面,更新数据

			holder.setData(getItem(position));

		} 



		return holder.getRootView();

	}

MoreHolder

	/**
  • MoreHolder的数据类型为整数,用来表示加载的几种状态
     */
     public class MoreHolder extends BaseHolder {

      @Override
    
      public View initView() {
    
      	View view = View.inflate(UIUtils.getContext(),
    
      			R.layout.layout_loading_more, null);
    
      	return view;
    
      }
    
    
    
      @Override
    
      public void refreshView(Integer data) {
    
      }
    
    
    
      -------------------------------------------
    
    
    
      layout_loading_more.xml
    
    
    
      <LinearLayout
    
          android:layout_width="match_parent"
    
          android:layout_height="wrap_content"
    
          android:gravity="center"
    
          android:orientation="horizontal" >
    
    
    
          <ProgressBar
    
              android:layout_width="wrap_content"
    
              android:layout_height="wrap_content"
    
              android:indeterminateDrawable="@drawable/custom_progress" />
    
    
    
          <TextView
    
              android:id="@+id/textView1"
    
              android:layout_width="wrap_content"
    
              android:layout_height="wrap_content"
    
              android:layout_marginLeft="5dp"
    
              android:text="正在加载..."
    
              android:textColor="#000"
    
              android:textSize="16sp" />
    
       </LinearLayout>
    

运行项目, 发现主页面HomeFragment增加了加载更多的item布局

加载更多布局状态

	某些页面不需要加载更多数据,所以不能展现加载更多的布局; 而某些页面加载布局时有可能失败,这时候应该展示"加载失败,点击重试"的布局,所以加载更多的布局分如下三种状态进行展示:



	public static final int TYPE_HAS_MORE = 0;// 可以加载更多

	public static final int TYPE_NO_MORE = 1;// 不能加载更多

	public static final int TYPE_LOAD_ERROR = 2;// 加载更多失败



	------------------------------------------------------



	在初始化MoreHolder时,就应该确定好是否支持加载更多的布局展示:

	

	public MoreHolder(boolean hasMore) {

		// 将加载类型以数据的方式设置进去

		setData(hasMore ? TYPE_HAS_MORE : TYPE_NO_MORE);

	}



	------------------------------------------------------



	加载更多的布局文件更新(新增加载失败的布局):



	<?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="wrap_content"

	    android:orientation="vertical" >

	

	    <LinearLayout

	        android:id="@+id/ll_loading_more"

	        android:layout_width="match_parent"

	        android:layout_height="wrap_content"

	        android:gravity="center"

	        android:orientation="horizontal" >

	

	        <ProgressBar

	            android:layout_width="wrap_content"

	            android:layout_height="wrap_content"

	            android:indeterminateDrawable="@drawable/custom_progress" />

	

	        <TextView

	            android:id="@+id/textView1"

	            android:layout_width="wrap_content"

	            android:layout_height="wrap_content"

	            android:layout_marginLeft="5dp"

	            android:text="正在加载..."

	            android:textColor="#000"

	            android:textSize="16sp" />

	    </LinearLayout>

	

	    <TextView

	        android:id="@+id/tv_load_error"

	        android:layout_width="match_parent"

	        android:layout_height="wrap_content"

	        android:gravity="center"

			android:padding="10dp"

	        android:text="加载失败,点击重试"

	        android:textColor="#000"

	        android:textSize="16sp" />

	

	</LinearLayout>



	---------------------------------------------------------



	刷新界面时,要根据当前的状态来更新布局展示



	@Override

	public void refreshView(Integer data) {

		// 根据当前状态,来更新界面展示

		switch (data) {

		case TYPE_HAS_MORE:

			llLoadingMore.setVisibility(View.VISIBLE);

			tvLoadError.setVisibility(View.GONE);

			break;

		case TYPE_NO_MORE:

			llLoadingMore.setVisibility(View.GONE);

			tvLoadError.setVisibility(View.GONE);

			break;

		case TYPE_LOAD_ERROR:

			llLoadingMore.setVisibility(View.GONE);

			tvLoadError.setVisibility(View.VISIBLE);

			break;

		}

	}

MyBaseAdapter添加hasMore方法

	@Override

	public View getView(int position, View convertView, ViewGroup parent) {

		BaseHolder holder = null;

		if (convertView == null) {

			// 根据当前item的类型来初始化不同的Holder对象

			if (getItemViewType(position) == ITEM_LORD_MORE) {

				// 返回加载更多Holder对象

				// 因为所有界面加载更多的UI显示效果都是一致的,所以加载更多的业务逻辑可以做详细处理

				holder = new MoreHolder(hasMore());

			} else {

				// 在初始化holder的同时,已经对布局进行了加载,也给view设置了tag

				holder = getHolder(position);

			}

		} else {

			holder = (BaseHolder) convertView.getTag();

		}



		if (getItemViewType(position) != ITEM_LORD_MORE) {

			// 刷新界面,更新数据

			holder.setData(getItem(position));

		} else {

			// 如果当前展示的是加载更多的布局,需要开始加载下一页数据

			MoreHolder moreHolder = (MoreHolder) holder;

			if (moreHolder.getData() == MoreHolder.TYPE_HAS_MORE) {// 加载之前要判断是否有更多数据

				loadMore(moreHolder);

			}

		}



		return holder.getRootView();

	}





	// 返回是否需要加载更多数据, 子类可以重写该方法

	public boolean hasMore() {

		return true;

	}

修改hasMore的返回值,true或false,分别进行演示效果(展示或不展示加载更多布局)

MyBaseAdapter加载更多数据

	private boolean isLoadMore = false;//标记当前是否正在加载更多



	/**
  • 加载更多数据
     */
     public void loadMore(final MoreHolder holder) {
     if (!isLoadMore) {
     isLoadMore = true;
     new Thread() {
     @Override
     public void run() {
     //获取更多数据
     final ArrayList moreList = onLoadMore();

      				UIUtils.runOnUiThread(new Runnable() {
    
      
    
      					@Override
    
      					public void run() {
    
      						if (moreList == null) {// 如果没有拿到数据,说明加载失败
    
      							holder.setData(MoreHolder.TYPE_LOAD_ERROR);
    
      						} else {
    
      							// 每页返回20条数据,如果发现获取数据小于20条,说明已经没有更多数据了
    
      							if (moreList.size() < 20) {
    
      								holder.setData(MoreHolder.TYPE_NO_MORE);
    
      							} else {
    
      								holder.setData(MoreHolder.TYPE_HAS_MORE);
    
      							}
    
      
    
      							// 将下一页的数据追加到当前集合当中
    
      							list.addAll(moreList);
    
      							// 刷新当前listview
    
      							notifyDataSetChanged();
    
      						}
    
    
    
      						isLoadMore = false;
    
      					}
    
      				});
    
      			}
    
      		}.start();
    
      	}
    
      }
    
    
    
      // 加载更多数据,必须由子类实现
    
      public abstract ArrayList<T> onLoadMore();
    
    
    
      --------------------------------------------------------
    
      HomeFragment.java
    
    
    
      class HomeAdapter extends MyBaseAdapter<String> {
    
    
    
      	public HomeAdapter(ArrayList<String> list) {
    
      		super(list);
    
      	}
    
    
    
      	@Override
    
      	public BaseHolder<String> getHolder(int position) {
    
      		return new HomeHolder();
    
      	}
    
    
    
      	@Override
    
      	public ArrayList<String> onLoadMore() {
    
      		// 模拟更多数据
    
      		// 初始化20条下一页的测试数据
    
      		ArrayList<String> moreList = new ArrayList<String>();
    
      		for (int i = 20; i < 40; i++) {
    
      			moreList.add("测试数据" + i);
    
      		}
    
    
    
      		SystemClock.sleep(2000);// 模拟耗时操作
    
    
    
      		return moreList;
    
      	}
    
      }
    

网络框架 ##

拷贝网络框架代码和相关工具类

将http包下的几个网络请求相关的类拷贝到本项目中
将utils包下几个工具类拷贝到本项目中

IOUtils
StringUtils
LogUtils

		分别介绍这三个工具类的作用和使用方式

BaseProtocol抽取

	/**
  • 访问网络的基类
     *

  • @author Kevin
     * 
     */
     public abstract class BaseProtocol {

      	/**
    
  • 获取数据
     *

  • @param index

  •        分页请求数据的起始位置
    

*/
 public T getData(int index) {
 String result = getDataFromNet(index);
 return parseJson(result);
 }

		/**
  • 访问网络获取数据
     *

  • @param index

  •        分页请求数据的起始位置
    
  • @return
     */
     private String getDataFromNet(int index) {
     HttpResult result = HttpHelper.get(HttpHelper.URL + getKey()
    “?index=” + index + getParams());
     return result.getString();
     }

      	// 获取网络接口的具体地址,每个页面都不一样,必须由子类实现
    
      	public abstract String getKey();
    
      
    
      	// 获取网络接口的具体参数,每个页面都不一样,必须由子类实现
    
      	public abstract String getParams();
    
      
    
      	/**
    
  • 解析json数据 ,每个页面要求的解析对象都不一样,必须由子类实现
     *

  • @param result
     */
     public abstract T parseJson(String result);

      }
    

读写缓存

	/**
  • 从本地缓存中读取数据
     */
     private String getCache(int index) {
     // 获取系统缓存目录
     File cacheDir = UIUtils.getContext().getCacheDir();
     // 以网络链接作为文件名称,保证特定接口对应特定数据
     File cacheFile = new File(cacheDir, getKey() + “?index=” + index
    getParams());

      	if (cacheFile.exists()) {// 缓存文件存在
    
      		BufferedReader reader = null;
    
      		try {
    
      			reader = new BufferedReader(new FileReader(cacheFile));
    
      			String validTime = reader.readLine();// 读取第一行内容,缓存截止时间
    
      			if (System.currentTimeMillis() < Long.parseLong(validTime)) {// 当前时间小于缓存截止时间,说明缓存还在有效期范围内
    
    
    
      				String line = null;
    
      				StringBuffer sb = new StringBuffer();
    
      				while ((line = reader.readLine()) != null) {
    
      					sb.append(line);
    
      				}
    
    
    
      				return sb.toString();
    
      			}
    
    
    
      		} catch (Exception e) {
    
      			e.printStackTrace();
    
      		} finally {
    
      			IOUtils.close(reader);
    
      		}
    
      	}
    
    
    
      	return null;
    
      }
    
    
    
      /**
    
  • 向本地缓存写数据
     */
     private void setCache(String result, int index) {
     // 获取系统缓存目录
     File cacheDir = UIUtils.getContext().getCacheDir();
     // 以网络链接作为文件名称,保证特定接口对应特定数据
     File cacheFile = new File(cacheDir, getKey() + “?index=” + index
    getParams());

      	FileWriter writer = null;
    
      	try {
    
      		writer = new FileWriter(cacheFile);
    
    
    
      		// 缓存有效期限, 截止时间设定为半小时之后
    
      		long validTime = System.currentTimeMillis() + 30  60  1000;
    
      		writer.write(validTime + "\n");// 将缓存截止时间写入文件第一行
    
      		writer.write(result);
    
      		writer.flush();
    
      	} catch (IOException e) {
    
      		e.printStackTrace();
    
      	} finally {
    
      		IOUtils.close(writer);
    
      	}
    
      }
    
    
    
      ---------------------------------------------
    
    
    
      /**
    
  • 获取数据
     *

  • @param index

  •        分页请求数据的起始位置
    

*/
 public T getData(int index) {
 // 先从本地缓存中读取数据,如果有,就直接返回,如果没有,才从网络加载
 String result = getCache(index);
 if (result == null) {
 result = getDataFromNet(index);
 }

		if (result != null) {

			return parseJson(result);

		}



		return null;

	}



	/**
  • 访问网络获取数据
     *

  • @param index

  •        分页请求数据的起始位置
    
  • @return
     */
     private String getDataFromNet(int index) {
     HttpResult result = HttpHelper.get(HttpHelper.URL + getKey()
    “?index=” + index + getParams());
     if (result != null) {
     String strResult = result.getString();
     if (!StringUtils.isEmpty(strResult)) {
     // 将缓存写到本地文件中
     setCache(strResult, index);
     return strResult;
     }
     }

      	return null;
    
      }
    

HomeProtocol实现&解析json

	/**
  • 首页应用信息封装
     *

  • @author Kevin
     *
     */
     public class AppInfo {

      	public String des;
    
      	public String downloadUrl;
    
      	public String iconUrl;
    
      	public String id;
    
      	public String name;
    
      	public String packageName;
    
      	public String size;
    
      	public double stars;
    
      	
    
      }
    
    
    
      ---------------------------------------------
    
    
    
      /**
    
  • 首页访问网络
     *

  • @author Kevin
     * 
     */
     public class HomeProtocol extends BaseProtocol<ArrayList> {

      	private ArrayList<AppInfo> mAppList;// 应用列表集合
    
      	private ArrayList<String> mPicList;// 广告图片url集合
    
      
    
      	@Override
    
      	public String getKey() {
    
      		return "home";
    
      	}
    
      
    
      	@Override
    
      	public String getParams() {
    
      		return "";
    
      	}
    
      
    
      	@Override
    
      	public ArrayList<AppInfo> parseJson(String result) {
    
      		try {
    
      			JSONObject jo = new JSONObject(result);
    
      
    
      			// 解析应用列表集合
    
      			JSONArray ja = jo.getJSONArray("list");
    
      			mAppList = new ArrayList<AppInfo>();
    
      			for (int i = 0; i < ja.length(); i++) {
    
      				AppInfo info = new AppInfo();
    
      
    
      				JSONObject jo1 = (JSONObject) ja.get(i);
    
      				info.des = jo1.getString("des");
    
      				info.downloadUrl = jo1.getString("downloadUrl");
    
      				info.iconUrl = jo1.getString("iconUrl");
    
      				info.id = jo1.getString("id");
    
      				info.name = jo1.getString("name");
    
      				info.packageName = jo1.getString("packageName");
    
      				info.size = jo1.getString("size");
    
      				info.stars = jo1.getDouble("stars");
    
      
    
      				mAppList.add(info);
    
      			}
    
      
    
      			// 解析头条广告图片信息
    
      			mPicList = new ArrayList<String>();
    
      			JSONArray ja1 = jo.getJSONArray("picture");
    
      			for (int i = 0; i < ja1.length(); i++) {
    
      				mPicList.add(ja1.getString(i));
    
      			}
    
      
    
      			return mAppList;
    
      
    
      		} catch (Exception e) {
    
      			e.printStackTrace();
    
      		}
    
      		return null;
    
      	}
    
      
    
      }
    

测试首页网络数据的加载

	HomeFragment.java



	@Override

	public ResultState onLoad() {

		//从网络加载数据

		HomeProtocol protocol = new HomeProtocol();

		mList = protocol.getData(0);//加载第一页数据

		return ResultState.STATE_SUCCESS;

	}



	@Override

	public ArrayList<AppInfo> onLoadMore() {

		return null;

	}



	------------------------------------

	HomeHolder.java



	@Override

	public void refreshView(AppInfo data) {

		tvContent.setText(data.name);

	}

校验网络数据合法性

	BaseFragment.java



	/**
  • 校验数据的合法性,返回相应的状态

  • @param data

  • @return
     */
     public ResultState check(Object data) {
     if (data != null) {
     if (data instanceof List) {//判断当前对象是否是一个集合
     List list = (List) data;
     if (!list.isEmpty()) {//数据不为空,访问成功
     return ResultState.STATE_SUCCESS;
     } else {//空集合
     return ResultState.STATE_EMPTY;
     }
     }
     }

      	return ResultState.STATE_ERROR;
    
      }
    
    
    
      -----------------------------------
    
      HomeFragment.java
    
    
    
      @Override
    
      public ResultState onLoad() {
    
      	// 从网络加载数据
    
      	HomeProtocol protocol = new HomeProtocol();
    
      	mList = protocol.getData(0);// 加载第一页数据
    
    
    
      	return check(mList);
    
      }
    
  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值