Android多线程的几种模式备忘

从eoe上的学习 http://www.eoeandroid.com/thread-210082-1-1.html



第一种,实际上只在UI线程跑的Handler.post方法,并没有多线程,用于对比。

private void loadText (final String string, final int id) {
		handler.post( new Runnable() {

			@Override
			public void run() {
				// TODO Auto-generated method stub
				SystemClock.sleep(2000);
				((TextView) MainActivity.this.findViewById(id)).setText(string);
			}
		});
	}

在onCreate方法中,通过调用loadText加载文字,sleep模拟延时环境,这种方法,所有函数都是在UI线程中跑的,大概和handler.post方法有关、

handler.post(Runnable)中的Run方法只会在handler所在的线程中运行,handler在UI线程,所以,这里面run的方法也都在UI线程中跑,要不然也不能findview更新view了,反正这样handler没有新开一个线程,只是把Runnable放进去而已。


第二种,Handler + Thread + Message组合方法

实际上这种方法最容易理解了,UI线程的handler不断查询新建的Thread返回来的Message,得到有效的消息后就更新UI,这样UI线程一直没有被耗时长的任务占用。

package test.thread;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

	private TextView tv1;
	private TextView tv2;
	private TextView tv3;
	private TextView tv4;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		// 运行四次函数,四个view同时加载
		loadText("1",R.id.textView1);
		loadText("2",R.id.textView2);
		loadText("3",R.id.textView3);
		loadText("4",R.id.textView4);
	}
	
	// handler运行在UI线程,用来接收其它线程返回的消息
	private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
        	((TextView) MainActivity.this.findViewById(msg.arg1)).setText((String) msg.obj);
        	Toast.makeText(MainActivity.this, (String)msg.obj, Toast.LENGTH_SHORT).show();
        }
	};

	
	// 运行函数会自动打开一个线程
	private void loadText (final String string, final int id) {
		
		// 创建一个线程,不知道这里面为什么不用写匿名类,java不熟
		Thread thread = new Thread() {
			@Override
			public void run() {
				
				// 假装处理状态
				SystemClock.sleep(2000);
				
				// 处理完毕发回主线程的数据
				Message message = handler.obtainMessage();
                		message.arg1 = id;
                		message.obj = string;
                		handler.sendMessage(message);
			}
		};
		// 这里才真正打开这个线程,这句不能少,要不然线程不可能运行
		thread.start();
	}
}
在函数中创建线程,然后在函数中打开线程,直接在主线程handler接收,方法ok,如果是我来写,可能更愿意写一个 内部任务类 + onCreate中创建线程 + 外部handler接收,实质是一样的,不知道这种写法优势在哪儿? 毕竟线程也是有限的,要是函数运行多了,循环创建几个,不就出问题了么。

第三种,和Java一样,线程多的时候需要使用线程池,也即Handler + ExecutorService + MessageQueue的模式

package test.thread;

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

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

	private TextView tv1;
	private TextView tv2;
	private TextView tv3;
	private TextView tv4;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		// 运行四次函数,四个view同时加载
		loadText("1",R.id.textView1);
		loadText("2",R.id.textView2);
		loadText("3",R.id.textView3);
		loadText("4",R.id.textView4);
	}
	
	// handler运行在UI线程,用来接收其它线程返回的消息
	private Handler handler = new Handler();
	
	private ExecutorService executorService = Executors.newFixedThreadPool(5);

	private void loadText (final String string, final int id) {
		
		// 与之前不一样,这里不创建Thread而是给ExecutorService submit一个Runnable对象
		// 相当于用ExecutorService去管理这个Runnable对象了
		executorService.submit(new Runnable() {
            public void run() {
                try {
				
                	// 假装处理状态
                	SystemClock.sleep(2000);
				
                	// 这里不是发回数据而是用handler.post,直接用主线程更新
                	handler.post(new Runnable() {
                        public void run() {
                        	((TextView) MainActivity.this.findViewById(id)).setText(string);
                        	}
                	});
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
		});
	}
}

第四种,终极大招 异步+缓存

谈到缓存管理,Android还是有一些内容的,一些频繁的资源,使用SoftReference,关于SoftReference,它是Java中的内存回收机制里面的东东, 这里写的很清楚http://www2.sys-con.com/itsg/virtualcd/java/archives/0507/shields/index.html 除了SoftReference,还有StrongReference, WeakReference以及虚引用PhantomReference,各有不同。

对于再有一些大型资源,需要频繁访问,就可以保存到本地,下次再加载了。

等于双重保障的意思吧,申请一个资源,1. 看缓存; 2. 看本地空间; 3. 费时获取;

这里就先试试缓存吧

1. 异步加载类(全部封装)

package test.thread;


import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import android.os.Handler;
import android.os.SystemClock;

public class AsyncLoader {
		// 为了加快速度,在内存中开启缓存(主要应用于重复图片较多时,或者同一个图片要多次被访问,比如在ListView时来回滚动)
		public Map<String, SoftReference<String>> stringCache = new HashMap<String, SoftReference<String>>();
		private ExecutorService executorService = Executors.newFixedThreadPool(5); // 固定五个线程来执行任务
		private final Handler handler = new Handler();

		
		public String loadText(final String string,
				final Callback callback) {
				// 如果缓存过就从缓存中取出数据
				if (stringCache.containsKey(string)) {
						SoftReference<String> softReference = stringCache.get(string);
						if (softReference.get() != null) {
								return softReference.get();
						}
				}
				// 缓存中没有数据,从耗时任务中获取资源
				executorService.submit(new Runnable() {
						public void run() {
								try {
										// 这里的函数用来访问外部资源,返回text
										final String text = loadStringFromOutSide(string);
										// 将text缓存
										stringCache.put(string, new SoftReference<String>(
													text));
										
										// 主线程回调,下面这段有点儿不太明白
										handler.post(new Runnable() {
												public void run() {
													callback.textLoaded(text);
												}
										});
								} catch (Exception e) {
									throw new RuntimeException(e);
								}
						}
				});
				return null;
		}

		//从网络上取数据方法
		protected String loadStringFromOutSide(String string) {
			try {

					SystemClock.sleep(2000);
					// 稍微修改一下string返回
					return string + " in outside.";
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
		
		// 回调
		public interface Callback {
			// 注意 此方法是用来设置目标对象的图像资源
			public void textLoaded(String string);
		}
}

2.UI线程

package test.thread;

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

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

	private TextView tv1;
	private TextView tv2;
	private TextView tv3;
	private TextView tv4;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		// 运行四次函数,四个view同时加载
		loadText("1",R.id.textView1);
		loadText("2",R.id.textView2);
		loadText("3",R.id.textView3);
		loadText("4",R.id.textView4);
	}
	
	private AsyncLoader asyncLoader = new AsyncLoader();
	
	// 线程池回调缓存等全部封装
	private void loadText (final String string, final int id) {
		String text = asyncLoader.loadText(string, 
				// 此回调?
				new AsyncLoader.Callback() {
					
					public void textLoaded(String string) {
						// TODO Auto-generated method stub
						((TextView) findViewById(id)).setText(string);
					}
				});
		
		if (null != text)
			((TextView) findViewById(id)).setText(text);
		
	}
}

所有这些方法,和个人的风格可能也有关系,蛮有意思,继续研读~

没有总结~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值