ทำความเข้าใจกับหัวข้อ Looper
java เธรดหน่วยการเรียกใช้งานซึ่งออกแบบมาเพื่อทำงานในวิธีการ run () & สิ้นสุดหลังจากนั้น:
แต่ใน Android มีกรณีการใช้งานมากมายที่เราต้องทำให้ Thread ยังมีชีวิตอยู่และรอการป้อนข้อมูล / เหตุการณ์ของผู้ใช้เช่น หัวข้อ UI Main Thread
aka
เธรดหลักใน Android เป็นเธรด Java ที่เริ่มต้นโดย JVM เมื่อเปิดตัวแอพและยังคงทำงานต่อไปจนกว่าผู้ใช้เลือกที่จะปิดหรือพบข้อยกเว้นที่ไม่สามารถจัดการได้
เมื่อเปิดใช้งานแอปพลิเคชันระบบจะสร้างเธรดของการดำเนินการสำหรับแอปพลิเคชันที่เรียกว่า "main" เธรดนี้มีความสำคัญมากเนื่องจากเป็นหน้าที่ของการจัดส่งเหตุการณ์ไปยังวิดเจ็ตส่วนต่อประสานผู้ใช้ที่เหมาะสมรวมถึงกิจกรรมการวาด
ตอนนี้ชี้ให้เห็นที่นี่คือแม้ว่าเธรดหลักคือเธรด Java แต่ก็ยังคงฟังเหตุการณ์ของผู้ใช้และวาด 60 เฟรมต่อวินาทีเฟรมบนหน้าจอและยังคงไม่ตายหลังจากแต่ละรอบ มันเป็นอย่างไร
คำตอบคือ Looper Class : Looper เป็นคลาสที่ใช้เพื่อให้เธรดมีชีวิตอยู่และจัดการคิวข้อความเพื่อดำเนินงานในเธรดนั้น
เธรดโดยค่าเริ่มต้นไม่มีการวนรอบข้อความที่เกี่ยวข้องกับพวกเขา แต่คุณสามารถกำหนดหนึ่งโดยการเรียก Looper.prepare () ในวิธีการเรียกใช้แล้วเรียก Looper.loop ()
วัตถุประสงค์ของ Looper คือการทำให้เธรดมีชีวิตอยู่และรอรอบถัดไปของMessage
วัตถุอินพุตเพื่อทำการคำนวณซึ่งมิฉะนั้นจะถูกทำลายหลังจากรอบแรกของการดำเนินการ
หากคุณต้องการขุดลึกลงไปถึงวิธี Looper จัดการMessage
วัตถุคิวแล้วคุณสามารถดูรหัสที่มาของLooperclass
:
https://github.com/aosp-mirror/platform_frameworks_base/blob/master/core/java/android/os/Looper.java
ด้านล่างเป็นตัวอย่างของวิธีการสร้างLooper Thread
และสื่อสารกับActivity
คลาสโดยใช้LocalBroadcast
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 หรือบริการ Intent แทนได้หรือไม่?
งาน Async ถูกออกแบบมาเพื่อดำเนินการสั้น ๆ ในพื้นหลังและให้โปรแกรมและผลลัพธ์บนเธรด UI งาน Async มีข้อ จำกัด เช่นคุณไม่สามารถสร้างมากกว่า128 งาน AsyncและThreadPoolExecutor
จะช่วยให้เพียงไม่เกิน 5 งาน
IntentServices
นอกจากนี้ยังได้รับการออกแบบที่จะทำงานพื้นหลังสำหรับระยะเวลาเล็ก ๆ น้อย ๆ อีกต่อไปและคุณสามารถใช้ในการสื่อสารกับLocalBroadcast
Activity
แต่บริการจะถูกทำลายหลังจากการปฏิบัติภารกิจ while(true){...}
หากคุณต้องการให้มันทำงานเป็นเวลานานกว่าที่คุณต้องทำเช่น hecks
กรณีการใช้งานที่มีความหมายอื่น ๆ สำหรับ Looper Thread:
ใช้สำหรับการสื่อสารซ็อกเก็ต 2 ทางที่เซิร์ฟเวอร์คอยรับฟังไคลเอ็นต์ซ็อกเก็ตและรับทราบการตอบกลับ
การประมวลผลบิตแมปในพื้นหลัง ส่ง URL รูปภาพไปยังเธรด Looper และจะใช้เอฟเฟ็กต์ฟิลเตอร์และเก็บไว้ในตำแหน่งเทมพีโรรี่แล้วจึงถ่ายทอดเส้นทางชั่วคราวของรูปภาพ