Android AsyncTask 和 handler 理解

来源:互联网 发布:开淘宝店的规则 编辑:程序博客网 时间:2024/05/16 14:16

开始记自己的东西吧,希望坚持下去,菜鸟变老鸟。


android的ui线程操作并不是安全的,并且和用户直接进行界面交互的操作都必须在ui线程中进行才可以。这种模式叫做单线程模式。

在单线程模式下编程一定要注意:不要阻塞ui线程、确保只在ui线程中访问ui组件

当要执行一个复杂耗时的算法并且最终要将计算结果反映到ui上时,我们会发现,我们根本没办法同时保证上面的两点要求;我们肯定会想到开启一个新的线程,让这个复杂耗时的任务到后台去执行,但是执行完毕了呢?我们发现,我们无法再与ui进行交互了。如果把UI组件作为参数传给后台线程,然后试图让后台线程更新UI组件时就会报错:04-30 08:57:16.457: W/System.err(537): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.意思就是只有UI线程可以更新Ui自己的组件。

为了解决这种情况,android为我们提供了很多办法,我用了两种办法。

1)、handler和message机制,通过显示的抛出、捕获消息与ui进行交互,这种方法操作时主要有两步:
.在主线程中创建Handler对象,并重载 handleMessage(Message msg) 处理方法,实现组件更新;b. 在子线程中使用MainThread中创建的 Handler对象进行消息发送和MainThread进行通信。
下面是一个简单的例子,但是运行时如果Message使用Bundle传值主线程居然获取不到。至今不知道为什么,等以后再调试吧。先直接传一个int值作为例子吧。
package com.example.base_day03_handler;import android.app.Activity;import android.content.res.Resources.Theme;import android.os.Bundle;import android.os.Handler;import android.os.HandlerThread;import android.os.Looper;import android.os.Message;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;public class MainActivity extends Activity implements OnClickListener {private Button btnTXT;private TextView tvTXT;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btnTXT = (Button) findViewById(R.id.btnTXT);tvTXT = (TextView) findViewById(R.id.tvTXT);btnTXT.setOnClickListener(this);}/**  * 主线程Handler,可以与UI控件交互 *  *  */Handler mainHanlder = new Handler() {@Overridepublic void handleMessage(Message msg) {if (msg.what == 0) {Log.i("test", "name = " +msg.arg1);tvTXT.setText(msg.arg1+" "); // 与主线程控件打交道(直接访问)Log.i("test", "Activity Thread   "+Thread.currentThread().getId()+"");}}};@Overridepublic void onClick(View v) {MyThread myThread = new MyThread(mainHanlder);Thread th = new Thread(myThread);th.start();}}

2)、另外android1.5以后为我们提供了一个工具类来搞定这个问题 AsyncTask。这个我也做了个简单的例子,功能是下载图片到SD卡,下载时有进度条提示,重点是AsyncTaskClzss类注释写的很明确。
package com.example.base_day03_asynctaskimage;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;import android.widget.ImageView;import android.widget.ProgressBar;import com.zzw.asynctaskdemo01.AsyncTaskClzss;public class MainActivity extends Activity {private Button mButton;private EditText mEditText;private ImageView mImageView;private ProgressBar mProgressBar;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mImageView = (ImageView) findViewById(R.id.imageView);mButton = (Button) findViewById(R.id.button);mProgressBar = (ProgressBar) findViewById(R.id.progressBar);mEditText = (EditText) findViewById(R.id.http_editText1);mButton.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {String URLStr = mEditText.getText().toString();AsyncTaskClzss task = new AsyncTaskClzss(getApplicationContext(),mProgressBar,mImageView);task.execute(URLStr);}});}}

