对Thread以及AsyncTask的理解整理

今天在写项目的时候,遇到了写引导页的需求,这个需求的实现想必是很简单的(还是老套路,大神请自觉略过);

思路:
1. 创建一个guideActivity文件,需要在Manifest文件中将MainActivity进行替换并注册MainActivity,在xml文件中声明一个ImageView;
2. 明确该图片是从网络上加载的还是本地加载;
3. 明确引导页的作用(添加广告,延时跳转为我们app加载网络信息争取时间等等);

4. 因为提及延时这个词,所以第一时间想到线程;


如何去写引导页并不是重点,重点是当再次使用线程的时候,感觉知识点还是有一些模糊,所以打算重新对线程进行理解以下是我的整理:

1.明确线程的作用:提高程序的效率,将我们的阻塞操作(网络请求,数据库查询等)放到子线程中去执行,可以有效的防止UI线程(主线程)卡顿,这里需要注意,当UI程序被阻塞大约5s后会出现(应用无响应)ANR对话框 !

2.
new Thread(new Runnable() {
    @Override
    public void run() {
        Picasso.with(GuideActivity.this).load(imageUrl).into(guideIv);
    }
}).start();

以上的这段代码表面上已经解决了我们的问题,因为它通过子线程避免了阻塞,但是它却违背了单线程模式的第二条(不要在UI线程之外访问UI工具包,Android UI包并非线程的安全工具包.以上线程为工作线程,会出现不可预见的行为).因此Android提供了几种其他线程访问主线程的方式:

Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.PostDelayed(Runnable)
Handler

3.天真烂漫的我以为以上几种方式会解决我在android世界中遇到的所有的线程问题,但事实并不是如此,当遇到复杂操作,页面频繁更新的时候,我们的代码逻辑会变得复杂,可读性差,所以AsyncTask(异步)的横空出世,大大的简化了线程间的通信(这里要注意的是,AsyncTask是Android1.5出现的,但并不代表之前的Android1.1和1.0用不了,只是名字不同罢了"UserTask");

4.通过阅读API文档:我们可以得知,AsyncTask被设计为是Thread和Handler的辅助类,但是理想情况下,AsyncTask还是比较适合短操作(大概就几秒),如果要长时间保持线程运行,强烈建议java.util.concurrent包提供的API,例如ThreadPoolExecutorFutureTask;

AsyncTask由3个通用类型(Params, Process, Result)和4个步骤(onPreExecute, doInBackground, onProgressUpdate and onPostExecute)定义;

除了doInBackground方法在子线程中执行外,剩下的方法都在UI线程执行,且在doInBackground方法中可以随时调用publishProgress(),以在 UI 线程中执行onProgressUpdate();

5. 将上面的代码用AsyncTask改写并补充完整为:

public class MainActivity extends AppCompatActivity {

    private ImageView mImageView;

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

        mImageView = (ImageView) findViewById(R.id.main_Iv);
        mImageView.setScaleType(ImageView.ScaleType.CENTER);

        // 当点击默认图片时,进行图片的切换
        mImageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 声明一个异步类对象
                DownloadTask downloadTask = new DownloadTask();
                // 将ImageView空间传递到异步类中
                downloadTask.setImageView(mImageView);
                // 执行异步操作(网址传递)
                downloadTask.execute("http://sjbz.fd.zol-img.com.cn/t_s320x510c/g5/M00/0F/0E/ChMkJ1fJSDKIFwPTAAvIx93CjoYAAU8twM39KkAC8jf384.png");
            }
        });


    }
}
 
  
public class DownloadTask extends AsyncTask {

    private ImageView mImageView;

    public void setImageView(ImageView imageView) {
        mImageView = imageView;
    }

    @Override
    protected Bitmap doInBackground(String... params) {

        try {
            // 进行网络请求(此处也可使用OkHttp进行网络请求)
            // 但是要注意的是发起请求的方法应该是 client.newCall(request).execute();
            // 而不是:
            //  client.newCall(request).enqueue(new Callback() {
            //      @Override
            //      public void onFailure(Call call, IOException e) {
            //
            //      }
            //  }
            // 正如你所看到的,该方法会再开一个线程,导致创建Bitmap的时候出现报空行为

            URL url = new URL(params[0]);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            InputStream is = conn.getInputStream();
            return BitmapFactory.decodeStream(is);

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        super.onPostExecute(bitmap);
        // 将网络解析下来的数据设置到控件上
        mImageView.setImageBitmap(bitmap);
    }
}
 
  
效果展示:
对Thread以及AsyncTask的理解整理_第1张图片

点击图标后:
对Thread以及AsyncTask的理解整理_第2张图片

你可能感兴趣的:(分析类)