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="//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