【0090】【项目实战】-【谷歌电子市场】-【02】【ListView封装】【listview增加加载更多布局】【加载更多功能添加】【导入http工具包&相关工具类】【BaseProtocol创建&拼接网络链接】【读写缓存&解析数据】【HomeProtocol实现&Json解析】【加载首页数据】
1. 回顾说明
【说明】Application一定需要在清单配置文件中配置一下,否则无法初始化变量GooglePlayApplication.java中的变量;

2.ListView第一层封装
【说明】首页中的布局是listView显示;

2.1 最简单的listView的书写
【new 一个listView】


【适配器数据】

【添加假数据】添加假数据,在集合中添加测试数据;


【listView的item的布局】

【ListView的convertView的复用】

【设置适配器】

【效果】

2.2 ListView的简单封装
【说明】
【封转的原因】在每次书写listView的时候总是需要写前面的三个方法,并且内容都基本一致;封装是为了简化代码的书写;

【第一层封装的思路】生成一个类,继承与BaseAdapter,该类实现了前面三个方法;
【类中的泛型的使用】【技巧】在类的定义的时候直接增加泛型;

【简单封装adpter】

【封装之后的使用】需要添加泛型的类型和实现构造方法;


【效果】跟之前的效果一模一样,大大简化了代码,只需要书写adapter中的getView方法即可;

3.ListView第二层封装
【说明】主要是对getView方法的封装;
【说明】getView分解为主要做下面的四件事情;需要ViewHolder的配合;父类完成不了事情让子类完成;

3.1BaseHolder的封装
【说明】BaseHolder主要完成对应的getView中的一些功能;

【BaseHolder的使用】
【说明】因为BaseHolder不能直接new,需要子类实现未实现的方法initView(只有子类才知道自己本身需要初始化哪些布局和控件),因此在此再次书写一个抽象方法,让子类实现;


3.2 【getView使用BaseHolder】


【注销原来的getView方法】

【子类实现加载布局和刷新的方法】

【HomeFragment调用Holder】很简洁,代码量很少;


【bug】返回值有问题,应该返回Holder中的RootView布局;


【效果】跟之前的效果一致;

