我是安卓系统的新手。我想知道Looper类做什么,以及如何使用它。我已经阅读了Android Looper类文档,但我无法完全理解它。 我在很多地方见过它,但无法理解它的目的。谁能帮我定义一下Looper的目的,如果可能的话,也给我一个简单的例子?
当前回答
什么是环形使者?
从文档
电影
循环程序类,用于为线程运行消息循环。默认情况下,线程没有与之关联的消息循环;要创建一个循环,在要运行循环的线程中调用prepare(),然后调用loop()让它处理消息,直到循环停止。
A Looper is a message handling loop: An important character of Looper is that it's associated with the thread within which the Looper is created The Looper class maintains a MessageQueue, which contains a list messages. An important character of Looper is that it's associated with the thread within which the Looper is created. The Looper is named so because it implements the loop – takes the next task, executes it, then takes the next one and so on. The Handler is called a handler because someone could not invent a better name Android Looper is a Java class within the Android user interface that together with the Handler class to process UI events such as button clicks, screen redraws and orientation switches.
它是如何工作的?
创造电影
线程通过在运行后调用loop .prepare()来获得Looper和MessageQueue。loop .prepare()标识调用线程,创建一个Looper和MessageQueue对象并关联线程
示例代码
class MyLooperThread extends Thread {
public Handler mHandler;
public void run() {
// preparing a looper on current thread
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
// this will run in non-ui/background thread
}
};
Looper.loop();
}
}
欲了解更多信息,请查看下面的帖子
在Android中,Looper, Handler和MessageQueue之间是什么关系? Android内脏:环形器和处理程序的介绍 理解Android核心:Looper, Handler和HandlerThread Android中的Handler 什么是Android Looper? Android: Looper, Handler, HandlerThread。我一部分。 Android中的MessageQueue和Looper
其他回答
java线程的生命周期在run()方法完成后结束。同一线程不能再次启动。
Looper将普通线程转换为消息循环。Looper的主要方法有:
void prepare ()
将当前线程初始化为循环程序。这使您有机会创建处理程序,然后在实际开始循环之前引用此循环程序。请确保在调用此方法后调用loop(),并通过调用quit()结束它。
void loop ()
在此线程中运行消息队列。确保调用quit()来结束循环。
void quit()
退出循环器。 导致loop()方法终止,而不处理消息队列中的任何其他消息。
Janishar的这篇mindorks文章很好地解释了核心概念。
循环程序与线程相关联。如果你在UI线程上需要Looper, loop . getmainlooper()将返回相关的线程。
您需要将Looper与Handler相关联。
Looper, Handler和HandlerThread是Android解决异步编程问题的方法。
有了Handler之后,就可以调用下面的api了。
post (Runnable r)
导致Runnable r被添加到消息队列。可运行对象将在附加此处理程序的线程上运行。
boolean sendMessage (Message msg)
在当前时间之前的所有挂起消息之后,将消息压入消息队列的末尾。它将在附加到此处理程序的线程中的handleMessage(Message)中接收。
HandlerThread是一个方便的类,用于启动具有循环程序的新线程。循环程序可以用来创建处理程序类
在某些情况下,你不能在UI线程上运行可运行任务。 例如,网络操作:在套接字上发送消息,打开URL并通过读取InputStream获取内容
在这些情况下,HandlerThread很有用。你可以从HandlerThread获取Looper对象,并在HandlerThread上创建Handler而不是主线程。
HandlerThread代码是这样的:
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
参考下面的示例代码:
Android:在线程中吐司
理解循环线程
java线程是一个执行单元,它被设计为在run()方法中执行任务,并在此之后终止:
但在Android中,有许多用例,我们需要保持线程活跃,并等待用户输入/事件等。UI线程又名主线程。
Android中的主线程是一个Java线程,它在应用程序启动时首先由JVM启动,并一直运行,直到用户选择关闭它或遇到未处理的异常。
当应用程序启动时,系统创建一个线程 应用程序的执行,称为“main”。这个帖子非常 重要是因为它负责将事件调度到 适当的用户界面小部件,包括绘图事件。
现在需要注意的是,虽然主线程是Java线程,但它一直在监听用户事件,并在屏幕上绘制60帧/秒的帧,并且在每个周期后仍然不会死亡。这是怎么回事?
答案是Looper类:Looper是一个用于保持线程活动并管理消息队列以在其上执行任务的类 该线程。
默认情况下,线程没有关联的消息循环,但你可以通过在run方法中调用loop .prepare()来分配一个消息循环,然后调用loop .loop()。
循环器的目的是保持一个线程活着,并等待下一个周期 input消息对象来执行计算,否则将得到 在第一个循环执行后销毁。
如果你想深入挖掘Looperclass如何管理Message对象队列,那么你可以看看Looperclass的源代码:
https://github.com/aosp-mirror/platform_frameworks_base/blob/master/core/java/android/os/Looper.java
下面是如何创建一个循环线程并使用LocalBroadcast与Activity类通信的示例
class LooperThread : Thread() {
// sendMessage success result on UI
private fun sendServerResult(result: String) {
val resultIntent = Intent(ServerService.ACTION)
resultIntent.putExtra(ServerService.RESULT_CODE, Activity.RESULT_OK)
resultIntent.putExtra(ServerService.RESULT_VALUE, result)
LocalBroadcastManager.getInstance(AppController.getAppController()).sendBroadcast(resultIntent)
}
override fun run() {
val looperIsNotPreparedInCurrentThread = Looper.myLooper() == null
// Prepare Looper if not already prepared
if (looperIsNotPreparedInCurrentThread) {
Looper.prepare()
}
// Create a handler to handle messaged from Activity
handler = Handler(Handler.Callback { message ->
// Messages sent to Looper thread will be visible here
Log.e(TAG, "Received Message" + message.data.toString())
//message from Activity
val result = message.data.getString(MainActivity.BUNDLE_KEY)
// Send Result Back to activity
sendServerResult(result)
true
})
// Keep on looping till new messages arrive
if (looperIsNotPreparedInCurrentThread) {
Looper.loop()
}
}
//Create and send a new message to looper
fun sendMessage(messageToSend: String) {
//Create and post a new message to handler
handler!!.sendMessage(createMessage(messageToSend))
}
// Bundle Data in message object
private fun createMessage(messageToSend: String): Message {
val message = Message()
val bundle = Bundle()
bundle.putString(MainActivity.BUNDLE_KEY, messageToSend)
message.data = bundle
return message
}
companion object {
var handler: Handler? = null // in Android Handler should be static or leaks might occur
private val TAG = javaClass.simpleName
}
}
用法:
class MainActivity : AppCompatActivity() {
private var looperThread: LooperThread? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// start looper thread
startLooperThread()
// Send messages to Looper Thread
sendMessage.setOnClickListener {
// send random messages to looper thread
val messageToSend = "" + Math.random()
// post message
looperThread!!.sendMessage(messageToSend)
}
}
override fun onResume() {
super.onResume()
//Register to Server Service callback
val filterServer = IntentFilter(ServerService.ACTION)
LocalBroadcastManager.getInstance(this).registerReceiver(serverReceiver, filterServer)
}
override fun onPause() {
super.onPause()
//Stop Server service callbacks
LocalBroadcastManager.getInstance(this).unregisterReceiver(serverReceiver)
}
// Define the callback for what to do when data is received
private val serverReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val resultCode = intent.getIntExtra(ServerService.RESULT_CODE, Activity.RESULT_CANCELED)
if (resultCode == Activity.RESULT_OK) {
val resultValue = intent.getStringExtra(ServerService.RESULT_VALUE)
Log.e(MainActivity.TAG, "Server result : $resultValue")
serverOutput.text =
(serverOutput.text.toString()
+ "\n"
+ "Received : " + resultValue)
serverScrollView.post( { serverScrollView.fullScroll(View.FOCUS_DOWN) })
}
}
}
private fun startLooperThread() {
// create and start a new LooperThread
looperThread = LooperThread()
looperThread!!.name = "Main Looper Thread"
looperThread!!.start()
}
companion object {
val BUNDLE_KEY = "handlerMsgBundle"
private val TAG = javaClass.simpleName
}
}
我们可以使用异步任务或意图服务代替吗?
Async tasks are designed to perform a short operation in background and give progres & results on UI thread. Async tasks have limits like you cant create more than 128 Async tasks and ThreadPoolExecutor will allow only upto 5 Async tasks. IntentServices are also designed to do background task for a little longer duration and you can use LocalBroadcast to communicate with Activity. But services get destroyed after task execution. If you want to keep it running for a long time than you need to do hecks like while(true){...}.
Looper Thread的其他有意义的用例:
用于双向套接字通信,服务器继续监听客户端套接字并写回确认 位图处理在后台。将图像url传递给循环线程,它将应用过滤器效果,并将其存储在临时位置,然后广播图像的临时路径。
您可以在GUI框架的上下文中更好地理解什么是Looper。《环形使者》有两项任务。
Looper将一个正常的线程转换为持续运行的线程,直到Android应用程序运行为止。 Looper提供了一个队列,要完成的作业将在其中排队。
正如你所知道的,当一个应用程序启动时,系统为应用程序创建了一个执行线程,称为“主线程”,而Android应用程序通常完全运行在一个线程上,默认情况下是“主线程”。但是主线程并不是一个秘密的、特殊的主线程。它只是一个普通的线程,类似于你可以用new thread()创建的线程,这意味着它在run()方法返回时终止!想想下面的例子。
public class HelloRunnable implements Runnable {
public void run() {
System.out.println("Hello from a thread!");
}
public static void main(String args[]) {
(new Thread(new HelloRunnable())).start();
}
}
Now, let's apply this simple principle to Android apps. What would happen if an Android app runs on a normal thread? A thread called "main" or "UI" or whatever starts your application and draws all UI. So the first screen is displayed to users. What now? The main thread terminates? No, it shouldn’t. It should wait until users do something, right? But how can we achieve this behavior? Well, we can try with Object.wait() or Thread.sleep(). For example, main thread finishes its initial job to display first screen, and sleeps. It awakes, which means interrupted, when a new job to do is fetched. So far so good, but at this moment we need a queue-like data structure to hold multiple jobs. Think about a case when a user touches screen serially, and a task takes longer time to finish. So, we need to have a data structure to hold jobs to be done in first-in-first-out manner. Also, you may imagine, implementing ever-running-and-process-job-when-arrived thread using interrupt is not easy, and leads to complex and often unmaintainable code. We'd rather create a new mechanism for such purpose, and that is what Looper is all about. The official document of Looper class says, "Threads by default do not have a message loop associated with them", and Looper is a class "used to run a message loop for a thread". Now you can understand what it means.
为了使事情更清楚,让我们检查转换主线程的代码。这一切都发生在ActivityThread类中。在它的main()方法中,您可以找到下面的代码,它将普通线程转换为我们需要的线程。
public final class ActivityThread {
...
public static void main(String[] args) {
...
Looper.prepareMainLooper();
Looper.loop();
...
}
}
和loop .loop()方法无限循环,每次出队列并处理一个消息:
public static void loop() {
...
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
msg.target.dispatchMessage(msg);
...
}
}
So, basically, Looper is a class that is made to address a problem that occurs in the GUI framework. But this kind of need can also happen in other situations as well. Actually, it is a pretty famous pattern for multi-thread applications, and you can learn more about it in "Concurrent Programming in Java" by Doug Lea(Especially, chapter 4.1.4 "Worker Threads" would be helpful). Also, you can imagine this kind of mechanism is not unique in Android framework, but all GUI framework may need somewhat similar. You can find almost same mechanism in Java Swing framework too.
什么是环形使者?
从文档
电影
循环程序类,用于为线程运行消息循环。默认情况下,线程没有与之关联的消息循环;要创建一个循环,在要运行循环的线程中调用prepare(),然后调用loop()让它处理消息,直到循环停止。
A Looper is a message handling loop: An important character of Looper is that it's associated with the thread within which the Looper is created The Looper class maintains a MessageQueue, which contains a list messages. An important character of Looper is that it's associated with the thread within which the Looper is created. The Looper is named so because it implements the loop – takes the next task, executes it, then takes the next one and so on. The Handler is called a handler because someone could not invent a better name Android Looper is a Java class within the Android user interface that together with the Handler class to process UI events such as button clicks, screen redraws and orientation switches.
它是如何工作的?
创造电影
线程通过在运行后调用loop .prepare()来获得Looper和MessageQueue。loop .prepare()标识调用线程,创建一个Looper和MessageQueue对象并关联线程
示例代码
class MyLooperThread extends Thread {
public Handler mHandler;
public void run() {
// preparing a looper on current thread
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
// this will run in non-ui/background thread
}
};
Looper.loop();
}
}
欲了解更多信息,请查看下面的帖子
在Android中,Looper, Handler和MessageQueue之间是什么关系? Android内脏:环形器和处理程序的介绍 理解Android核心:Looper, Handler和HandlerThread Android中的Handler 什么是Android Looper? Android: Looper, Handler, HandlerThread。我一部分。 Android中的MessageQueue和Looper
什么是环形使者?
Looper是一个用于执行队列中的消息(可运行对象)的类。普通线程没有这样的队列,例如简单线程没有任何队列。它执行一次,方法执行完成后,线程将不再运行另一个Message(Runnable)。
我们可以在哪里使用Looper类?
如果有人想要执行多个消息(Runnables),那么他应该使用负责在线程中创建队列的Looper类。 例如,在编写从internet下载文件的应用程序时,我们可以使用Looper类将要下载的文件放入队列中。
它是如何工作的?
有prepare()方法来准备Looper。然后,您可以使用loop()方法在当前线程中创建一个消息循环,现在您的Looper已经准备好在队列中执行请求,直到退出循环。
下面是您可以准备Looper的代码。
class LooperThread extends Thread {
public Handler mHandler;
@Override
public void run() {
Looper.prepare();
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
推荐文章
- 警告:API ' variable . getjavacompile()'已过时,已被' variable . getjavacompileprovider()'取代
- 安装APK时出现错误
- 碎片中的onCreateOptionsMenu
- TextView粗体通过XML文件?
- 如何使线性布局的孩子之间的空间?
- 自动化invokerrequired代码模式
- DSL元素android.dataBinding。enabled'已过时,已被'android.buildFeatures.dataBinding'取代
- ConstraintLayout:以编程方式更改约束
- PANIC: AVD系统路径损坏。检查ANDROID_SDK_ROOT值
- 如何生成字符串类型的buildConfigField
- Recyclerview不调用onCreateViewHolder
- Android API 21工具栏填充
- Android L中不支持操作栏导航模式
- c#线程安全快速(est)计数器
- 如何将此foreach代码转换为Parallel.ForEach?