搭建android简洁开发架构--多线程交互篇

声明:本文读者适合有一定android开发经验的程序员,文中肯定有不足之处,欢迎指正。

在android开发中,异步处理模块(控制器)占有很大比例,异步处理的稳定与否关乎整个应用的运行速度和用户体验,android开发不像web开发,web开发有各种各样的框架可以套用,使整个系统的架构看上去很明朗,因为笔者有代码混乱恐惧症,所以每当看到各种android实例,包括一些成熟应用的代码中,progress dialog满天飞,一个activity实例化n个oncliklistener,handler  thread得哪儿放哪儿,笔者就忍不住用最快的时间关掉程序。在了解和使用了无数handler+thread组合后,我决定抛弃它们,使用android api提供的AsyncTask,虽然重构代码需要一定工作量,但我认为这是值得的。

什么是AsyncTask?简单地说,它是一个线程池。

如何使用AsyncTask并有效把它整合为架构的一部分?

首先我们需要新建一个继承AsyncTask的类,名字就叫MainAsyncTask,好了,就用它来处理乱七八糟的异步任务!MainAsyncTask需要继承一些父类方法,供系统回调(注意不能主动调用回调接口),AsyncTask中常用的回调方法如下:

onPreExecute(), 该方法将在执行实际的后台操作前被UI thread调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。

doInBackground(Params...), 将在onPreExecute 方法执行后马上执行,该方法运行在后台线程中。这里将主要负责执行那些很耗时的后台计算工作。可以调用 publishProgress方法来更新实时的任务进度。该方法是抽象方法,子类必须实现。

onProgressUpdate(Progress...),在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。

onPostExecute(Result), 在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用,后台的计算结果将通过该方法传递到UI thread.

好吧,让我们看看如何在主线程(UI线程)中调用吧。

1、activity页面调用

MainAsynTask asynTask = new MainAsynTask(this);
asynTask.execute(Constants.TASK_USER_LOGIN);
以LoginActivity为例,我们要执行的是一个登录任务,这里只需两行代码,execute 传入的是任务号(当然,这里可以传入多个参数,类型自便),this代表的activity上下文,至于如何执行,就交给万能的AsyncTask吧。

2、MainAsyncTask!

public class MainAsynTask extends AsyncTask<Object, Object, Object> implements Serializable{// 继承AsyncTask

AsyncTask定义了三种泛型类型 Params,Progress和Result,作为传入参数。

Params 是启动任务执行的输入参数,比如HTTP请求的URL。Progress 是后台任务执行的百分比。Result 是后台执行任务最终返回的结果,比如String。
上面代码是我定义的三个输入参数,为了兼容全定义成Object,第一个参数是任务号,用来区分处理任务,仍然沿用之前的int类型的TASK_ID,只不过放入Object中;第二个参数暂时没用,第三个参数是返回类型,定义为Object,在刷新UI线程时(即取得结果时)再强转成需要的类型。

3、MainAsyncTask的构造函数

public MainAsynTask(Context context) {
		this.context = context;
		baseActivity = (BaseActivity) this.getContext();
	}

没错,context接收的参数就是调用时的activity上下文,方法体中利用多态思想实例化当前activity。

4、业务处理前要做的....

// 在 doInBackground(Params...)之前被调用,ui线程执行
	@Override
	protected void onPreExecute() {
		baseActivity.setDialogDisplay(this);
	}
这里是简单地显示一个等待框。

5、业务处理时

@Override
	protected Object doInBackground(Object... params) {// 处理后台执行的任务,在后台线程执行
		while (running) {
			Log.e("执行任务中", "..........");
			int taskId = (Integer)params[0];
			switch (taskId) {
			case Constants.TASK_USER_LOGIN:
				User user = UHomeApplication.getInstance().getUser();
				//其它业务代码
				return true;
			}
		}
		return null;
	}
注意,params[0]就是我们传入的任务号。switch先判断不同的任务号然后再确定执行哪个任务。进入此方法就不能对UI线程进行操作了。

6、返回结果

@Override
	protected void onPostExecute(Object result) {// 后台任务执行完之后被调用,在ui线程执行
		if (result != null) {
			baseActivity.setDialogDisappear(this);
			baseActivity.refresh(result);
			running = false;
		} else {
			baseActivity.setDialogDisappear(this);
			Toast.makeText(context, "服务器无响应", Toast.LENGTH_LONG).show();
			running = false;
		}
	}
传入参数result即上一步的return,我们可以对它进行分析和处理,,在这里可以对UI线程进行操作了。因为baseActivity已经被我们强转成了子类,所以,这里调用的refresh是子类实现的方法。

7、更新主线程(UI)

@Override
	public void refresh(Object... args) {
		super.refresh(args);
		boolean flag = (Boolean) args[0];
		if(flag){
			//登录成功
		}
	}
上述代码在第一步中的activity中,refresh方法是继承自BaseActivity的。BaseActivity是一个自定义的类,内有常用的方法,供继承者调用,如refresh

附:部分BaseActivity代码

public class BaseActivity extends Activity {
	//等待框
	protected ProgressDialog dlg;
	protected MainAsynTask mainAsyncTask;
	//异步调用后activity接收结果并更新UI
	public void refresh(Object... param) {

	}
	//activity初始化时执行代码,如检查网络、实例化控件等
	public void prepareUI() {
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		Log.e("BaseActivity启动", "..................");
		dlg = new ProgressDialog(this);
	}
	public void setDialogDisplay(MainAsynTask mainTask) {
		Bundle bun = new Bundle();
		bun.putSerializable("syc", mainTask);
		this.onCreateDialog(1,bun);
	}
	public void setDialogDisappear(MainAsynTask mainTask) {
		Bundle bun = new Bundle();
		bun.putSerializable("syc", mainTask);
		this.onCreateDialog(0,bun);
	}
}

总结:
先前异步处理模块特点:使用handler+thread处理机制,缺点是代码冗余量大,业务处理晦涩难懂,thread(线程)运行有不可遇见的问题,需要另写大量的维护代码,handler对程序主线程的占用率也是惊人的,如果出现异常可能导致系统崩溃。优点是效率较高,无需另启线程池来维护,对于业务量少后台任务不复杂的应用来说这种机制是首选。

使用AsyncTask后特点:优点:AsyncTask是成熟的作品,可以很好解决一些线程安全问题,不用我们手动维护线程;代码比较整洁,业务易于理解。缺点:虽然AsyncTask在代码上比handler要轻量,而实际上要比handler更耗资源,因为AsyncTask底层是一个线程池,这也是开始没有使用它的原因,但是,如果异步任务的数据庞大,AsyncTask这种线程池结构的优势就体现出来了。另外,AsyncTask目前最多只能同时存在20个实例,不过只要能够做到用完就释放,这个不算是太大的问题。

还需解决的问题:

大家都知道,此框架中,如果activity要处理异步任务,需要继承BaseActivty,而有些应用中activity还会继承别的类,如tabhost,鉴于java单一继承机制,笔者认为上述框架还需修改,将BaseActivty抽象成接口即可,本文算是改进前的一篇技术预言吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值