现在的位置: 首页 > 综合 > 正文

Android异步任务框架AsyncTask由潜入深

2018年04月27日 ⁄ 综合 ⁄ 共 3023字 ⁄ 字号 评论关闭

一、引子

android中新手比较容易犯的一种错误就是界面响应消息阻塞超时。亦即当界面消息在5秒钟内没有完成响应,android系统将自动判断对应activity已无响应,从而系统报错。

下面来看一个简单的例子

                                      

该按键的响应逻辑为使UI线程休眠10秒,那么当我按了一下按键后再按一下按键,第二次按键在5秒后还没有被响应,所以应用程序报错了。

代码如下:

例1:

public class TimeOutActivity extends Activity {

	Button mButton;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.time_out_activity);
		
		mButton = (Button) findViewById(R.id.btn_timeout);
		mButton.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				try {
					TimeUnit.SECONDS.sleep(10);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});
	}
}

所以往往我们在编写UI后台的响应逻辑时,往往需要启动一个后台的线程来进行复杂好使的处理。
通常我们会使用Thread和header来帮组我们解决该问题。

如下例

例2:

public class UIHandlerActivity extends Activity {
	private static final int OPER_RESAULT = 0x01;
	private Button btn_start;
	private static int time = 0;
	private TextView tv_resault;
	
	private Handler mHandler = new Handler() {

		@Override
		public void handleMessage(Message msg) {
			switch(msg.what) {
			case OPER_RESAULT:
				String resault = (String) msg.obj;
				tv_resault.setText(resault);
				break;
			}	
		}
	};
	
	private Runnable operation = new Runnable() {
		@Override
		public void run() {
			for(int i = 1 ; i <= 1000 ; i++) 
				for(int j=1 ; j <= 10000 ; j++);

			mHandler.sendMessage(mHandler.obtainMessage(OPER_RESAULT, "第" + (++time) + "次运算"));
		}
	};
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.ui_handler_activity);
		
		btn_start = (Button) findViewById(R.id.btn_timeout);
		tv_resault = (TextView) findViewById(R.id.tv_resault);
		
		btn_start.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Thread mThread = new Thread(operation);
				mThread.start();
			}
		});
	}
}

二、初窥Async Task

由于后台线程的管理以及对应handler逻辑的维护往往也会比较繁琐,所以android提供了一个异步工具类AsyncTask。它使得UI thread的使用变得异常简单。它使创建需要与用户界面交互的长时间运行的任务变得更简单,不需要借助线程和Handler即可实现。 

根据google关于AsyncTask的参考文档可知,一个AsyncTask的工作流程图如下

2

所以我们在使用AsyncTask时不用关系UI线程阻塞的问题。
我们使用AsycnTask只需要
1)实现doInBackground()接口并将我们需要的计算放在我们实现的doInBackground()方法中。
2)继承onPostExecute()方法并将根据计算结果对应UI的操作放在实现的onPostExecute()方法中。

下面我使用AsyncTask实现上面的例子:

例3:

public class AsyncTaskDemoActivity extends Activity {
	private Button btn_start;
	private TextView tv_resault;
	private static int time = 0;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.ui_handler_activity);
        
        btn_start = (Button) findViewById(R.id.btn_timeout);
		tv_resault = (TextView) findViewById(R.id.tv_resault);
		
		btn_start.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				new Operation().execute();
			}
		});
    }
    
    class Operation extends AsyncTask {

		@Override
		protected Object doInBackground(Object... params) {
			for(int i = 1 ; i <= 1000 ; i++) 
				for(int j=1 ; j <= 10000 ; j++)
					;
			return null;
		}

		@Override
		protected void onPostExecute(Object result) {
			tv_resault.setText( "第" + (++time) + "次运算");
		}
    	
    }
}

但是我们使用的时候应该注意以下几个问题:

1)   Task的实例 必须在UI thread中创建 

2)   execute方 法必须在UI thread中调用 

3)   不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法 

4)   该task只能被执行一次,否则多次调用时将会出现异常

注意这几点后,使用AsyncTask将会变得非常简便。

本文中所有代码均能在以下地址下载:

例1-3下载

抱歉!评论已关闭.