AsyncTask的简单使用以及注意事项

AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程.

AsyncTask定义了三种泛型类型 Params,Progress和Result。

  • Params 启动任务执行的输入参数,比如HTTP请求的URL。
  • Progress 后台任务执行的完成的百分比。
  • Result 后台执行任务最终返回的结果,比如byte[],String。
在AsyncTask中需要注意的几个方法:

  • onPreExecute()   当任务执行之前开始调用此方法,比如可以在这里将进度对话框显示出来。
  • doInBackground(Params…) 在后台执行,主要是完成耗时的操作。因为此方法在后台线程执行,所以不能再次更新UI。在执行过程中可以通过调用publicProgress(Progress…)来更新任务的进度。
  • onPostExecute(Result)  当doInBackground(Params…)方法执行完成之后执行该方法 此方法在主线程执行,在这里面可以使用在doInBackground返回的结果进行更新UI。
  • onProgressUpdate(Progress…)   更新进度条加载的进度, 此方法在主线程中执行,可直接进行UI更新。
除此之外,使用过程中还要注意几点:1.AsyncTak实例化以及execute的调用必须要在主线程中完成;2.不能手动调用上面提到的几个方法;3.task不能执行多次,只能执行一次,否则容易出现异常。

接下来开始一个简单的使用例子:

1.activity_main.xml布局文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.chen.asynctask.MainActivity">
    <TextView
        android:id="@+id/tv_show"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

2.MainActivity.java文件:

public class MainActivity extends AppCompatActivity {
    private static final String URL_CONTENT = "http://json.cn/wiki.html";
    private TextView tvShow;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvShow = (TextView)findViewById(R.id.tv_show);
        new MyAsyncTask(this,tvShow).execute(URL_CONTENT);
    }
}
 
   
 
  

3. MyAsyncTask.java文件:

public class MyAsyncTask extends AsyncTask<String, Integer, byte[]> {
    private static final String TAG = "MyAsyncTask";
    private Context context;
    private TextView tvShow;
    private ProgressDialog progressDialog = null;

    public MyAsyncTask(Context context, TextView tvShow) {
        this.context = context;
        this.tvShow = tvShow;

        progressDialog = new ProgressDialog(context);
        progressDialog.setIcon(R.mipmap.ic_launcher);
        progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        progressDialog.setTitle("提示");
        progressDialog.setMessage("数据正在加载中...");
    }

    @Override
    protected byte[] doInBackground(String... params) {
        BufferedInputStream bis = null;
        ByteArrayOutputStream bao = new ByteArrayOutputStream();
        try {
            URL url = new URL(params[0]);
            HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
            // 默认情况下,HttpURLConnection使用gzip方式获取,要取得长度则要求http请求不要gzip压缩;
            httpConn.setRequestProperty("Accept-Encoding", "identity"); // 添加此行目的是避免httpConn.getContentLength()返回-1
//            httpConn.setDoOutput(true);
            httpConn.setDoInput(true);// 默认为true,使用getInputStream需设为true
            httpConn.setRequestMethod("GET");
            httpConn.connect();
            Log.i(TAG, "doInBackground: -------获取到的请求码为--" + httpConn.getResponseCode());
            if (httpConn.getResponseCode() == HttpURLConnection.HTTP_OK) {
                // 获取文件的长度大小
                int len = httpConn.getContentLength();
                // 统计已经读取的大小
                int count = 0;
                bis = new BufferedInputStream(httpConn.getInputStream());
                Log.i(TAG, "doInBackground: ---" + new String(bis.toString()));
                byte[] buf = new byte[1024 * 8];
                int c = 0;
                while ((c = bis.read(buf)) != -1) {
                    bao.write(buf, 0, c);
                    bao.flush();
                    count += c;
                    if (len > 0) // 更新下载进度
                    {
                        int aa = (int) ((count / (double) len) * 100);
                        publishProgress(aa);
                    }
                    Thread.sleep(500);
                }
                return bao.toByteArray();
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bis != null) {
                    bis.close();
                }
                if (bao != null) {
                    bao.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        return new byte[0];
    }

    @Override
    protected void onCancelled() {
        Log.i(TAG, "onCancelled: -------执行onCancelled()方法---");
        super.onCancelled();
    }

    @Override
    protected void onCancelled(byte[] bytes) {
        Log.i(TAG, "onCancelled: -------执行onCancelled(byte[] bytes)方法---");
        super.onCancelled(bytes);
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
        Log.i(TAG, "onProgressUpdate: ----" + values[0]);
        // 更新进度条的数值
        progressDialog.setProgress(values[0]);
    }

    @Override
    protected void onPostExecute(byte[] bytes) {
        if (bytes != null) {
            tvShow.setText(new String(bytes));
        } else {
            tvShow.setText("请求不到数据");
        }
        progressDialog.dismiss();
        super.onPostExecute(bytes);
    }

    @Override
    protected void onPreExecute() {
        progressDialog.show();
        super.onPreExecute();
    }
}

在这里需要提醒大家注意,在测试过程中你可能会发现获取文件大小httpConn.getContentLength()的时候,返回结果是-1,然后内容下载确是正常的,也就是可以把内容下载下来,但是调用这个方法获取内容的大小的时候确是返回了-1,为什么?结果发现,原来2.2版本以上HttpURLConnection跟服务交互采用了"gzip"压缩,也就是默认情况下,HttpURLConnection使用gzip方式获取,要取得长度则要求http请求不要gzip压缩。参考api:By default, this implementation of HttpURLConnection requests that servers use gzip compression. Since getContentLength() returns the number of bytes transmitted, you cannot use that method to predict how many bytes can be read from getInputStream(). Instead, read that stream until it is exhausted: whenread() returns -1. 
取消办法在http request的head中设置如下参数即可:

    httpConn.setRequestProperty("Accept-Encoding", "identity");

另外,还要注意的是,你所测试的URL尽可能使用有效的http,不要用https重定向的,不然会出现你请求不到数据的现象,比如博主刚开始的时候使用的测试URL是“http://www.baidu.com/”,结果发现返回的响应码302,意思就是服务端重定向了,于是我灵机一动,把http改为https,发现结果还是一样,这不科学啊,于是我开始怀疑人生了!后来我换了一个测试RUL,就是现在的这个“http://json.cn/wiki.html",发现可以了,神了!!!所以,建议大家尽量避免使用重定向的URL进行测试。


最后,附上效果图:

            


 
   
 
  









发布了8 篇原创文章 · 获赞 20 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/u012850536/article/details/75142425