从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);
}
}
所有这些方法,和个人的风格可能也有关系,蛮有意思,继续研读~
没有总结~