我是安卓系统的新手。我想知道Looper类做什么,以及如何使用它。我已经阅读了Android Looper类文档,但我无法完全理解它。 我在很多地方见过它,但无法理解它的目的。谁能帮我定义一下Looper的目的,如果可能的话,也给我一个简单的例子?


当前回答

Android Looper是一个包装器,用于将messagqueuue附加到线程,并管理队列处理。它在Android文档中看起来非常神秘,很多时候我们可能会面临与Looper相关的UI访问问题。如果我们不了解基础知识,就很难处理。

这是一篇文章,解释了Looper的生命周期,如何使用它,以及在Handler中使用Looper

循环器=线程+消息队列

其他回答

Looper允许在单个线程上按顺序执行任务。handler定义了我们需要执行的任务。这是我在这个例子中试图说明的一个典型场景:

class SampleLooper extends Thread {
@Override
public void run() {
  try {
    // preparing a looper on current thread     
    // the current thread is being detected implicitly
    Looper.prepare();

    // now, the handler will automatically bind to the
    // Looper that is attached to the current thread
    // You don't need to specify the Looper explicitly
    handler = new Handler();

    // After the following line the thread will start
    // running the message loop and will not normally
    // exit the loop unless a problem happens or you
    // quit() the looper (see below)
    Looper.loop();
  } catch (Throwable t) {
    Log.e(TAG, "halted due to an error", t);
  } 
}
}

现在我们可以在一些其他线程(比如ui线程)中使用处理程序将任务发布到Looper上执行。

handler.post(new Runnable()
{
public void run() {
//This will be executed on thread using Looper.
    }
});

在UI线程上,我们有一个隐式的循环器,允许我们处理UI线程上的消息。

什么是环形使者?

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();
      }
  }

理解循环线程

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传递给循环线程,它将应用过滤器效果,并将其存储在临时位置,然后广播图像的临时路径。

Android Looper是一个包装器,用于将messagqueuue附加到线程,并管理队列处理。它在Android文档中看起来非常神秘,很多时候我们可能会面临与Looper相关的UI访问问题。如果我们不了解基础知识,就很难处理。

这是一篇文章,解释了Looper的生命周期,如何使用它,以及在Handler中使用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:在线程中吐司