为 AsyncTask 实现一个常规的 JSON 解析器函数

Posted

技术标签:

【中文标题】为 AsyncTask 实现一个常规的 JSON 解析器函数【英文标题】:Implementing a regular JSON parser function to AsyncTask 【发布时间】:2019-01-15 08:35:30 【问题描述】:

我正在开发一个应用程序,它有很多远程 JSON 调用来获取数据并在应用程序中实现。

目前,我正在使用此函数从 URL 获取 JSON 数据并对其进行解析。

但不幸的是,它会冻结应用程序,直到下载 JSON 文件。

google了一下,发现AsyncTask可以解决这个问题。

我刚开始开发 android 应用程序。我试过但失败了。

你们能帮我实现这个功能到 AsyncTask 吗?

public class JSONParser 

String charset = "UTF-8";
HttpURLConnection conn;
DataOutputStream wr;
StringBuilder result;
URL urlObj;
JSONObject jObj = null;
JSONArray jAry = null;
StringBuilder sbParams;
String paramsString;

public JSONObject makeHttpRequest(String url, String method, HashMap<String, String> params) 

    sbParams = new StringBuilder();
    int i = 0;
    for (String key : params.keySet()) 
        try 
            if (i != 0) 
                sbParams.append("&");
            
            sbParams.append(key).append("=")
                    .append(URLEncoder.encode(params.get(key), charset));

         catch (UnsupportedEncodingException e) 
            e.printStackTrace();
        
        i++;
    

    if (method.equals("POST")) 
        try 
            urlObj = new URL(url);
            conn = (HttpURLConnection) urlObj.openConnection();
            conn.setDoOutput(true);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Accept-Charset", charset);
            conn.setReadTimeout(10000);
            conn.setConnectTimeout(15000);
            conn.connect();
            paramsString = sbParams.toString();
            wr = new DataOutputStream(conn.getOutputStream());
            wr.writeBytes(paramsString);
            wr.flush();
            wr.close();

         catch (IOException e) 
            e.printStackTrace();
        
     else if (method.equals("GET")) 
        if (sbParams.length() != 0) 
            url += "?" + sbParams.toString();
        

        Log.d("URL",url);
        try 
            urlObj = new URL(url);
            conn = (HttpURLConnection) urlObj.openConnection();
            conn.setDoOutput(false);
            conn.setRequestMethod("GET");
            conn.setRequestProperty("Accept-Charset", charset);
            conn.setConnectTimeout(15000);
            conn.connect();
         catch (IOException e) 
            e.printStackTrace();
        
    
    try 
        InputStream in = new BufferedInputStream(conn.getInputStream());
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        result = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) 
            result.append(line);
        

        Log.d("JSON Parser", "result: " + result.toString());

     catch (IOException e) 
        e.printStackTrace();
    

    conn.disconnect();

    try 
        jObj = new JSONObject(result.toString());
     catch (JSONException e) 
        Log.e("JSON Parser", "Error parsing data " + e.toString());
    

    return jObj;

这是我进行 json 调用的方式:

JSONParser jsonParser = new JSONParser();
JSONObject json = jsonParser.makeHttpRequest("https://url", "GET", parametters);

【问题讨论】:

所以如果你调用 apis ,它会给你 json 响应,那么我建议你使用 okhttpretrofit 网络库。 这不在问题范围内。但谦虚地建议您使用网络客户端可能是 RetroFitGSON 。这样你就不用解析大量的数据和更少的代码了。 【参考方案1】:

如果您想使用 AsyncTask 来做到这一点,这是一个好的开始:

public class JsonParser extends AsyncTask<Void, Void, JSONObject> 

    public interface ParserListener 
        void onSuccess(JSONObject result);
        void onFailure();
    

    private ParserListener listener;    
    private HashMap<String, String> params;
    private String method;
    private String url;
    String charset = "UTF-8";
    HttpURLConnection conn;
    DataOutputStream wr;
    StringBuilder result;
    URL urlObj;
    JSONObject jObj = null;
    JSONArray jAry = null;
    StringBuilder sbParams;
    String paramsString;

    public JsonParser(String url, String method, HashMap<String, String> params) 
        this.url = url;
        this.method = method;
        this.params = params;
    

    public void setListener(ParserListener listener) 
        this.listener = listener;
    

    @Override
    protected JSONObject doInBackground(Void... voids) 
        sbParams = new StringBuilder();
        int i = 0;
        for (String key : params.keySet()) 
            try 
                if (i != 0) 
                    sbParams.append("&");
                
                sbParams.append(key).append("=")
                        .append(URLEncoder.encode(params.get(key), charset));

             catch (UnsupportedEncodingException e) 
                e.printStackTrace();
            
            i++;
        

        if (method.equals("POST")) 
            try 
                urlObj = new URL(url);
                conn = (HttpURLConnection) urlObj.openConnection();
                conn.setDoOutput(true);
                conn.setRequestMethod("POST");
                conn.setRequestProperty("Accept-Charset", charset);
                conn.setReadTimeout(10000);
                conn.setConnectTimeout(15000);
                conn.connect();
                paramsString = sbParams.toString();
                wr = new DataOutputStream(conn.getOutputStream());
                wr.writeBytes(paramsString);
                wr.flush();
                wr.close();

             catch (IOException e) 
                e.printStackTrace();
            
         else if (method.equals("GET")) 
            if (sbParams.length() != 0) 
                url += "?" + sbParams.toString();
            

            Log.d("URL",url);
            try 
                urlObj = new URL(url);
                conn = (HttpURLConnection) urlObj.openConnection();
                conn.setDoOutput(false);
                conn.setRequestMethod("GET");
                conn.setRequestProperty("Accept-Charset", charset);
                conn.setConnectTimeout(15000);
                conn.connect();
             catch (IOException e) 
                e.printStackTrace();
            
        
        try 
            InputStream in = new BufferedInputStream(conn.getInputStream());
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            result = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) 
                result.append(line);
            

            Log.d("JSON Parser", "result: " + result.toString());

         catch (IOException e) 
            e.printStackTrace();
        

        conn.disconnect();

        try 
            jObj = new JSONObject(result.toString());
         catch (JSONException e) 
            Log.e("JSON Parser", "Error parsing data " + e.toString());
        

        return jObj;
    

    @Override
    protected void onPostExecute(JSONObject jsonObject) 
        /* executed on main thread */
        if (listener != null) 
            if (jsonObject != null) 
                listener.onSuccess(jsonObject);
             else 
                listener.onFailure();
            
        
    

并使用它:

JsonParser parser = new JsonParser("https://url", "GET", parameters);
parser.setListener(new JsonParser.ParserListener() 
      @Override
       public void onSuccess(JSONObject result) 
            /* delivered result */
        

        @Override
        public void onFailure() 
                /* delivered failure */
        
        );
parser.execute();

代码可以改进,正如 cmets 中所指出的,有更好的方法可以做到这一点。 AsyncTask 在学习阶段仍然很有趣。

【讨论】:

嗨,非常感谢,这就是我要找的。但是要获得返回值呢? JSONParser jsonParser = new JSONParser("url", "GET", 参数);那么如何获取JSONObject呢? 响应是通过 JsonParser.ParserListener 的 onSuccess 回调给出的。有意义吗? 太棒了,正是我想要的。非常感谢先生。你刚刚拯救了我的一天。希望它也能帮助其他人。

以上是关于为 AsyncTask 实现一个常规的 JSON 解析器函数的主要内容,如果未能解决你的问题,请参考以下文章

使用 AsyncTask 从 JSON 中获取数据

AsyncTask #3 解析 JSON 对象时出错。字符串无法转换为 JSONObject

解析JSON对象的AsyncTask#3错误。 String无法转换为JSONObject

实现 Widget Android Studio 的问题 - AsyncTask

来自使用 AsyncTask 解析的 JSON 对象的 setText [重复]

从 AsyncTask 携带和重用信息(json 字符串)?