android.os.NetworkOnMainThreadException:重构代码使用AsyncTask?

时间:2015-11-08 23:30:33

标签: php android android-asynctask

我收到错误:android.os.NetworkOnMainThreadException,我知道修复是在AsnycTask中运行我的代码。

我不知道如何重构以下代码以使用AsnycTask?我可以在一个activity中完成所有这些吗?

public class MainActivity extends AppCompatActivity {

    @Bind(R.id.tvTitle)
    TextView title;
    @Bind(R.id.etName)
    EditText name;
    @Bind(R.id.etEmail)
    EditText email;
    @Bind(R.id.etIdea)
    EditText idea;
    @Bind(R.id.btnSubmit)
    Button submit;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        submit.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                //get input from editText boxes to send to php file on server
                String  toSubmit = name.getText().toString() + " " + email.getText().toString() + " " + idea.getText().toString();

                try{
                    getData(toSubmit);
                }catch(IOException e){
                    e.printStackTrace();
                }
            }
        });
    }

    public static InputStream toInputStream(String input, String encoding) throws IOException {
        byte[] bytes = encoding != null ? input.getBytes(encoding) : input.getBytes();
        return new ByteArrayInputStream(bytes);
    }

    private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;

    public static long copyLarge(InputStream input, OutputStream output)
            throws IOException {
        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
        long count = 0;
        int n = 0;
        while (-1 != (n = input.read(buffer))) {
            output.write(buffer, 0, n);
            count += n;
        }
        return count;
    }

    public static int copy(InputStream input, OutputStream output) throws IOException {
        long count = copyLarge(input, output);
        if (count > Integer.MAX_VALUE) {
            return -1;
        }
        return (int) count;
    }

    String getData(String postData) throws IOException {
        StringBuilder respData = new StringBuilder();
        URL url = new URL("MY_URL");
        URLConnection conn = url.openConnection();
        HttpURLConnection httpUrlConnection = (HttpURLConnection) conn;

        httpUrlConnection.setUseCaches(false);
        httpUrlConnection.setRequestProperty("User-Agent", "YourApp"); 
        httpUrlConnection.setConnectTimeout(30000);
        httpUrlConnection.setReadTimeout(30000);

        httpUrlConnection.setRequestMethod("POST");
        httpUrlConnection.setDoOutput(true);

        OutputStream os = httpUrlConnection.getOutputStream();
        InputStream postStream = toInputStream(postData, "UTF-8");
        try {
            copy(postStream, os);
        } finally {
            postStream.close();
            os.flush();
            os.close();
        }

        httpUrlConnection.connect();

        int responseCode = httpUrlConnection.getResponseCode();

        if (200 == responseCode) {
            InputStream is = httpUrlConnection.getInputStream();
            InputStreamReader isr = null;
            try {
                isr = new InputStreamReader(is);
                char[] buffer = new char[1024];
                int len;
                while ((len = isr.read(buffer)) != -1) {
                    respData.append(buffer, 0, len);
                }
            } finally {
                if (isr != null)
                    isr.close();
                Toast toast = Toast.makeText(getApplicationContext(), "Success", Toast.LENGTH_SHORT);
            }
            is.close();
        }
        else {
            // use below to get error stream
            // inputStream = httpUrlConnection.getErrorStream();
        }
        return respData.toString();
    }

}

1 个答案:

答案 0 :(得分:1)

请参阅http://developer.android.com/reference/android/os/AsyncTask.html以获取android记录的用法,但它基本上归结为以下实现:

扩展AsyncTask的私有子类,实现以下方法:

  1. onPreExecute - 在执行任务之前在UI线程上调用并用于设置填充(例如显示进度条)

  2. doInBackground - 您想要执行的实际操作在onPreExecute之后立即触发

  3. onPostExecute - 在doInBackground完成后在UI线程上调用。这会将doInBackground的结果作为参数接收,然后可以在UI线程上使用。

  4. AsyncTask用于UI线程上不允许的操作,例如:

    • 打开套接字连接
    • HTTP请求(例如HTTPClient和HTTPURLConnection)
    • 尝试连接远程MySQL数据库
    • 下载文件

    您当前的代码位于将在UI线程上创建的方法(将抛出NetworkOnMainThreadException,因此您需要将代码移动到{{1}上运行的线程} thread。

    将代码移到AsyncTask

    从外观上看,只需要重新安排worker方法。有关检索数据的所有内容都可以放在任务的getData()位,并且所有更新的UI组件(例如doInBackground)都需要移至toast

    它应该类似于以下内容(注意可能需要调整一些内容。这是从编译器中删除的):

    onPostExecute