php - android.os.NetworkOnMainThreadException : refactoring code to use AsyncTask?

标签 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();
    }

}

最佳答案

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

一个继承了 AsyncTask 的私有(private)子类,它实现了以下方法:

  1. onPreExecute – 在任务执行之前在 UI 线程上调用,用于设置内容(例如显示进度条)

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

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

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

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

您当前的代码位于将在 UI 线程上创建的方法中(这将抛出 NetworkOnMainThreadException,因此您需要将代码移至运行在 上的线程code>worker 线程。

将代码移至 AsyncTask

从表面上看,只有 getData() 方法需要重新排列。与检索数据有关的所有事情都可以放在任务的 doInBackground 位中,所有 UI 组件的更新(例如您的 toast)都需要移至 onPostExecute

它应该看起来像下面这样(注意一些事情可能需要调整。这是在编译器之外编写的):

private class MyTask extends AsyncTask<Void, Void, Value> 
{
    boolean success = false;

    @Override
    protected String doInBackground(String toSubmit) 
    {
        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(toSubmit, "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();
                    success = true;
                }
            }
            is.close();
        }
        else {
            // use below to get error stream
            // inputStream = httpUrlConnection.getErrorStream();
        }
        return respData.toString();
    }

    @Override
    protected void onPostExecute(String result) 
    {
        Toast toast = Toast.makeText(getApplicationContext(), "Success", Toast.LENGTH_SHORT);
        processValue(result);
    }
}

private void processValue(String theResult) 
{
   //handle value
}

String toSubmit = "";

@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
            toSubmit = name.getText().toString() + " " + email.getText().toString() + " " + idea.getText().toString();

            try{
                new MyTask().execute();
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    });
}

关于php - android.os.NetworkOnMainThreadException : refactoring code to use AsyncTask?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33600303/

相关文章:

PHP url 函数和子域

php - CakePHP:setFlash() 中的 HTML

php - config.xml 覆盖导致购物车不可见?

c# - Android 单声道 : ListView Delete Items NotifyDataSet Changed

java - 在 doInBackground 中创建另一个 AsyncTask

php - FPDF 错误 : Missing or incorrect image file

android - ' :ProjectName' could not be found

android - 在 android 中向 Commonsware RichEditText 添加自定义控件

android - 如何停止 AsyncTask 类中的 Activity

java - 从 Android 中单独的 AsyncTask 类连接 WiFi 管理器