Looper分析。ThreadLocal有关
Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one,
call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
(1)提出问题:正如上面所说, 一个线程默认是没有Looper用来处理message队列的。但为什么我们在主线程时又没有自己创建Looper呢?
public class Looper {
private static final String TAG = "Looper";
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); //(1)又见到了眼熟的ThreadLocal,里面存放的是每个线程的Looper
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
volatile boolean mRun;
private Printer mLogging;
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper(); //(2)为主线程的Looper赋值
}
}
/** Returns the application's main looper, which lives in the main thread of the application.
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static Looper myLooper() { //(3)为主线程Looper赋值的其实就是调用ThreadLocal的get()
return sThreadLocal.get();
}
}
2.如果不知道ThreadLocal是什么意思,自己去查API,我没这么大气和你讲。
3.所以我们可以这样用:
public class MainActivity extends Activity {
private ProgressDialog mpDialog;
private int mCount = 0;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
//update UI
System.out.println("----------update ui ok--------------"+Thread.currentThread().getId()); // Thread id 为1 说明在主线程中执行。
System.out.println("message arg1 : "+ msg.arg1); //因为这是主线程,所以可以在这时更新UI
super.handleMessage(msg);
}
};
private Thread downThread = new Thread(){
@Override
public void run() {
try{
while(mCount<=100){
mpDialog.setProgress(mCount++);
Thread.sleep(100); //模拟下载过程
}
// This is essentially the same as calling dismiss(),
//but it will also call your DialogInterface.OnCancelListener (if registered).
mpDialog.cancel();
System.out.println("------------download ok----------");
Message message = handler.obtainMessage();
message.arg1 = 10;
handler.sendMessage(message);
}catch(Exception ex){
mpDialog.cancel();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button= (Button) this.findViewById(R.id.button);
imageView = (ImageView) this.findViewById(R.id.imageView01);
button.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View view) {
System.out.println("--------------download start----------------"+Thread.currentThread().getId()); //主线程的id为1
mCount = 0;
mpDialog = new ProgressDialog(MainActivity.this);
mpDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mpDialog.setTitle("dialogʾ");
mpDialog.setIcon(R.drawable.ic_launcher);
mpDialog.setMessage("好消息");
mpDialog.setMax(100);
mpDialog.setProgress(0);
mpDialog.setSecondaryProgress(50);
mpDialog.setIndeterminate(false);
mpDialog.setCancelable(true);
mpDialog.setButton("取消", new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
downThread.start();
mpDialog.show();
}
});
}
}
4.正如上面所说,一个新线程在默认情况下是没有Looper相关联的。所以需要自己创建。但android提供了一个HandlerThread,方便我们使用Looper。
public class HandlerThread extends Thread {
Looper mLooper;
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
/**
* This method returns the Looper associated with this thread. If this thread not been started
* or for any reason is isAlive() returns false, this method will return null. If this thread
* has been started, this method will block until the looper has been initialized.
* @return The looper.
*/
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
}
Looper分析。ThreadLocal有关的更多相关文章
- 分析 ThreadLocal 内存泄漏问题
ThreadLocal 的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度.但是如果滥用 ThreadLocal,就可能会导 ...
- 分析ThreadLocal的弱引用与内存泄漏问题
目录 一.介绍 二.问题提出 2.1内存原理图 2.2几个问题 三.回答问题 3.1为什么会出现内存泄漏 3.2若Entry使用弱引用 3.3弱引用配合自动回收 四.总结 一.介绍 之前使用Threa ...
- Netty源码分析-- ThreadLocal分析(九)
为了更好地探讨Netty的内存模型,后面会用到,这里我还是决定跟大家一起看下ThreadLocal和FastThreadLocal的源码,有的时候我们在看源码的时候会一层层的遇到很多之前没有看过的内容 ...
- ThreadLocal 工作原理、部分源码分析
1.大概去哪里看 ThreadLocal 其根本实现方法,是在Thread里面,有一个ThreadLocal.ThreadLocalMap属性 ThreadLocal.ThreadLocalMap t ...
- Java 中 ThreadLocal 内存泄露的实例分析
前言 之前写了一篇深入分析 ThreadLocal 内存泄漏问题是从理论上分析ThreadLocal的内存泄漏问题,这一篇文章我们来分析一下实际的内存泄漏案例.分析问题的过程比结果更重要,理论结合实际 ...
- ThreadLocal的原理,源码深度分析及使用
文章简介 ThreadLocal应该都比较熟悉,这篇文章会基于ThreadLocal的应用以及实现原理做一个全面的分析 内容导航 什么是ThreadLocal ThreadLocal的使用 分析Thr ...
- ThreadLocal的使用及原理分析
文章简介 ThreadLocal应该都比较熟悉,这篇文章会基于ThreadLocal的应用以及实现原理做一个全面的分析 内容导航 什么是ThreadLocal ThreadLocal的使用 分析Thr ...
- ThreadLocal和ThreadLocalMap源码分析
目录 ThreadLocal和ThreadLocalMap源码分析 背景分析 定义 例子 源码分析 ThreadLocalMap源码分析 ThreadLocal源码分析 执行流程总结 源码分析总结 T ...
- 多线程之美2一ThreadLocal源代码分析
目录结构 1.应用场景及作用 2.结构关系 2.1.三者关系类图 2.2.ThreadLocalMap结构图 2.3. 内存引用关系 2.4.存在内存泄漏原因 3.源码分析 3.1.重要代码片段 3. ...
随机推荐
- python对oracle数据库的操作
1 Oracle数据库 1.1 Oracle环境配置&客户端连接 1.1.1 下载安装Oracle绿色版客户端instantclient: 到o ...
- mosquitto 参数配置
mosquitto 参数配置 1.retry_interval 当QoS为1或2的消息已经被发送后,mosquitto在一段时间内仍未接收到客户端的反馈消息,将重新发送消息. 默认为20秒 2.sy ...
- django初体验 学习笔记
django环境搭建 1.安装Python 2.ipython sudo apt-get install ipython sudo pip instal ...
- php_admin_value open_basedir 引起的上传文件失败解决方法
为了安全,我们通常会在虚拟主机设置中,加入这一行php_admin_value open_basedir "/usr/local/apache/htdocs/www"但这会导致mo ...
- Qt——添加动作及对话框
1. 添加动作 教程:https://www.devbean.net/2012/08/qt-study-road-2-action/ 运行教程中的第一个程序,报错如下: 原因:没有将main.cpp改 ...
- echarts - 树图实现四个层级
我相信很多人和我一样,制作echats图标时,都会先去demo官网找相同的或者近似的效果,然后再此基础上改进成我们想要的那个. 但是近期混迹某微信群时,我看到一个群友抛出问题说,echarts画树状图 ...
- 九度OJ小结
1. 高精度问题 可参考题目 题目1137:浮点数加法 http://ac.jobdu.com/problem.php?pid=1137 对于高精度问题可以考虑使用结构体.上述为浮点数加法,因此该 ...
- sencha touch 在线实战培训 第一期 第六节
2014.1.11晚上8点开的课 本来计划8号晚上开课的,不过那天晚上小区电路出了问题,所以没有讲成.后面两天我又有点其他的事情,所以放到了11号来讲. 本期培训一共八节,前三堂免费,后面的课程需要付 ...
- App.config使用ASP.NET Web Project的Transformation
1.创建对应configuration的App.config文件,比如:App.Debug.config.App.Release.config. 2.编辑项目文件,将App.*.config文件的Bu ...
- CListCtrl使用(转)
CListCtrl使用技巧 以下未经说明,listctrl默认view 风格为report 1. CListCtrl 风格 LVS_ICON: 为每个item显示大图标 LVS_SMALLI ...