Android多线程的几种模式备忘

来源:互联网 发布:淘宝有找兼职的吗 编辑:程序博客网 时间:2024/06/07 14:14

从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() {@Overridepublic void run() {// TODO Auto-generated method stubSystemClock.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;@Overrideprotected 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() {@Overridepublic 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;@Overrideprotected 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 {// 这里的函数用来访问外部资源,返回textfinal 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;@Overrideprotected 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);}}

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

没有总结~