android异步处理Handler+Thread使用进阶

本文介绍了一种在Android应用中优化异步处理的方法,通过将Handler和Thread从Activity中独立出来,实现三者分离,减少代码冗余并提高管理效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android中异步实现的两个方式,一个是AsyncTask,一个是Handler+Thread。两个方式基本上都是在每个activity里去创建一个AsyncTask或者Handler+Thread。自己也如此做过几个项目,发现的有很多代码冗余,而且不利于管理。自己也在琢磨有什么办法解决这些问题,想着能不能将handler和Thread独立出来。自己试着写了个demo,也算是抛砖引玉,大家评价一下如何。

这里使用的是handler+thread的方式,与一般的结构不同。Handler和Thread的创建并没有在Activity中。App中只用了一个全局的handler,还有有个专门管理子线程的类。

 

结构如上图,Activity A、B通过调用AppRest提供的接口,完成子线程任务的创建。线程任务结束会通过handler发送信息到AppHandler。在这个过程中activity的实例会通过依次传递,最终到AppHandler。AppHandler通过instanceof方法判断调用哪个回调方法。

这样的设计实现了Activity,Handler,Thread三者的分离。

XML代码就是一显示文本内容的Textview和一个页面跳转的Button,这里就不贴代码了。

代码:

Base类

package com.example.testh;

import android.app.Activity;

/**
 * @author SunnyCoffee
 * @date 2013-8-4
 * @version 1.0
 * @desc activity的基类,泛型用于指明回调函数的返回值
 */
public abstract class Base<T> extends Activity {

	/**
	 * 回调方法。
	 * 
	 * @param T
	 */
	public abstract void deal(T result);
}


Activity A:

package com.example.testh;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

//通过泛型指明回调函数返回值类型
public class A extends Base<String> implements OnClickListener {

	private Button btn;
	private TextView tv;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.a);
		btn = (Button) findViewById(R.id.btn);
		btn.setOnClickListener(this);
		tv = (TextView) findViewById(R.id.tv);
		AppRest.login(this, "zhangsan", "123456");// 子线程登录操作
	}

	// 回调函数
	@Override
	public void deal(String result) {
		tv.setText(result);
	}

	@Override
	public void onClick(View v) {
		Intent intent = new Intent();
		intent.setClass(this, B.class);
		startActivity(intent);
	}

}


Activity B:

package com.example.testh;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class B extends Base<String> implements OnClickListener {

	private Button btn;
	private TextView tv;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.b);
		btn = (Button) findViewById(R.id.btn);
		btn.setOnClickListener(this);
		tv = (TextView) findViewById(R.id.tv);
		AppRest.getGoodsList(this);
	}

	@Override
	public void deal(String result) {
		tv.setText(result);
	}

	@Override
	public void onClick(View v) {
		Intent intent = new Intent();
		intent.setClass(this, A.class);
		startActivity(intent);
	}
}

AppRest 类:

package com.example.testh;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

/**
 * @author SunnyCoffee
 * @date 2013-8-4
 * @version 1.0
 * @desc 调用子线程工作的接口
 */
public class AppRest {

	private static final int THREAD_POOL_SIZE = 5;
	private static Handler handler = AppHandler.getInstance();
	private static ExecutorService service = Executors// 线程池
			.newFixedThreadPool(THREAD_POOL_SIZE);

	/**
	 * 启动登录线程的接口
	 * 
	 * @param context
	 * @param name
	 * @param passwd
	 */
	public static void login(final Context context, final String name,
			final String passwd) {
		Runnable r = new Runnable() {
			@Override
			public void run() {
				/**
				 * TODO 连接服务器获取数据的操作写在这里,返回结果将通过handler发送
				 * 
				 * 这里假设服务器返回的都是文本类型的数据。 如果返回的是json对象,建议这里使用gson进行解析javabean,
				 * 然后通过bundle .putSerializable(key,value)方式发送。
				 * 这会要求javabean实现Serializable接口
				 * 
				 */

				Message msg = handler.obtainMessage();
				Bundle b = new Bundle();
				b.putString("result", "服务器返回登录结果:hello," + name);// 模拟数据
				msg.setData(b);
				msg.obj = context;
				handler.sendMessage(msg);
			}
		};
		service.execute(r);
	}

	/**
	 * 获得商品列表数据
	 * 
	 * @param context
	 */
	public static void getGoodsList(final Context context) {

		Runnable r = new Runnable() {
			@Override
			public void run() {
				// TODO 实际的操作
				Message msg = handler.obtainMessage();
				Bundle b = new Bundle();
				b.putString("result", "服务器返回的商品列表数据");
				msg.setData(b);
				msg.obj = context;
				handler.sendMessage(msg);
			}
		};
		service.execute(r);
	}
}
 

AppHandler 类:

package com.example.testh;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

/**
 * @author SunnyCoffee
 * @date 2013-8-4
 * @version 1.0
 * @desc 整个APP的handler,用于处理子线程向主线程的信息传递
 */
public class AppHandler extends Handler {

	private static AppHandler handler = new AppHandler();

	// 单例模式
	private AppHandler() {
	}

	public static AppHandler getInstance() {
		return handler;
	}

	@Override
	public void handleMessage(Message msg) {
		Object obj = msg.obj;
		if (msg == null || obj == null)
			return;
		Bundle b = msg.getData();
		if (b == null)
			return;
		/**
		 * obj即为Activity的实例,这里建议进行生命周期的判断,比如puse destroy。
		 * 如果确定服务器返回值为文本类型且要把json的解析放在主线程,建议使用这种方式 if (obj instanceof Base) {
		 * String json = b.getString("result"); ((Base) obj).deal(result) }
		 * 
		 */
		String result = b.getString("result");

		if (obj instanceof A) {
			((A) obj).deal(result);
		} else if (obj instanceof B) {
			((B) obj).deal(result);
		}

	}
}

这个设计现在还是一个初步设计,觉得和AsyncTask的设计很相似,很多可以借鉴AsyncTask的思想。当然还有好多自己的想法没有涉及。


1.当一个Activity中有两个以上的线程的时候,简单的方法就是通过在Activity再创建一个方法供AppHandler进行回调。

2.如果服务器返回的只用文本信息(如json等),可以考虑将json放在主线程中解析,这样回调函数就能有一个统一的参数类型String。

3.等待页面的问题,将等待页面写在AppRest类中以实现代码复用。

4.将AppHandler和AppRest合二为一?这个我现在还没打算这么做,现在这样觉得更清晰条理。

5.关于泛型的问题。因为handler使用了单例,所以无法使用泛型。下一步考虑不再使用static对象或方法。

6.如果线程的调用者不是activity而是Fragment,这个问题也再考虑中。

 

改进方案参考:

android异步处理Handler+Thread使用进阶(二)

android异步处理Handler+Thread使用进阶(三)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值