Android客户端获取服务器的json数据(二)

 这一周课很多,所以没有及时的接上。

现在的我不打算再拼命的做码农了,而是尽量的做总结。把以前写过的一些代码回忆一下,把以前有过的思路再重新寻觅一回。似乎,我好多废话。

在做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设计。

 

 

 

 

 

 

 

 

  

 

 

 

    

 

posted @ 2013-03-07 20:54  shuimuouyang  阅读(12429)  评论(3编辑  收藏  举报