这一周课很多,所以没有及时的接上。
现在的我不打算再拼命的做码农了,而是尽量的做总结。把以前写过的一些代码回忆一下,把以前有过的思路再重新寻觅一回。似乎,我好多废话。
在做Android应用程序开发时,有很多应用都会获取由Web Server返回的数据,有的可能是xml数据,有可能是json数据。他们各有应用范围。我继续总结一下获取网络json数据的一些idea。这里先分析一下业务逻辑,UI稍后再唠叨。
1.分析一下手机购物应用的执行过程。
首次执行一个MainActivity,此activity的功能是构成main UI(即下方有个Tab 菜单),由于我的没个Activity都是继承了上文中的IMActivity接口,这里实现初始化init()方法。我们都知道Activity的生命周期,所以我在onResume()方法里调用init()方法。并且,初始化方法完成几个任务。
1.1 检查网络连接
android系统有提供检测网络的api。我们可以很方便的调用。我们可以把检查网络的方法封装在一个工具类里(可根据自己的programing style)
View Code
package com.mpros.util;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
/***
* 工具类,检查当前网络状态
*
* @author shuimu
*
*/
public class NetUtil {
public static boolean checkNet(Context context) {
// 获取手机所以连接管理对象(包括wi-fi,net等连接的管理)
ConnectivityManager conn = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
if (conn != null) {
// 网络管理连接对象
NetworkInfo info = conn.getActiveNetworkInfo();
if(info != null && info.isConnected()) {
// 判断当前网络是否连接
if (info.getState() == NetworkInfo.State.CONNECTED) {
return true;
}
}
}
return false;
}
}
1.2如果网络连接正常,启动服务Service。否则提醒用户网络连接异常。网络连接异常的方法,我封装在了MainService中,可以直接invoke。
View Code
@Override
protected void onResume() {
super.onResume();
init();
}
@Override
public void init() {
if (NetUtil.checkNet(this)) {
Intent startService = new Intent("com.mpros.service.MainService");
this.startService(startService);
} else {
MainService.alerNetErr(this);
}
}
2.当MainActivity执行到onResume()方法时,会启动服务。正常情况下,MainService开始执行onCreate()方法。此方法里,启动线程,因为我的MainService是实现了Runnbale接口的。
View Code
public class MainService extends Service implements Runnable {
。。。
// 循环控制变量
private boolean isrun = true;
。。。
@Override
public void onCreate() {
super.onCreate();
isrun = true;
new Thread(this).start();
}
}
3.于是,后台服务框架正常搭建起来了。子线程一直在获取任务,只要有任务的时候,取走任务,然后就执行任务。
run方法:
View Code
/*********
* 启动线程
*/
@Override
public void run() {
while (isrun) {
Task lastTask = null;
if (allTasks.size() > 0) {
synchronized (allTasks) {
// 获取任务
lastTask = allTasks.get(0);
// 执行任务
doTask(lastTask);
}
}
// 如果没有任务,则等待2000ms,继续获取任务
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
4.插叙一下Handler。
在每个Acitivity和Service主线程下,有一个Handler对象负责线程通信,消息传递,更新UI。(我是这么理解的)。通常采用异步实现网络通信,通过Handler来做数据媒介,然后把数据显示在界面上来。
主要涉及Message对象和handMessage(Message msg)方法。有时候还常用Handler对象的postXXX(Runnable run)方法。此方法有几个重载方法。就是加入一个Runnable(api:Represents a command that can be executed,表示可执行的命令)到Handler对象的附属子线程队列里。
5.理一下doTask(Task task)方法。
5.1先瞧瞧系统要执行的任务Task
View Code
package com.mpros.bean;
import java.util.Map;
/**
* 任务类 获取不同信息
*
* @author Scherrer
*
*/
public class Task {
// 任务编号
public static final int TASK_GET_PRODUCTTYPE = 0;// 获取产品类别
public static final int GET_TYPE_LOGO = 1; // 获取父类logo
public static final int TASK_GET_CHILDTYPE_LOGO = 2;// 获取二级类别logo
public static final int TASK_GET_PRODUCT_IMAGE = 3;// 获取产品
// 日志
public static final String Logger = "logger";
private int taskId;// 任务编号
@SuppressWarnings("rawtypes")
private Map taskParam;// 任务参数
@SuppressWarnings("rawtypes")
public Task(int taskId, Map taskParam) {
this.taskId = taskId;
this.taskParam = taskParam;
}
public int getTaskId() {
return taskId;
}
public void setTaskId(int taskId) {
this.taskId = taskId;
}
@SuppressWarnings("rawtypes")
public Map getTaskParam() {
return taskParam;
}
@SuppressWarnings("rawtypes")
public void setTaskParam(Map taskParam) {
this.taskParam = taskParam;
}
}
这里我声明成了原生类型了,但在Java里,在使用HashMap或者Map,常常会涉及泛型,如:Map<?,?> map ;
5.2 首先创建一个消息对象
Message msg = new Message();
5.3 赋予消息的标识,这里把任务编号赋予它。
msg.what = task.getTaskId();
5.4 通过switch语句,根据任务ID分别执行任务。具体代码上文已贴了。
6.在点击获取产品分类时,会转至相应分类的Activity。在初始化方法里,老规矩先检查网络,然后新建任务,该任务表示获取产品分类。
View Code
@Override
public void init() {
// 网络正常,新建获取产品类别的任务
if (NetUtil.checkNet(this)) {
Task getTypeTask = new Task(Task.TASK_GET_PRODUCTTYPE, null);
MainService.newTask(getTypeTask);
// 将此activity入栈
MainService.allActivities.add(this);
} else {
MainService.alerNetErr(this);
}
}
7.MainService会马上收到任务,然后调用doTask方法。根据编号,执行获取产品分类任务。
View Code
Message msg = new Message();
System.out.println("任务编号: " + task.getTaskId());
msg.what = task.getTaskId();
try {
switch (task.getTaskId()) {
case Task.TASK_GET_PRODUCTTYPE:// 获取产品类型
8.封装通过Http获取请求响应(HttpResponse)以及通过一个图片的URL,然后返回一张位图(BitmapDrawable)的工具类HttpUtil.
View Code
package com.mpros.util;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import android.graphics.drawable.BitmapDrawable;
public class HttpUtil {
public static HttpResponse getHttpResponse(String url)
throws ClientProtocolException, IOException {
// post请求
HttpPost post = new HttpPost(url);
// 请求客户
DefaultHttpClient client = new DefaultHttpClient();
return client.execute(post);
}
/***
* 获取logo
*
* @param url
* @return
*/
public static BitmapDrawable getImageFromUrl(String action) {
BitmapDrawable icon = null;
try {
URL url = new URL(action);
HttpURLConnection hc = (HttpURLConnection) url.openConnection();
icon = new BitmapDrawable(hc.getInputStream());
hc.disconnect();
} catch (Exception e) {
}
return icon;
}
}
9.解析json数据的业务。
通过HttpUtil获取一个HttpResponse.
HttpResponse response = HttpUtil.getHttpResponse(action);//在浏览器里输入此action,浏览器里可显示一串json数据。
测试响应码
// 响应code
int rescode = response.getStatusLine().getStatusCode();如果rescode 为200,表示获取ok.
然后通过response.getEntity().getContent();方法返回获取的所有数据,在转化为StringBuffer变长字串。再根据字段来解析。
View Code
package com.mpros.service.json;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpResponse;
import org.json.JSONArray;
import org.json.JSONObject;
import android.util.Log;
import com.mpros.bean.Task;
import com.mpros.bean.product.Product;
import com.mpros.bean.product.ProductBrand;
import com.mpros.bean.product.ProductStyle;
import com.mpros.bean.product.ProductType;
import com.mpros.bean.product.Sex;
import com.mpros.util.HttpUtil;
/***
* 产品模块 解析json数据
*
* @author Scherrer
*
*/
public class ProductTypeService {
/**
* 获取产品类型
*
* @param action
* 访问URl
* @return 类型列表
*/
public static List<ProductType> getTypesFromJson(String action) {
List<ProductType> types = null;
try {
HttpResponse response = HttpUtil.getHttpResponse(action);
// 响应code
int rescode = response.getStatusLine().getStatusCode();
if (rescode == 200) {// 获取ok
String line = null;
StringBuilder builder = new StringBuilder();// 可变String
BufferedReader lineReader = new BufferedReader(
new InputStreamReader(response.getEntity().getContent()));
while ((line = lineReader.readLine()) != null) {
builder.append(line);
}
Log.i(Task.Logger, builder.toString());
JSONObject obj = new JSONObject(builder.toString());
obj = obj.getJSONObject("types");
// 以关键字types获取一个json数组
JSONArray array = obj.getJSONArray("results");
// /System.out.println("json array " + array.toString());
types = new ArrayList<ProductType>();
JSONObject temp = null;
for (int i = 0; i < array.length(); ++i) {
temp = (JSONObject) array.opt(i);
System.out.println("temp i" + temp.toString());
ProductType type = resolveProductType(temp);
// 是否有子类
if (temp.getString("childTypes") != null) {
JSONArray array2 = temp.getJSONArray("childTypes");
System.out.println("获取的子类数组 -- " + array2.toString());
List<ProductType> childtypes = new ArrayList<ProductType>();
for (int e = 0; e < array2.length(); ++e) {
JSONObject temp2 = (JSONObject) array2.opt(e);
System.out.println("二级类别 一条记录 ---- " +
temp2.toString());
ProductType childtype = resolveProduct(temp2);
if (temp.getString("childTypes") != null) {
JSONArray array3 = temp
.getJSONArray("childTypes");
List<ProductType> child2types = new ArrayList<ProductType>();
for (int k = 0; k < array3.length(); ++k) {
JSONObject temp3 = (JSONObject) array3
.opt(k);
System.out.println("temp3 k" +
temp3.toString());
child2types.add(resolveProduct(temp3));
}
childtype.setChildtypes(child2types);
}
if(childtype != null) {
childtypes.add(childtype);
}
}
type.setChildtypes(childtypes);
}
if (type != null) {
types.add(type);
}
}
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
Log.i(Task.Logger, "types --- 大小" + types.size());
for (ProductType type : types) {
if (type.getChildtypes() != null) {
Log.i(Task.Logger, "type child types --- 大小"
+ type.getChildtypes().size());
}
}
return types != null ? types : null;
}
public static ProductType resolveProduct(JSONObject temp) {
ProductType type = new ProductType();
try {
// 获取type的简单属性
System.out.println("产品类型属性:");
type.setTypeid(Integer.parseInt(temp.getString("typeId")));
System.out.println("typeid: "
+ Integer.parseInt(temp.getString("typeId")));
type.setName(temp.getString("name"));
System.out.println("type name -- " + temp.getString("name"));
type.setRemark(temp.getString("remark"));
System.out.println("type remark -- " + temp.getString("remark"));
type.setTypelogo(temp.getString("typelogo"));
JSONArray products = temp.getJSONArray("products");
if (products != null) {
System.out.println("类别产品 -- " + products.toString());
// 获取type的所有产品--产品列表
for (int j = 0; j < products.length(); ++j) {
JSONObject p = (JSONObject) products.opt(j);
Product product = new Product();
System.out.println("一个产品记录 -- " + p.toString());
// 产品简单属性
System.out.println("产品id-- " + p.getInt("id"));
product.setId(p.getInt("id"));
product.setCode(p.getString("code"));
System.out.println("产品货号: " + p.getString("code"));
product.setBaseprice(Float.parseFloat(p
.getString("baseprice")));
if (p.getString("buyexplain") != null) {
product.setBuyexplain(p.getString("buyexplain"));
}
product.setClickcount(p.getInt("clickcount"));
product.setCommend(p.getBoolean("commend"));
product.setCreatetime(p.getString("createdate"));
product.setDescription(p.getString("description"));
product.setMarketprice(Float.parseFloat(p
.getString("marketprice")));
if(p.getString("model") != null) {
product.setModel(p.getString("model"));
}
product.setName(p.getString("name"));
product.setSellcount(p.getInt("sellcount"));
product.setSellprice(Float.parseFloat(p
.getString("sellprice")));
product.setSexrequest(Sex.valueOf(p.getString("sexrequest")));
System.out.println("产品性别要求 -- " + product.getSexrequest());
/*if (p.getString("weight") != null) {
product.setWeight(Integer.parseInt(p.getString("weight")));
}*/
System.out.println(" 产品品牌 测试 ---------");
// 品牌
/*if (p.getString("brand") != null) {
JSONObject b = p.getJSONObject("brand");
System.out.println("产品品牌记录 -- " + b.toString());
ProductBrand brand = new ProductBrand();
brand.setId(b.getString("id"));
brand.setLogoPath(b.getString("logoPath"));
brand.setName(b.getString("name"));
// 产品添加品牌
product.setBrand(brand);
}*/
System.out.println(" 产品样式 测试 ---------");
if (p.getJSONArray("styles") != null) {
// 产品样式
JSONArray ss = p.getJSONArray("styles");
System.out.println("产品样式记录 -- " + ss.toString());
for (int k = 0; k < ss.length(); ++k) {
JSONObject s = (JSONObject) ss.opt(k);
System.out.println("一条样式记录 -- " + s.toString());
ProductStyle style = new ProductStyle();
style.setId(s.getInt("id"));
style.setName(s.getString("name"));
style.setImagename(s.getString("imagename"));
// 添加样式
product.addStyle(style);
}
}
// 添加产品
type.addProduct(product);
}
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
return type;
}
/***
* 解析产品类型
* @return
*/
public static ProductType resolveProductType(JSONObject temp) {
ProductType type = new ProductType();
try {
// 获取type的简单属性
System.out.println("产品类型属性:");
type.setTypeid(Integer.parseInt(temp.getString("typeId")));
System.out.println("typeid: "
+ Integer.parseInt(temp.getString("typeId")));
type.setName(temp.getString("name"));
System.out.println("type name -- " + temp.getString("name"));
type.setRemark(temp.getString("remark"));
System.out.println("type remark -- " + temp.getString("remark"));
type.setTypelogo(temp.getString("typelogo"));
System.out.println("type logo -- " + temp.getString("typelogo"));
}catch (Exception e) {
e.printStackTrace();
return null;
}
return type;
}
}
10.在执行获取产品类型时,正常的话会返回解析好的产品类型对象列表list。然后通过handler对象传递该list,根据任务id去更新UI。
View Code
msg.obj = types;
。。。
handler.sendMessage(msg);
allTasks.remove(task);// 执行完任务,则移出该任务
// 当前服务的子线程Handler,负责处理更新UI操作
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.i(Task.Logger, "UI 更新编号:" + msg.what);
switch (msg.what) {
case Task.TASK_GET_PRODUCTTYPE:
IMActivity ia = (ClassifyActivity) getActivityByName("ClassifyActivity");
ia.refresh(ClassifyActivity.GET_TYPE_SUCCESS, msg.obj);
11.在ClassifyActivity里实现refresh方法。
View Code
@SuppressWarnings("unchecked")
@Override
public void refresh(Object... param) {
switch (((Integer) param[0]).intValue()) {
case GET_TYPE_SUCCESS:
viewBar.setVisibility(View.GONE);
List<ProductType> producttypes = (List<ProductType>) param[1];
this.types = producttypes;
if (this.types != null) {
System.out.println("获取的类别记录 -- " + this.types.size());
Log.i(Task.Logger, "types.size() -- " + this.types.size());
// 适配器
MyListViewAdapter adapter = new MyListViewAdapter(this, this.types);
typesListView.setAdapter(adapter);
} else {
makeToast("加载数据失败,请再试..");
}
break;
12.执行一个任务的逻辑顺序就是这样了,
通过UI新建任务 ---> 后台服务获取任务并执行任务 ---> 通过相应的方法获取的数据 ---> Hanlder传递数据 ---> 返回原来的UI ---> UI是否更新.
有时间会再补充我觉得比较有用的UI设计。