【说明】listView在项目中使用个情况较多,则需要搭建此此框架,如果仅仅使用一个则不需要搭建框架;
【源码】/GooglePlay74/src/com/itheima/googleplay74/ui/holder/BaseHolder.java
1 package com.itheima.googleplay74.ui.holder; 2 3 import android.view.View; 4 5 public abstract class BaseHolder<T> { 6 7 private View mRootView;// 一个item的根布局 8 9 private T data; 10 11 //当new这个对象时, 就会加载布局, 初始化控件,设置tag 12 public BaseHolder() { 13 mRootView = initView(); 14 // 3. 打一个标记tag 15 mRootView.setTag(this); 16 } 17 18 // 1. 加载布局文件 19 // 2. 初始化控件 findViewById 20 public abstract View initView(); 21 22 // 返回item的布局对象 23 public View getRootView() { 24 return mRootView; 25 } 26 27 // 设置当前item的数据 28 public void setData(T data) { 29 this.data = data; 30 refreshView(data); 31 } 32 33 // 获取当前item的数据 34 public T getData() { 35 return data; 36 } 37 38 // 4. 根据数据来刷新界面 39 public abstract void refreshView(T data); 40 41 }
【源码】/GooglePlay74/src/com/itheima/googleplay74/ui/holder/HomeHolder.java
1 package com.itheima.googleplay74.ui.holder; 2 3 import android.view.View; 4 import android.widget.TextView; 5 6 import com.itheima.googleplay74.R; 7 import com.itheima.googleplay74.domain.AppInfo; 8 import com.itheima.googleplay74.utils.UIUtils; 9 /** 10 * 首页holder 11 * @author Kevin 12 * @date 2015-10-28 13 */ 14 public class HomeHolder extends BaseHolder<AppInfo> { 15 16 private TextView tvContent; 17 18 @Override 19 public View initView() { 20 // 1. 加载布局 21 View view = UIUtils.inflate(R.layout.list_item_home); 22 // 2. 初始化控件 23 tvContent = (TextView) view.findViewById(R.id.tv_content); 24 return view; 25 } 26 27 @Override 28 public void refreshView(AppInfo data) { 29 tvContent.setText(data.name); 30 } 31 32 }

4.listview增加加载更多布局
4.1 效果及思路
【效果】如下,将下拉加载更多封装到listView中;
【说明】之前使用的增加一个脚布局,现在使用的另外一种思路实现,使用listView加载多种布局(安全卫士当中使用过);


4.2 源码实现
【说明】需要重写这两个方法

【增加了一个布局,因此数量增加1】

【定义两种类型】

【局限性】有的页面的布局类型超过了两种,但是下面的写法只支持两种,因此具有局限性;

[此页面具有三种类型]使用的是listView开发的;

[改进]多一个方法,默认值写为TYPE_NORMAL,但是子类可以复写该方法,增加类型,变得灵活了;

【增加加载更多布局】




【加载更多的布局】


【加载布局】

【效果】

5.加载更多布局根据状态刷新页面
5.1 存在的三种状态

【存在的三种状态】

5.2 没有更多数据
【说明】在某些页面是天生没有更多数据的,比如分类,在构造法中直接表明该页面是否具有更多数据


【灵活变通】子类重写方法修改是否可以具有加载更多的属性;


【根据data值refreshView框架】

【将多种布局放在一个xml中】根据情况进行显示或者隐藏;

[源码]/GooglePlay74/res/layout/list_item_more.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="wrap_content" 5 android:gravity="center" 6 android:orientation="vertical" > 7 8 <LinearLayout 9 android:id="@+id/ll_load_more" 10 android:layout_width="match_parent" 11 android:layout_height="wrap_content" 12 android:gravity="center" 13 android:orientation="horizontal" > 14 15 <ProgressBar 16 android:id="@+id/progressBar1" 17 android:layout_width="wrap_content" 18 android:layout_height="wrap_content" 19 android:indeterminateDrawable="@drawable/custom_progress" /> 20 21 <TextView 22 android:layout_width="wrap_content" 23 android:layout_height="wrap_content" 24 android:layout_marginLeft="5dp" 25 android:text="加载中..." 26 android:textColor="#000" 27 android:textSize="20sp" /> 28 </LinearLayout> 29 30 <TextView 31 android:id="@+id/tv_load_error" 32 android:layout_width="wrap_content" 33 android:layout_height="wrap_content" 34 android:paddingTop="10dp" 35 android:paddingBottom="10dp" 36 android:layout_marginLeft="5dp" 37 android:text="加载失败,点击重试" 38 android:textColor="#000" 39 android:textSize="20sp" /> 40 41 </LinearLayout>
【根据data值refreshView更改显示隐藏布局】

【效果】隐藏布局

[隐藏布局的调用关系]页面子类重写hasMore()方法,返回值为false;将返回值false传递给父类,然后设置data,然后刷新页面;

6.加载更多数据逻辑
6.1 加载更多数据的逻辑
【框架】请求加载更多的数据框架,需要开辟子线程,请求数据;

【对数据的判断】
[没有更多数据了]

[有更多数据]

[标记的添加]


【将数据追加到当前的listView后面,然后刷新页面】

6.2 加载更多数据的方法的调用时机
【说明】调用加载更多数据的逻辑可以有两种,一种是了listView进行监听,但是比较繁琐,每一个listView可能都需要设置listener事件;
另外一种就是根据搭建的框架,直接在适配器的父类中进行设置,如下面的,根据数据来刷新页面,选择这种方式;


6.3 子类实现加载更多数据的方法
【说明】此方法运行在子线程中,因为被调用是子线程中;

【加载成功效果】测试加载成功的状态

【加载失败的效果】


【没有更多数据的效果】


6.4 注意
【说明】没有整明白为什么需要从0开始;

7.导入http工具包&相关工具类
7.1 【LogUtils工具类的作用】
打印分等级的日志信息,可以在上线之前进行关闭,避免性能的浪费和敏感信息的被捕获;
/GooglePlay74/src/com/itheima/googleplay74/utils//GooglePlay74/src/com/itheima/googleplay74/utils/LogUtils.java
【源码】
1 package com.itheima.googleplay74.utils; 2 import android.util.Log; 3 4 5 public class LogUtils { 6 /** 日志输出级别NONE */ 7 public static final int LEVEL_NONE = 0; 8 /** 日志输出级别E */ 9 public static final int LEVEL_ERROR =1; 10 /** 日志输出级别W */ 11 public static final int LEVEL_WARN = 2; 12 /** 日志输出级别I */ 13 public static final int LEVEL_INFO = 3; 14 /** 日志输出级别D */ 15 public static final int LEVEL_DEBUG = 4; 16 /** 日志输出级别V */ 17 public static final int LEVEL_VERBOSE = 5; 18 19 /** 日志输出时的TAG */ 20 private static String mTag = "LogUtils"; 21 /** 是否允许输出log */ 22 private static int mDebuggable = LEVEL_VERBOSE; //在上线之前将此处改为:LEVEL_NONE,则可以屏蔽掉所有的打印信息; 23 24 /** 以级别为 d 的形式输出LOG */ 25 public static void v(String msg) { 26 if (mDebuggable >= LEVEL_VERBOSE) { 27 Log.v(mTag, msg); 28 } 29 } 30 31 /** 以级别为 d 的形式输出LOG */ 32 public static void d(String msg) { 33 if (mDebuggable >= LEVEL_DEBUG) { 34 Log.d(mTag, msg); 35 } 36 } 37 38 /** 以级别为 i 的形式输出LOG */ 39 public static void i(String msg) { 40 if (mDebuggable >= LEVEL_INFO) { 41 Log.i(mTag, msg); 42 } 43 } 44 45 /** 以级别为 w 的形式输出LOG */ 46 public static void w(String msg) { 47 if (mDebuggable >= LEVEL_WARN) { 48 Log.w(mTag, msg); 49 } 50 } 51 52 /** 以级别为 w 的形式输出Throwable */ 53 public static void w(Throwable tr) { 54 if (mDebuggable >= LEVEL_WARN) { 55 Log.w(mTag, "", tr); 56 } 57 } 58 59 /** 以级别为 w 的形式输出LOG信息和Throwable */ 60 public static void w(String msg, Throwable tr) { 61 if (mDebuggable >= LEVEL_WARN && null != msg) { 62 Log.w(mTag, msg, tr); 63 } 64 } 65 66 /** 以级别为 e 的形式输出LOG */ 67 public static void e(String msg) { 68 if (mDebuggable >= LEVEL_ERROR) { 69 Log.e(mTag, msg); 70 } 71 } 72 73 /** 以级别为 e 的形式输出Throwable */ 74 public static void e(Throwable tr) { 75 if (mDebuggable >= LEVEL_ERROR) { 76 Log.e(mTag, "", tr); 77 } 78 } 79 80 /** 以级别为 e 的形式输出LOG信息和Throwable */ 81 public static void e(String msg, Throwable tr) { 82 if (mDebuggable >= LEVEL_ERROR && null != msg) { 83 Log.e(mTag, msg, tr); 84 } 85 } 86 }
7.2 【/StringUtils.java类使用的作用】
/GooglePlay74/src/com/itheima/googleplay74/utils/StringUtils.java
【说明】类比于TextUtils.isempty,但是此处判断的更严谨:包括为值不为null,去除了空格之后的大小写和不论大小写的null。都会进入到判断;
1 package com.itheima.googleplay74.utils; 2 3 4 public class StringUtils { 5 /** 判断字符串是否有值,如果为null或者是空字符串或者只有空格或者为"null"字符串,则返回true,否则则返回false */ 6 public static boolean isEmpty(String value) { 7 if (value != null && !"".equalsIgnoreCase(value.trim()) 8 && !"null".equalsIgnoreCase(value.trim())) { 9 return false; 10 } else { 11 return true; 12 } 13 } 14 }
7.3 【IOUtils.java类的作用】
/GooglePlay74/src/com/itheima/googleplay74/utils/IOUtils.java
【说明】Closeable指的是可以关闭的一些类,除了stream,还有其他的类型;
包含了异常的捕获;
1 package com.itheima.googleplay74.utils; 2 3 import java.io.Closeable; 4 import java.io.IOException; 5 6 public class IOUtils { 7 /** 关闭流 */ 8 public static boolean close(Closeable io) { 9 if (io != null) { 10 try { 11 io.close(); 12 } catch (IOException e) { 13 LogUtils.e(e); 14 } 15 } 16 return true; 17 } 18 }
7.4 http工具包
【包含的文件】两个HttpHelper.java和HttpClientFactory.java;

【源码】/GooglePlay74/src/com/itheima/googleplay74/http/HttpHelper.java
1 package com.itheima.googleplay74.http; 2 3 import java.io.ByteArrayOutputStream; 4 import java.io.IOException; 5 import java.io.InputStream; 6 7 import org.apache.http.HttpEntity; 8 import org.apache.http.HttpResponse; 9 import org.apache.http.StatusLine; 10 import org.apache.http.client.HttpClient; 11 import org.apache.http.client.HttpRequestRetryHandler; 12 import org.apache.http.client.methods.HttpGet; 13 import org.apache.http.client.methods.HttpPost; 14 import org.apache.http.client.methods.HttpRequestBase; 15 import org.apache.http.entity.ByteArrayEntity; 16 import org.apache.http.impl.client.AbstractHttpClient; 17 import org.apache.http.protocol.BasicHttpContext; 18 import org.apache.http.protocol.HttpContext; 19 import org.apache.http.protocol.SyncBasicHttpContext; 20 21 import android.util.Log; 22 23 import com.itheima.googleplay74.utils.IOUtils; 24 import com.itheima.googleplay74.utils.LogUtils; 25 import com.itheima.googleplay74.utils.StringUtils; 26 27 public class HttpHelper { 28 29 public static final String URL = "http://127.0.0.1:8090/"; 30 31 /** get请求,获取返回字符串内容 */ 32 public static HttpResult get(String url) { 33 HttpGet httpGet = new HttpGet(url); 34 return execute(url, httpGet); 35 } 36 37 /** post请求,获取返回字符串内容 */ 38 public static HttpResult post(String url, byte[] bytes) { 39 HttpPost httpPost = new HttpPost(url); 40 ByteArrayEntity byteArrayEntity = new ByteArrayEntity(bytes); 41 httpPost.setEntity(byteArrayEntity); 42 return execute(url, httpPost); 43 } 44 45 /** 下载 */ 46 public static HttpResult download(String url) { 47 HttpGet httpGet = new HttpGet(url); 48 return execute(url, httpGet); 49 } 50 51 /** 执行网络访问 */ 52 private static HttpResult execute(String url, HttpRequestBase requestBase) { 53 boolean isHttps = url.startsWith("https://");//判断是否需要采用https 54 AbstractHttpClient httpClient = HttpClientFactory.create(isHttps); 55 HttpContext httpContext = new SyncBasicHttpContext(new BasicHttpContext()); 56 HttpRequestRetryHandler retryHandler = httpClient.getHttpRequestRetryHandler();//获取重试机制 57 int retryCount = 0; 58 boolean retry = true; 59 while (retry) { 60 try { 61 HttpResponse response = httpClient.execute(requestBase, httpContext);//访问网络 62 if (response != null) { 63 return new HttpResult(response, httpClient, requestBase); 64 } 65 } catch (Exception e) { 66 IOException ioException = new IOException(e.getMessage()); 67 retry = retryHandler.retryRequest(ioException, ++retryCount, httpContext);//把错误异常交给重试机制,以判断是否需要采取从事 68 LogUtils.e(e); 69 } 70 } 71 return null; 72 } 73 74 /** http的返回结果的封装,可以直接从中获取返回的字符串或者流 */ 75 public static class HttpResult { 76 private HttpResponse mResponse; 77 private InputStream mIn; 78 private String mStr; 79 private HttpClient mHttpClient; 80 private HttpRequestBase mRequestBase; 81 82 public HttpResult(HttpResponse response, HttpClient httpClient, HttpRequestBase requestBase) { 83 mResponse = response; 84 mHttpClient = httpClient; 85 mRequestBase = requestBase; 86 } 87 88 public int getCode() { 89 StatusLine status = mResponse.getStatusLine(); 90 return status.getStatusCode(); 91 } 92 93 /** 从结果中获取字符串,一旦获取,会自动关流,并且把字符串保存,方便下次获取 */ 94 public String getString() { 95 if (!StringUtils.isEmpty(mStr)) { 96 return mStr; 97 } 98 InputStream inputStream = getInputStream(); 99 ByteArrayOutputStream out = null; 100 if (inputStream != null) { 101 try { 102 out = new ByteArrayOutputStream(); 103 byte[] buffer = new byte[1024 * 4]; 104 int len = -1; 105 while ((len = inputStream.read(buffer)) != -1) { 106 out.write(buffer, 0, len); 107 } 108 byte[] data = out.toByteArray(); 109 mStr = new String(data, "utf-8"); 110 } catch (Exception e) { 111 LogUtils.e(e); 112 } finally { 113 IOUtils.close(out); 114 close(); 115 } 116 } 117 return mStr; 118 } 119 120 /** 获取流,需要使用完毕后调用close方法关闭网络连接 */ 121 public InputStream getInputStream() { 122 if (mIn == null && getCode() < 300) { 123 HttpEntity entity = mResponse.getEntity(); 124 try { 125 mIn = entity.getContent(); 126 } catch (Exception e) { 127 LogUtils.e(e); 128 } 129 } 130 return mIn; 131 } 132 133 /** 关闭网络连接 */ 134 public void close() { 135 if (mRequestBase != null) { 136 mRequestBase.abort(); 137 } 138 IOUtils.close(mIn); 139 if (mHttpClient != null) { 140 mHttpClient.getConnectionManager().closeExpiredConnections(); 141 } 142 } 143 } 144 }
【源码】/GooglePlay74/src/com/itheima/googleplay74/http/HttpClientFactory.java
1 package com.itheima.googleplay74.http; 2 3 import org.apache.http.HttpVersion; 4 import org.apache.http.client.params.HttpClientParams; 5 import org.apache.http.conn.params.ConnManagerParams; 6 import org.apache.http.conn.params.ConnPerRouteBean; 7 import org.apache.http.conn.scheme.PlainSocketFactory; 8 import org.apache.http.conn.scheme.Scheme; 9 import org.apache.http.conn.scheme.SchemeRegistry; 10 import org.apache.http.conn.ssl.SSLSocketFactory; 11 import org.apache.http.impl.client.DefaultHttpClient; 12 import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; 13 import org.apache.http.params.BasicHttpParams; 14 import org.apache.http.params.HttpConnectionParams; 15 import org.apache.http.params.HttpParams; 16 import org.apache.http.params.HttpProtocolParams; 17 import org.apache.http.protocol.HTTP; 18 19 public class HttpClientFactory { 20 /** http请求最大并发连接数 */ 21 private static final int MAX_CONNECTIONS = 10; 22 /** 超时时间 */ 23 private static final int TIMEOUT = 10 * 1000; 24 /** 缓存大小 */ 25 private static final int SOCKET_BUFFER_SIZE = 8 * 1024; // 8KB 26 27 public static DefaultHttpClient create(boolean isHttps) { 28 HttpParams params = createHttpParams(); 29 DefaultHttpClient httpClient = null; 30 if (isHttps) { 31 // 支持http与https 32 SchemeRegistry schemeRegistry = new SchemeRegistry(); 33 schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); 34 schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443)); 35 // ThreadSafeClientConnManager线程安全管理类 36 ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(params, schemeRegistry); 37 httpClient = new DefaultHttpClient(cm, params); 38 } else { 39 httpClient = new DefaultHttpClient(params); 40 } 41 return httpClient; 42 } 43 44 private static HttpParams createHttpParams() { 45 final HttpParams params = new BasicHttpParams(); 46 // 设置是否启用旧连接检查,默认是开启的。关闭这个旧连接检查可以提高一点点性能,但是增加了I/O错误的风险(当服务端关闭连接时)。 47 // 开启这个选项则在每次使用老的连接之前都会检查连接是否可用,这个耗时大概在15-30ms之间 48 HttpConnectionParams.setStaleCheckingEnabled(params, false); 49 HttpConnectionParams.setConnectionTimeout(params, TIMEOUT);// 设置链接超时时间 50 HttpConnectionParams.setSoTimeout(params, TIMEOUT);// 设置socket超时时间 51 HttpConnectionParams.setSocketBufferSize(params, SOCKET_BUFFER_SIZE);// 设置缓存大小 52 HttpConnectionParams.setTcpNoDelay(params, true);// 是否不使用延迟发送(true为不延迟) 53 HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); // 设置协议版本 54 HttpProtocolParams.setUseExpectContinue(params, true);// 设置异常处理机制 55 HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);// 设置编码 56 HttpClientParams.setRedirecting(params, false);// 设置是否采用重定向 57 58 ConnManagerParams.setTimeout(params, TIMEOUT);// 设置超时 59 ConnManagerParams.setMaxConnectionsPerRoute(params, new ConnPerRouteBean(MAX_CONNECTIONS));// 多线程最大连接数 60 ConnManagerParams.setMaxTotalConnections(params, 10); // 多线程总连接数 61 return params; 62 } 63 64 }
8.BaseProtocol创建&拼接网络链接

【网络封装】主要完成三件事:请求网络获取数据、缓存机制(写缓存和读缓存)、解析数据;

【网络访问地址的拼接】

【实际网址的拼接】实际的网址的拼接比较复杂;其中存在index分页返回的数据页面;

1 // 从网络获取数据 2 // index表示的是从哪个位置开始返回20条数据, 用于分页 3 private String getDataFromServer(int index) { 4 // http://www.itheima.com/home?index=0&name=zhangsan&age=18 5 HttpResult httpResult = HttpHelper.get(HttpHelper.URL + getKey() 6 + "?index=" + index + getParams()); 7 8 if (httpResult != null) { 9 String result = httpResult.getString(); 10 System.out.println("访问结果:" + result); 11 // 写缓存 12 if (!StringUtils.isEmpty(result)) { 13 setCache(index, result); 14 } 15 16 return result; 17 } 18 19 return null; 20 }
9.读写缓存&解析数据
9.1【写缓存】

【增加缓存的有效期】缓存中的数据需要定期刷新;打上时间戳就好;

【写缓存的调用】将取到的数据放入到缓存中;

9.2 读缓存数据
1 // 读缓存 2 public String getCache(int index) { 3 // 以url为文件名, 以json为文件内容,保存在本地 4 File cacheDir = UIUtils.getContext().getCacheDir();// 本应用的缓存文件夹 5 // 生成缓存文件 6 File cacheFile = new File(cacheDir, getKey() + "?index=" + index 7 + getParams()); 8 9 // 判断缓存是否存在 10 if (cacheFile.exists()) { 11 // 判断缓存是否有效 12 BufferedReader reader = null; 13 try { 14 reader = new BufferedReader(new FileReader(cacheFile)); 15 String deadline = reader.readLine();// 读取第一行的有效期 16 long deadtime = Long.parseLong(deadline); 17 18 if (System.currentTimeMillis() < deadtime) {// 当前时间小于截止时间, 19 // 说明缓存有效 20 // 缓存有效 21 StringBuffer sb = new StringBuffer(); 22 String line; 23 while ((line = reader.readLine()) != null) { //此处已经去掉了原来的时间的数据; 24 sb.append(line); 25 } 26 27 return sb.toString(); 28 } 29 30 } catch (Exception e) { 31 e.printStackTrace(); 32 } finally { 33 IOUtils.close(reader); 34 } 35 36 } 37 38 return null; 39 }
9.3 缓存数据的使用
1 // index表示的是从哪个位置开始返回20条数据, 用于分页 2 public T getData(int index) { 3 // 先判断是否有缓存, 有的话就加载缓存 4 String result = getCache(index); 5 6 if (StringUtils.isEmpty(result)) {// 如果没有缓存,或者缓存失效 7 // 请求服务器 8 result = getDataFromServer(index); 9 } 10 11 // 开始解析 12 if (result != null) { 13 T data = parseData(result); 14 return data; 15 } 16 17 return null; 18 }
9.4 解析数据的接口
【说明】因为子类的对数据的解析各不同,因此需要放到子类中去实现该方法;


10.HomeProtocol实现&Json解析
10.1.HomeProtocol 子类的建立
【新建子类,继承与父类BaseProtocol】

【泛型的确定】


10.2.json的解析
【json解析可以使用两种方法】一种是使用Gson(比较严格,遇到中括号就是数组,遇到大括号就是对象),另外一种是使用jsonObject(比较随意);
【参考json网址】http://www.json.org/json-zh.html

【泛型的替代使用的是ArrayList<AppInfo>泛型】此处的构造方法的泛型是个集合;

【源码】/GooglePlay74/src/com/itheima/googleplay74/http/protocol/HomeProtocol.java
【解析起来比较繁琐】
1 package com.itheima.googleplay74.http.protocol; 2 3 import java.util.ArrayList; 4 5 import org.json.JSONArray; 6 import org.json.JSONException; 7 import org.json.JSONObject; 8 9 import com.itheima.googleplay74.domain.AppInfo; 10 11 /** 12 * 首页网络数据解析 13 * 14 * @author Kevin 15 * @date 2015-10-28 16 */ 17 public class HomeProtocol extends BaseProtocol<ArrayList<AppInfo>> { 18 19 @Override 20 public String getKey() { 21 return "home"; 22 } 23 24 @Override 25 public String getParams() { 26 return "";// 如果没有参数,就传空串,不要传null 27 } 28 29 @Override 30 public ArrayList<AppInfo> parseData(String result) { 31 // Gson, JsonObject 32 // 使用JsonObject解析方式: 如果遇到{},就是JsonObject;如果遇到[], 就是JsonArray 33 try { 34 JSONObject jo = new JSONObject(result); 35 36 // 解析应用列表数据 37 JSONArray ja = jo.getJSONArray("list"); 38 ArrayList<AppInfo> appInfoList = new ArrayList<AppInfo>(); 39 for (int i = 0; i < ja.length(); i++) { 40 JSONObject jo1 = ja.getJSONObject(i); 41 42 AppInfo info = new AppInfo(); 43 info.des = jo1.getString("des"); 44 info.downloadUrl = jo1.getString("downloadUrl"); 45 info.iconUrl = jo1.getString("iconUrl"); 46 info.id = jo1.getString("id"); 47 info.name = jo1.getString("name"); 48 info.packageName = jo1.getString("packageName"); 49 info.size = jo1.getLong("size"); 50 info.stars = (float) jo1.getDouble("stars"); 51 52 appInfoList.add(info); 53 } 54 55 // 初始化轮播条的数据 56 JSONArray ja1 = jo.getJSONArray("picture"); 57 ArrayList<String> pictures = new ArrayList<String>(); 58 for (int i = 0; i < ja1.length(); i++) { 59 String pic = ja1.getString(i); 60 pictures.add(pic); 61 } 62 63 return appInfoList; 64 65 } catch (JSONException e) { 66 e.printStackTrace(); 67 } 68 69 return null; 70 } 71 72 }
11.加载首页数据
11.1 泛型和首页数据的加载

【泛型替换】


【加载数据】

11.2 加载的校验
【说明】网络请求回来的数据有可能是空值或者是异常的值;
【说明】对于每一个网络数据加载的页面都可以进行数据的校验,因此将校验放在父类当中;



【增加网络权限】

【效果】首页加载了第一页的数据,缺点是没有加载第二页的数据;

【加载第二页的数据】获取页面的数据的大小的时候需要将index放入,index的大小正好是加载到当前集合中数据的多少;


【将获取的数据返回】

【效果】

【查看缓存是否起到了作用】

浙公网安备 33010602011771号