如果在Android中判断某个线程是否是主线程?对于这个问题,你可能说根据线程的名字,当然这个可以解决问题,但是这样是最可靠的么?万一某天Google一下子将线程的名字改称其他神马东西呢。
方法揭晓
下面的方法是最可靠的解决方案。
public static boolean isInMainThread() { return Looper.myLooper() == Looper.getMainLooper(); }
实际上,写到这里就基本解决了文章标题的问题了,但是仅仅研究到这里太肤浅了,刨的不够深,所以需要继续,希望你也可以继续读下去。
刨根问底
实验一
好,现在,我们对这个稳定的方法做一些测试,首先,下面的方法会增加一些调试打印信息。
private boolean isInMainThread() { Looper myLooper = Looper.myLooper(); Looper mainLooper = Looper.getMainLooper(); Log.i(LOGTAG, "isInMainThread myLooper=" + myLooper + ";mainLooper=" + mainLooper); return myLooper == mainLooper; }
Log.i(LOGTAG, "testInMainThread inMainThread=" + isInMainThread());
OK,我们看一下输出日志。验证OK。
I/TestInMainThread(32028): isInMainThread myLooper=Looper{40d35ef8};mainLooper=Looper{40d35ef8} I/TestInMainThread(32028): testInMainThread inMainThread=true
实验二
现在我们继续在一个没有消息循环的非主线程,进行验证。
new Thread() { @Override public void run() { Log.i(LOGTAG, "testIn NOT in MainThread isMainThread=" + isInMainThread()); super.run(); } }.start();
I/TestInMainThread(32028): isInMainThread myLooper=null;mainLooper=Looper{40d35ef8} I/TestInMainThread(32028): testIn NOT in MainThread isMainThread=false
实验三
继续,我们创建一个绑定了消息循环的线程,根据Android开发者文档说明,以下是一个典型的创建消息循环线程的示例,使用单独prepare()方法和loop()方法来创建一个绑定到Looper的Handler。
new Thread() { private Handler mHandler; @Override public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; Log.i(LOGTAG, "testInNonMainLooperThread isMainThread=" + isInMainThread()); Looper.loop(); } }.start();
OK,现在再次检查以下日志,
I/TestInMainThread(32028): isInMainThread myLooper=Looper{40d72c58};mainLooper=Looper{40d35ef8} I/TestInMainThread(32028): testInNonMainLooperThread isMainThread=false
两个Looper都被初始化赋值了,但是他们是不同的对象。
原理发掘
但是,这是为什么呢,这里面有什么奥秘呢? 好,让我们看以下Looper.class
// sThreadLocal.get() will return null unless you've called prepare(). static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); private static Looper sMainLooper; // guarded by Looper.class/** * 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(); } }
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)); }
/** * 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() { return sThreadLocal.get(); }
/** Returns the application's main looper, which lives in the main thread of the application. */ public static Looper getMainLooper() { synchronized (Looper.class) { return sMainLooper; } }
对于主线程来说,prepareMainLooper这个方法会被Android运行环境调用,而不是程序显式调用。通过这个方法,主线程的looper被创建,并且将对象引用传递给sMainLooper。所以保证了主线程myLooper()获取到的引用和getMainLooper()获取到的都是同一个引用。
对于没有消息循环的非主线程,默认的当前线程的looper是null,因为你从来没有手动地调用prepare(),所以它和主线程的looper不一样。
对于绑定了消息循环的非主线程,当调用Looper.prepare方法时,主线程的Looper已经由Android运行环境创建,当调用prepare方法后,绑定到这个非主线程的looper被创建,当然,这不可能和主线程的Looper一样。
综上所述,这个方法是可靠的。
如何检查当前线程是否是Linux上的主线程?看起来gettid()只返回一个pid,但linux似乎并不保证main()的线程总是具有一个常量和统一的pid。 这样做的原因是,我正在进行自动并行化,并且我希望确保pthread_create()不会在已经运行在pthread_create()创建的线程上的函数中调用。
问题内容: 之前已针对Android,ObjectiveC和C++解决了此问题,但显然不适用于Python。如何可靠地确定当前线程是否为主线程?我可以想到一些方法,但没有一种方法能让我真正满意,因为考虑到与存在的方法相比,它可能是如此简单。 主线程是这样实例化的: 所以一个人可以做 但是这个名字是固定的吗?我见过的其他代码检查了线程名称中是否包含任何代码。 存储启动线程 我可以在程序启动时即在没有
所以一个人可以做 但这个名字固定了吗?我看到的其他代码检查了是否包含在线程名称的任何地方。 我可以在程序启动时存储对起始线程的引用,也就是在没有其他线程的时候。这是绝对可靠的,但对于这样一个简单的查询来说太麻烦了? 有没有更简洁的方法?
我需要检查运行某段代码的线程是否是主(UI)线程。我怎样才能做到这一点呢?
问题内容: 如今,哪个XMPP库将是Android开发的最佳选择? 我一直在使用修补过的Smack库,如本文其他许多问题所建议的那样。但是,那是两年前Smack API的补丁版本。尽管总体上效果不错,但我正在探索其他任何最新的选择。 我一直在研究官方的Smack API,经过一些研究,现在看来它可能还不错(尽管我还没有在实际的应用程序中尝试过它)。 我遇到的另一个解决方案是Beem的aSMACK库
我有一个方法,它将检查RecolyerView中的最后一个元素是否被用户完全可见,到目前为止,我有这段代码,问题是如何检查RecolyerView是否到达了它的底部? PS我有项目分隔符