package com.zzw.asynctaskdemo01;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.HttpURLConnection;import java.net.MalformedURLException;import java.net.URL;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.AsyncTask;import android.widget.ImageView;import android.widget.ProgressBar;/** * 与主线程有交互时用AsyncTask,否则就用Thread * @author Administrator * */public class AsyncTaskClzss extends AsyncTask<String, Integer, Bitmap> {private FileUtils fileUitl = null;private Context context = null;private int totalSize = 0;private int currentSize = 0;private int len = 0;private byte[] buffer = new byte[4 * 1024];private ImageView mImageView;private ProgressBar mProgressBar;public AsyncTaskClzss() {}public AsyncTaskClzss(Context context, ProgressBar mProgressBar, ImageView mImageView){this.context = context;this.mProgressBar = mProgressBar;this.mImageView = mImageView;}/** * 将在onPreExecute 方法执行后马上执行,该方法运行在后台线程中。 * 这里将主要负责执行那些很耗时的后台计算工作。可以调用  * publishProgress方法来更新实时的任务进度。该方法是抽象方法, * 子类必须实现。  */@SuppressWarnings("resource")@Overrideprotected Bitmap doInBackground(String... params) {publishProgress(0);fileUitl = new FileUtils();URL URLPaht = null;String strURL = params[0];try {URLPaht = new URL(strURL);} catch (MalformedURLException e) {e.printStackTrace();}HttpURLConnection conn = null;try {conn = (HttpURLConnection) URLPaht.openConnection();} catch (IOException e) {e.printStackTrace();}String fileName = strURL.substring(strURL.lastIndexOf("/")+1);File newFile = fileUitl.creatNewFile("/Img", fileName);write2SDFromInput(newFile, conn);Bitmap bm = BitmapFactory.decodeFile(fileUitl.getFilePaht());return bm;}/** * 在publishProgress方法被调用后, * UI 线程将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。 */@Overrideprotected void onProgressUpdate(Integer... values) {this.mProgressBar.setProgress(values[0]);}/** * 在doInBackground 执行完成后, * onPostExecute 方法将被UI thread调用,后台的计算结果将通过该方法传递到UI thread.  */@Overrideprotected void onPostExecute(Bitmap result) {this.mImageView.setImageBitmap(result);}/** * 该方法将在执行实际的后台操作前被UI thread调用。 * 可以在该方法中做一些准备工作,如在界面上显示一个进度条。 */@Overrideprotected void onPreExecute() {this.mProgressBar.setProgress(0);this.mImageView.setImageBitmap(null);}public File write2SDFromInput(File newFile, HttpURLConnection conn) {InputStream input = null;try {input = conn.getInputStream();totalSize = conn.getContentLength();} catch (IOException e1) {e1.printStackTrace();}OutputStream output = null;try {output = new FileOutputStream(newFile);byte buffer[] = new byte[4 * 1024];int temp = 0;while ((temp = input.read(buffer)) != -1) {currentSize += temp;output.write(buffer, 0, temp);//更新进度条int index = currentSize * 100 / totalSize;//该方法可以在后台线程执行时通知UI线程(主线程)去更新其界面//更新操作具体实现是,触发onProgressUpdate()方法,该方法在UI线程运行一次更新UI界面publishProgress(index);}output.flush();} catch (Exception e) {e.printStackTrace();} finally {try {output.close();} catch (Exception e) {e.printStackTrace();}}return newFile;}}

package com.zzw.asynctaskdemo01;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.HttpURLConnection;import android.os.Environment;import android.util.Log;public class FileUtils {private String filePaht ;public String getFilePaht() {return filePaht;}public void setFilePaht(String filePaht) {this.filePaht = filePaht;}public File creatNewFile(String dirPath, String fileName) {File newFile = null;if (Environment.getExternalStorageState().equals((Environment.MEDIA_MOUNTED))) {File sdCardDir = Environment.getExternalStorageDirectory();            String tmpPath=sdCardDir.getPath();            File dir= new File(tmpPath+ dirPath);              dir.mkdir();            newFile = new File(dir,  fileName);this.filePaht = dir.getPath()+"/"+fileName;Log.i("test", "tmppath "+tmpPath);Log.i("test", "tmppath+ dirPath "+tmpPath+ dirPath);Log.i("test", "filePaht "+filePaht);try {newFile.createNewFile();} catch (IOException e1) {}}else{Log.i("test", "SDCard does not exist");}return newFile;}}



0 0