AsyncTask的异步线程的使用

Posted EdwardRu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AsyncTask的异步线程的使用相关的知识,希望对你有一定的参考价值。

使用异步任务加载BItmap以及模仿Progressbar进度条的案例

public class MainActivity extends AppCompatActivity {
    public Context context;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent=new Intent();
                intent.setClass(MainActivity.this,ImageText.class);
                startActivity(intent);
            }
        });
        Button button1= (Button) findViewById(R.id.button2);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent=new Intent();
                intent.setClass(MainActivity.this,ProgressBarTest.class);
                startActivity(intent);
            }
        });
    }

}

设置监听事件分别调用两个不同的Activity,在第一个加载网络图片的Activity中需要用到网络,要在mainfest中设置用户访问网络的权限

在设置监听事件中,使用Intent调用代码,使用的是6.0的api,需要将intent中的参数设置为(XXXX.this,XXXXX.class)才能解决无效指针的问题。

加载网络图片的代码

public class ImageText extends AppCompatActivity {
    private ImageView imageView;
    private ProgressBar progressBar;
    private static String URL="http://img.my.csdn.net/uploads/201504/12/1428806103_9476.png";
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.imagetest);
        imageView=(ImageView) findViewById(R.id.image11);
        progressBar= (ProgressBar) findViewById(R.id.bar);
        new MyASyncTask().execute(URL);
    }
    class MyASyncTask extends AsyncTask<String,Void,Bitmap> {
        @Override
        protected void onPostExecute(Bitmap bitmap) {
            //在已经加载过图片后Progressbar设置为不可见
            progressBar.setVisibility(View.GONE);
            //设置已经传入的网络图片bitmap
            imageView.setImageBitmap(bitmap);
            super.onPostExecute(bitmap);
        }

        @Override
        protected void onPreExecute() {
            //显示进度条
            progressBar.setVisibility(View.VISIBLE);
            super.onPreExecute();
        }

        @Override
        protected Bitmap doInBackground(String... strings) {
            //从excute中获得所传进来的string的值
            String url=strings[0];
            //必须初始化bitmap
            Bitmap bitmap = null;
            //设置网络连接的对象
            URLConnection connection;
            //设置输入流
            InputStream inputStream;
            try {
                //获取网络连接对象,必须导入java.net.URL的包
                connection=new URL(url).openConnection();
                inputStream=connection.getInputStream();
                Thread.sleep(3000);
                //封装输入流
                BufferedInputStream bis=new BufferedInputStream(inputStream);
                //解析输入流
                bitmap= BitmapFactory.decodeStream(bis);
                //关闭输入流和封装流
                inputStream.close();
                bis.close();
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
            //返回所接受过的bitmap
            return bitmap;
        }
    }
    }

写代码的思路梳理:

通过OnProExcute方法和onPostExcute方法操作UI设置图像
mProgressBar.setVisbility(View.VISIBLE)显示进度条
onPostExcute(BitMap bitmap)//bitmap为doingbackground方法返回的一个bitmap
在Main方法中,调用MyAsycTask的execute方法传入(URL)
通过AsyncTask的实例调用execute方法就可以开启AsyncTask的异步操作,在execute方法中传入一个或多个参数作为我们doingbackground方法中所传进来的一个参数
在AsyncTask的OnPreExecute方法中调用初始化的方法,在后台启动异步操作提示用户等待,

调用真正的doingBackGround方法开始真正的异步处理,这里的整个方法都是现在子线程之中,在这个方法中进行所有的耗时操作,并将所要返回的值返回到我们所设定的值的类型中

在OnpostExecute方法中获得我们所返回的结果,onPostExcute方法也运行在主线程之中从而我们可以对UI进行操作,这就是AsyncTask所要调用的整个流程。


在Mainfest中开通所要访问的网络权限
增加button调用

********************************************************************

设置ProgressBar的代码

public class ProgressBarTest extends AppCompatActivity {
    private MaysncTask mTask;
    private ProgressBar progressBar;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.progressbartest);
        //获取自定义内部类的AsyncTask的方法
        mTask=new MaysncTask();
        //运行这个方法
        mTask.execute();
        progressBar= (ProgressBar) findViewById(R.id.progressBar);
    }

    @Override
    //在activity退出前想保存用户重要数据的,必须在onPause中处理,因为当系统急需内存事,onStop和onDestroy是不会被执行的,
    protected void onPause() {
        super.onPause();
        if(mTask!=null&&mTask.getStatus()==AsyncTask.Status.RUNNING){
            mTask.cancel(true);
        }
    }

    class MaysncTask extends AsyncTask<Void,Integer,Void>{
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            //从doingbackground中得到所传入的值,为传入的整形数组values的第一个值,使用setprogress方法设置Progressbar的方法
            progressBar.setProgress(values[0]);
            if(isCancelled()){
                //判断AsyncTask是否为cancel状态如果为cancel状态则return。return语句是将函数的值返回主调函数
                return;
            }
        }

        @Override
        protected Void doInBackground(Void... voids) {
            for(int i=0;i<100;i++){
                if(isCancelled()){
                    break;
                }
                //publishProgress() 更新进度,给onProgressUpdate()传递进度参数publishProgress传递的为整数
                publishProgress(i);
                try {
                    //设置延迟的效果300毫秒
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }
    }
    }

在运行模拟Progress的运动的代码中出现没有办法停止前一个线程的解决办法:

AsyncTask默认情况下会等待前一个线程执行完毕后再执行下一个线程,要取消该机制,可以让AsyncTask和Activity的生命周期保持一致
protected void onPause(){
super.onPause();
if(mTask != null && mTask.getStatus() == AsyncTask.Status.RUNNING){
//只是发送了一个取消请求,将AsyncTask标记为cancel状态,但未真正取消线程的执行
//实际上JAVA语音没办法粗暴地直接停止一个正在运行的线程
mTask.cancel(true);
}
}

所以需要在doInBackground方法和onProgressUpdate方法中增加isCancelled()方法进行判断,标记为cancel的,则跳出循环,尽快结束当前线程的剩余操作,开始下一个线程

AsyncTask实现的机制:底层通过线程池来作用的,当我们一个线程没有执行完毕时,后面的线程是无法执行的;
调用cancel方法去cancel一个asynctask线程,并没有将这个线程直接停止掉,只是给这个asynctask发送了一个cancel请求,将它标识为cancel状态;
在java中是无法直接将一个线程粗暴地停止掉,我们必须等一个线程执行完毕后才能做后面的操作。(需通过状态值判断去跳出子线程的循环操作)

只有doInBackground是在非UI线程中执行
mytask!=null&&mytask.getStatus()== AsyncTask.Status.RUNNING
ansystask 即使cancel设置为true 也不能立即取消,只是将状态设为取消
故在doInBackground和onUpdatexx的时候检测isCancled()是不是true

 

以上是关于AsyncTask的异步线程的使用的主要内容,如果未能解决你的问题,请参考以下文章

AsyncTask实现网络图片的异步加载

安卓Android开发:使用Executor线程池代替AsyncTask进行异步操作

安卓Android开发:使用Executor线程池代替AsyncTask进行异步操作

安卓Android开发:使用Executor线程池代替AsyncTask进行异步操作

android asynctask怎么用

AsyncTask的异步线程的使用