当前位置:网站首页>Learning Android 8 from scratch -- threads and services
Learning Android 8 from scratch -- threads and services
2022-04-23 00:13:00 【Scattered moon】
Catalog
Service
Service yes Android In the background of the implementation of the program running solutions , It's ideal for performing tasks that don't need to interact with users and require long-term running .
Service Not running in a separate process , It depends on creating Service when The application process in which you are working . When an application process is killed , All that depends on the process Service Will also stop shipping That's ok .
Android Multithreaded programming
Basic usage of threads
Using inheritance is a bit coupling , We will choose to use more implementations Runnable Interface One thread
class MyThread : Runnable {
override fun run() {
// Write specific logic
}
}
How to start a thread
val myThread = MyThread()
Thread(myThread).start()
If you don't want to define another class specifically to implement Runnable Interface , You can also use Lambda The way , This kind of writing is more common
Thread {
// Write specific logic
}.start()
How to turn on threads ( recommend )
Kotlin It also provides us with a simpler way to start threads
there thread It's a Kotlin Built in top-level functions , All we need to do is Lambda Write specific logic in expressions That's all right. , even start() Methods don't have to call ,thread The function helps us all deal with it internally .
thread {
// Write specific logic
}
Update... In child threads UI
Android It's true that it's not allowed in a child thread UI Operation of the . But sometimes , We have to perform some time-consuming tasks in sub threads , Then update the corresponding UI Control , In this case ,Android Provides a set of asynchronous message processing mechanism , It perfectly solves the problem of running in a sub thread UI Operational issues .Android Basic usage of asynchronous message processing , Using this mechanism, you can solve the problem of updating in sub threads excellently UI The problem of .
val updateText = 1
val handler = object : Handler(Looper.getMaininLooper()) {
override fun handleMessage(msg: Message) {
// It can be done here UI operation
when (msg.what) {
updateText -> textView.text = "Nice to meet you"
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
changeTextBtn.setOnClickListener {
thread {
val msg = Message()
msg.what = updateText
handler.sendMessage(msg) // take Message Object sent out
}
}
}
Parsing asynchronous message processing mechanism
Android Asynchronous message processing in mainly consists of 4 Component composition :Message、Handler、MessageQueue and Looper.
- Message
Message It's a message passing between threads , It can carry a small amount of information inside , Used to switch between different threads To transfer data . In the last section we used Message Of what Field , Besides, you can also use arg1 and arg2 Fields to carry some integer data , Use obj Field carries one Object object . - Handler
Handler As the name implies, it means the processor , It's mainly Used to send and process messages Of . Send message general It's using Handler Of sendMessage() Method 、post() Such method , And the message sent out goes through a series of rolling After transfer , It will eventually reach Handler Of handleMessage() In the method . - MessageQueue
MessageQueue What message queuing means , It is mainly used to store all passing through Handler Message sent . This part of the message will always exist in the message queue , Waiting to be dealt with . There will only be one... In each thread MessageQueue object . - Looper
Looper Is in each thread MessageQueue The steward of , call Looper Of loop() After the method , Will enter In an infinite loop , And every time I find out MessageQueue When a message exists in , Will take it out , And deliver it to Handler Of handleMessage() In the method . There will only be one... In each thread Looper object .
The whole process of asynchronous message processing :
First you need to create a... In the main thread Handler object , And rewrite handleMessage() Method . And then when it needs to be done in the child thread UI In operation , Just create one Message object , and adopt Handler Send this message . After that, the message will be added to MessageQueue Waiting in the queue to be Handle , and Looper Will always try to MessageQueue Remove pending messages from , Last minute Handler Of handleMessage() In the method . because Handler In the constructor of, we passed Looper.getMainLooper(), So at this time handleMessage() Method will also run in the main thread , So we can do it safely here UI Operation .
AsyncTask( recommend )
So let's look at this first AsyncTask The basic usage of . because AsyncTask Is an abstract class , So if we want to use it , You have to create a subclass to inherit it . We can inherit for AsyncTask Class specified 3 Generic parameters , this 3 Parameters are used as follows .
Params. In execution AsyncTask The parameter passed in is required when , Can be used in background tasks .
Progress. During background task execution , If you need to display the current progress on the interface , Then use the pan... Specified here Type as progress unit .
Result. When the task is finished , If you need to return the result , Then use the generics specified here as the return value type .
Need to rewrite AsyncTask In order to complete the task customization . The methods that often need to be rewritten are as follows 4 individual .
- onPreExecute() This method is called before the background task starts executing , It is used to initialize some interfaces , For example, display a progress bar dialog box .
- doInBackground(Params…)
All the code in this method will run in the child thread , We should be here to deal with all the time-consuming tasks . ren Once the work is done , You can go through return Statement returns the execution result of the task , If AsyncTask The third pan The type parameter specifies Unit, You don't need to return the task execution result . Be careful , It can't be done in this method UI Operation of the , Update if necessary UI Elements , For example, feedback on the progress of the current task , You can call publishProgress (Progress…) Method to accomplish . - onProgressUpdate(Progress…)
When called in the background task publishProgress(Progress…) After the method , onProgressUpdate (Progress…) Method will be called soon , The parameters carried in this method are Passed in the background task . In this method, you can UI To operate , The value of... Can be used Update the interface elements accordingly . - onPostExecute(Result)
When the background task is completed and passed return When the statement returns , This method will be called soon . The number of returns Data is passed to this method as a parameter , The returned data can be used for some UI operation , For example, remind the task executor The result of that , And close the progress bar dialog box .
Simply speaking , Use AsyncTask The trick is ,
stay doInBackground() Method to perform specific time-consuming tasks ,
stay onProgressUpdate() Method UI operation ,
stay onPostExecute() Method to complete some tasks .
class DownloadTask : AsyncTask<Unit, Int, Boolean>() {
override fun onPreExecute() {
progressDialog.show() // Show progress dialog
}
override fun doInBackground(vararg params: Unit?) = try {
while (true) {
val downloadPercent = doDownload() // It's a fictional way
publishProgress(downloadPercent)
if (downloadPercent >= 100) {
break
}
}
true
} catch (e: Exception) {
false
}
override fun onProgressUpdate(vararg values: Int?) {
// Update download progress here
progressDialog.setMessage("Downloaded ${
values[0]}%")
}
override fun onPostExecute(result: Boolean) {
progressDialog.dismiss()// Close the progress dialog // Here is the download result
if (result) {
Toast.makeText(context, "Download succeeded", Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(context, " Download failed", Toast.LENGTH_SHORT).show()
}
}
}
Start this task
DownloadTask().execute()
You can give execute() Method to pass in any number of parameters , These parameters will be passed to DownloadTask Of doInBackground() Among the methods . Just call publishProgress() Method , You can easily switch from a child thread to UI Thread .
Service The basic usage of
backstage Service
onBind() The method is Service The only abstract method in , So it must be implemented in subclasses .
Rewrote onCreate()、onStartCommand() and onDestroy() this 3 Individual Law , They are every Service Most commonly used in 3 There's a way . among onCreate() Methods in Service Created Time call ,onStartCommand() The method will be used every time Service Called at startup ,onDestroy() Method Will be in Service Call when destroying .
Usually , If we want to Service Once started, immediately perform an action , You can write logic in onStartCommand() In the method . And when Service At the time of destruction , We should be in onDestroy() Recover... From the method Resources that are no longer used .
class MyService : Service() {
override fun onBind(intent: Intent): IBinder {
TODO("Return the communication channel to the service.")
}
override fun onCreate() {
super.onCreate()
Log.d("MyService", "onCreate executed")
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
super.onDestroy()
Log.d("MyService", "onDestroy executed")
}
}
Now only when the application remains visible in the foreground ,Service To ensure stable operation , Once applied After entering the backstage ,Service It may be recycled by the system at any time .
Activity and Service communicate
At present, we hope to MyService A download function is provided in , And then in Activity You can decide when to start download , And check the download progress at any time . The idea of realizing this function is to create a special Binder Object to manage the download function .
class MyService : Service() {
private val mBinder = DownloadBinder()
class DownloadBinder : Binder() {
fun startDownload() {
Log.d("MyService", "startDownload executed")
}
fun getProgress(): Int {
Log.d("MyService", "getProgress executed")
return 0
}
}
override fun onBind(intent: Intent): IBinder {
return mBinder
}
}
When one Activity and Service After binding , You can call the Service Inside Binder Provided The method .
class MainActivity : AppCompatActivity() {
lateinit var downloadBinder: MyService.DownloadBinder
private val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
downloadBinder = service as MyService.DownloadBinder
downloadBinder.startDownload()
downloadBinder.getProgress()
}
override fun onServiceDisconnected(name: ComponentName) {
}
}
override fun onCreate(savedInstanceState: Bundle?) {
bindServiceBtn.setOnClickListener {
val intent = Intent(this, MyService::class.java)
bindService(intent, connection, Context.BIND_AUTO_CREATE) // binding Service
}
unbindServiceBtn.setOnClickListener {
unbindService(connection) // Unbundling Service
}
}
}
Service Life cycle of
Although every call startService() Method ,onStartCommand() I'll do it once , But actually every one Service Will only exist An instance . So no matter how many times you call startService() Method , Just call... Once stopService() or stopSelf() Method ,Service Will stop .
The front desk Service
override fun onCreate() {
super.onCreate()
Log.d("MyService", "onCreate executed")
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as
NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel("my_service", " The front desk Service notice ", NotificationManager.IMPORTANCE_DEFAULT)
manager.createNotificationChannel(channel)
}
val intent = Intent(this, MainActivity::class.java)
val pi = PendingIntent.getActivity(this, 0, intent, 0)
val notification = NotificationCompat.Builder(this, "my_service")
.setContentTitle("This is content title")
.setContentText("This is content text")
.setSmallIcon(R.drawable.small_icon)
.setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.large_icon))
.setContentIntent(pi)
.build()
startForeground(1, notification)
}
Use the front desk Service Must be in AndroidManifest.xml The right to proceed in the document Only a declaration of limitations
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
Use IntentService( recommend )
Service The code in is run in the main thread by default Of , If you are directly in Service Deal with some time-consuming logic in , It's easy to show up ANR(Application Not Responding) The situation of .
So we need to use Android Multithreading technology , We should Service Each specific method of Start a child thread in the , Then deal with the time-consuming logic here .
class MyService : Service() {
...
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
thread {
// Handling specific logic
}
return super.onStartCommand(intent, flags, startId)
}
}
Example
class MyIntentService : IntentService("MyIntentService") {
override fun onHandleIntent(intent: Intent?) {
// Print the... Of the current thread id
Log.d("MyIntentService", "Thread id is ${
Thread.currentThread().name}")
}
override fun onDestroy() {
super.onDestroy()
Log.d("MyIntentService", "onDestroy executed")
}
}
Log.d("MainActivity", "Thread id is ${
Thread.currentThread().name}")
val intent = Intent(this, MyIntentService::class.java)
startService(intent)
版权声明
本文为[Scattered moon]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204230012371064.html
边栏推荐
猜你喜欢
随机推荐
Vibrato tiktok
Li Kou exercise set 3 -- the longest substring without repeated characters
倍福Scaling factor因子计算
倍福两台CX控制器之间添加路由
算法--两数相加 II(Kotlin)
Niuke bm41 Right view of output binary tree
Scheme of making target detection training samples
Compared with the traditional anchor based method, fcos is unique
(转)通过RDP隧道绕过网络限制
(转)Aspose.words编程指南之DOM树结构初识,Node类继承关系及说明
基于.NetCore开发博客项目 StarBlog - (3) 模型设计
力扣习题集2--两数相加
Algorithm -- adding two numbers II (kotlin)
L1-066 cat is liquid (5 points)
Concurrent reachability analysis (three color marking method)
(轉)使用dotTrace6.0進行性能,內存分析
(转)Aspose.words编程指南之DocumentBuilder二
倍福TwinCAT两台CX控制器之间做ADS通信
For the pictures in the specified directory, take the picture name (excluding the extension of the picture), separate the file path from the picture name, and separate the file name from the picture e
node+mongoose分页效果









