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設計。

 

 

 

 

 

 

 

 

  

 

 

 

    

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM