【问题标题】:Perform AsyncTask on Android / Posting JSON在 Android 上执行 AsyncTask / 发布 JSON
【发布时间】:2013-11-03 21:01:30
【问题描述】:

我正在开发一个 android 应用程序,但在注册用户时遇到了一些麻烦。我想将一个 JSON 对象发布到我的服务器并收到一个返回。我可以使用正确的信息成功地创建一个 JSON 对象,但是当我发布它时,我得到一个 NetworkOnMainThreadException 或者我的 HttpClient 类在它应该返回一个 JSONObject 时返回 null,我非常有信心我的 Web 服务器可以正常工作。我知道您无法在主线程上连接到网络,并创建了一个使用 AsnycTask 的 HttpClient 类(尽管可能不正确)。我已经为此工作了很长一段时间,并希望得到任何正确方向的指导。

//Main activity
@Override
public void onClick(View arg0) {
    if(!(isEmpty(name) || isEmpty(username) || isEmpty(password) || isEmpty(email))) {
        user = new JSONObject();
        try {
            user.put("username", username.getText().toString());
            user.put("name", name.getText().toString());
            user.put("email", email.getText().toString());
            user.put("password", password.getText().toString());
        } catch (JSONException e) {
            e.printStackTrace();
        }

        jRegister = new JSONObject();

        try {
            jRegister.put("apiToken", Utilities.apiToken);
            jRegister.put("user", user);

            Log.i("MainActivity", jRegister.toString(2));

        } catch (JSONException e) {
            e.printStackTrace();
        }

       //
        HttpClient client = new HttpClient(url, jRegister);
        result = client.getJSONFromUrl();


        try {
            if(result  != null)
                tv.setText(result.toString(2));
            else
                 tv.setText("null");
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }else {
        tv.setText("");
    }
}

HttpClient 类

public class HttpClient extends AsyncTask<Void, Void, JSONObject>{
    private final String TAG = "HttpClient";
    private String URL;
    private JSONObject jsonObjSend;
    private JSONObject result = null;

    public HttpClient(String URL, JSONObject jsonObjSend) {
        this.URL = URL;
        this.jsonObjSend = jsonObjSend;
    }

    public JSONObject getJSONFromUrl() {
        this.execute();
        return result;
    }

    @Override
    protected JSONObject doInBackground(Void... params) {

            try {
                    DefaultHttpClient httpclient = new DefaultHttpClient();
                    HttpPost httpPostRequest = new HttpPost(URL);

                    StringEntity se;
                    se = new StringEntity(jsonObjSend.toString());

                    // Set HTTP parameters
                    httpPostRequest.setEntity(se);
                    httpPostRequest.setHeader("Accept", "application/json");
                    httpPostRequest.setHeader("Content-type", "application/json");

                    long t = System.currentTimeMillis();
                    HttpResponse response = (HttpResponse) httpclient.execute(httpPostRequest);
                    Log.i(TAG, "HTTPResponse received in [" + (System.currentTimeMillis()-t) + "ms]");

                    HttpEntity entity = response.getEntity();

                    if (entity != null) {
                            // Read the content stream
                            InputStream instream = entity.getContent();

                            // convert content stream to a String
                            String resultString= convertStreamToString(instream);
                            instream.close();
                            resultString = resultString.substring(1,resultString.length()-1); // remove wrapping "[" and "]"

                            JSONObject jsonObjRecv = new JSONObject(resultString);

                            // Raw DEBUG output of our received JSON object:
                            Log.i(TAG,"<JSONObject>\n"+jsonObjRecv.toString()+"\n</JSONObject>");

                            return jsonObjRecv;
                    } 

            }
            catch (Exception e) {
                    e.printStackTrace();
            }
            return null;
    }

    protected void onPostExecute(JSONObject jObject) {
        result = jObject;
    }
    private static String convertStreamToString(InputStream is) {

            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            StringBuilder sb = new StringBuilder();

            String line = null;
            try {
                    while ((line = reader.readLine()) != null) {
                            sb.append(line + "\n");
                    }
            } catch (IOException e) {
                    e.printStackTrace();
            } finally {
                    try {
                            is.close();
                    } catch (IOException e) {
                            e.printStackTrace();
                    }
            }
            return sb.toString();
    }

}

【问题讨论】:

    标签: java android json http android-asynctask


    【解决方案1】:

    我了解到您无法在主线程上连接到网络 并创建了一个使用 AsnycTask 的 HttpClient 类(尽管 可能不正确)。

    你是对的,你没有以正确的方式实现它。

    在您的 onClick 事件中(仍在主线程上)您执行了导致错误的网络活动:

    HttpClient client = new HttpClient(url, jRegister);
    result = client.getJSONFromUrl();
    

    您应该在 AsnycTask 内运行网络操作

    public class GetJsonTask extends AsyncTask<Void, Void, JSONObject >{
        private String URL;
        private JSONObject jsonObjSend;
    
        public GetJsonTask(String URL, JSONObject jsonObjSend) {
            this.URL = URL;
            this.jsonObjSend = jsonObjSend;
        }
    
        @Override
        protected JSONObject doInBackground(Void... params) {
        JSONObject jsonObjRecv;
               try {
                        DefaultHttpClient httpclient = new DefaultHttpClient();
                        HttpPost httpPostRequest = new HttpPost(URL);
    
                        StringEntity se;
                        se = new StringEntity(jsonObjSend.toString());
    
                        // Set HTTP parameters
                        httpPostRequest.setEntity(se);
                        httpPostRequest.setHeader("Accept", "application/json");
                        httpPostRequest.setHeader("Content-type", "application/json");
    
                        long t = System.currentTimeMillis();
                        HttpResponse response = (HttpResponse) httpclient.execute(httpPostRequest);
                        Log.i(TAG, "HTTPResponse received in [" + (System.currentTimeMillis()-t) + "ms]");
    
                        HttpEntity entity = response.getEntity();
    
                        if (entity != null) {
                                // Read the content stream
                                InputStream instream = entity.getContent();
    
                                // convert content stream to a String
                                String resultString= convertStreamToString(instream);
                                instream.close();
                                resultString = resultString.substring(1,resultString.length()-1); // remove wrapping "[" and "]"
    
                                jsonObjRecv = new JSONObject(resultString);
    
                                // Raw DEBUG output of our received JSON object:
                                Log.i(TAG,"<JSONObject>\n"+jsonObjRecv.toString()+"\n</JSONObject>");
    
    
                        } 
    
                }
                catch (Exception e) {
                        e.printStackTrace();
                }
                return jsonObjRecv;         
        }
    
        protected void onPostExecute(JSONObject result) {
            try {
                if(result  != null)
                    tv.setText(result.toString(2));
                else
                     tv.setText("null");
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }else {
            tv.setText("");
        }
        }
    
    }
    

    然后你像这样在 onclik 方法中调用你的异步:

    public void onClick(View arg0) {
    //.......
    GetJsonTask client = new GetJsonTask(url, jRegister);
    client.execute();
    }
    

    【讨论】:

      【解决方案2】:

      您的代码中的一个问题是您对AsyncTask 的期望并不完全正确。特别是这个功能:

      public JSONObject getJSONFromUrl() {
          this.execute();
          return result;
      }
      

      AsyncTask 在单独的线程中运行doInBackground() 函数中的代码。这意味着一旦您调用execute(),您就会有两条并行的执行线。您最终会得到所谓的种族条件。当您到达return result 行时,可能会发生几件事:

      • doInBackground() 尚未运行,因此 result 仍具有默认值。在这种情况下null
      • doInBackground() 可以在代码中间。在您的特定情况下,因为它不会修改 result,所以这不会对您产生太大影响。但当返回发生时,它可能在 任何 行(如果操作不是原子的,有时也可以在行的中间)。
      • doInBackground() 可能已经完成,但由于 onPostExecute() 在 UI 线程上运行,它必须等到您的 onClick 处理程序完成。当onPostExecute() 有机会运行onClick 时,已经尝试用getJSONFromUrl 返回的内容更新tv,很可能是null

      AsyncTask设置任务的方法是给它工作所需的信息,用execute启动它,既然你不知道完成需要多长时间,就让它处理任务的完成步骤。

      这意味着在调用execute 之后,您不会等待它的结果来更新视图(就像您的情况一样),而是依靠AsyncTaskonPostExecute 或相关方法来接管下一步。

      对于您的情况,这意味着您的 onPostExecute 应该类似于:

      protected void onPostExecute(JSONObject result) {
          try {
              if(result  != null)
                  tv.setText(result.toString(2));
              else
                  tv.setText("null");
          } catch (JSONException e) {
              e.printStackTrace();
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2013-12-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多