首页 > 代码库 > AsyncTask的异步线程的使用

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的异步线程的使用