Android 服务(Service)
一、服務(wù)的解釋
服務(wù)(Service)是Android中實(shí)現(xiàn)后臺(tái)運(yùn)行的解決方案,它適合那些去執(zhí)行不需要和用戶交互而且還要求長(zhǎng)期運(yùn)行的任務(wù)。服務(wù)的運(yùn)行不依賴任何的與任何用戶界面,即使程序被切換到后臺(tái),或者用戶打開(kāi)了另外一個(gè)應(yīng)用程序,服務(wù)仍然能夠保持正常運(yùn)行。
注意:服務(wù)并不是運(yùn)行在一個(gè)獨(dú)立的進(jìn)程當(dāng)中,而是依賴于創(chuàng)建服務(wù)時(shí)所在的應(yīng)用程序進(jìn)程。當(dāng)某個(gè)應(yīng)用程序被殺死時(shí),所有依賴于該進(jìn)程的服務(wù)也會(huì)停止運(yùn)行。
服務(wù)并不會(huì)自動(dòng)開(kāi)啟線程,所有的代碼都是默認(rèn)運(yùn)行在主線程中的。我們?cè)诜?wù)的內(nèi)部手動(dòng)創(chuàng)建了子線程,并在這里執(zhí)行具體的任務(wù),否則就有可能出現(xiàn)主線程被阻塞住的情況。
二、Android多線程編程
1、線程的基本用法
這部分與Java相同,線程創(chuàng)建的兩種方式。
2、在子線程中更新UI
與其他許多的GUI庫(kù)一樣,Android的UI也是不安全的。也就是說(shuō),如果想要更新應(yīng)用程序的UI元素,則必須在主線程中進(jìn)行,否則就會(huì)出現(xiàn)異常。
實(shí)踐:新建AndroidThreadTest項(xiàng)目:
一個(gè)按鈕,一個(gè)TextView,顯示出Hello world,目標(biāo)效果:當(dāng)我們點(diǎn)擊按鈕時(shí),會(huì)把Hello world 改變成 Nice to meet you。
我們開(kāi)始寫(xiě)MainActivity.java
package com.zhj.androidthreadtest;import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView;public class MainActivity extends AppCompatActivity {private TextView text;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);text =(TextView)findViewById(R.id.text);Button changeText = (Button)findViewById(R.id.change_text);changeText.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {switch(v.getId()){case R.id.change_text:new Thread(new Runnable() {@Overridepublic void run() {text.setText("Nice to meet you");}}).start();break;default:break;}}});} }邏輯非常簡(jiǎn)單。我們?cè)?按鈕的點(diǎn)擊事件中開(kāi)啟了一個(gè)子線程,然后在子線程中調(diào)用TextView的setText()方法將顯示的字符串改成Nice to meet you。我們運(yùn)行之后,點(diǎn)擊按鈕按鈕發(fā)現(xiàn)程序崩潰了。
查看logcat日志:可以看出由于在子線程中更新UI造成的。
由此證實(shí),An'd'roid確實(shí)不允許在子線程中進(jìn)行UI操作的。但是有些時(shí)候我們必須在子線程中去執(zhí)行一些耗時(shí)任務(wù),然后根據(jù)任務(wù)的執(zhí)行結(jié)果來(lái)更新相應(yīng)的UI控件。
對(duì)于這種情況,Android 提供了一套異步消息處理機(jī)制,完美解決了在子線程中進(jìn)行UI操作的問(wèn)題。我們先來(lái)了解一下異步消息處理的使用方法,
修改MainActivity的代碼:
package com.zhj.androidthreadtest;import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView;public class MainActivity extends AppCompatActivity {public static final int UPDATE_TEXT = 1; //表示更新TextView這個(gè)動(dòng)作private TextView text;private Handler handler = new Handler(){//新增Handler對(duì)象,并重寫(xiě)handleMessage()方法,對(duì)具體的Message進(jìn)行處理,public void handleMessage(Message msg){//如果發(fā)現(xiàn)Message的what字段的值等于UPDATA_TEXT,就將TextView顯示的內(nèi)容改成Nice to meet youswitch (msg.what){case UPDATE_TEXT ://在這里進(jìn)行UI操作text.setText("Nice to meet you");break;default:break;}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);text =(TextView)findViewById(R.id.text);Button changeText = (Button)findViewById(R.id.change_text);changeText.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {switch(v.getId()){case R.id.change_text:new Thread(new Runnable() {@Overridepublic void run() {Message message = new Message();//創(chuàng)建一個(gè)Message(android.os.Message)對(duì)象,并將他的what字段設(shè)置為UPDATE_TEXTmessage.what = UPDATE_TEXT;handler.sendMessage(message);//將Message對(duì)象發(fā)送出去}}).start();break;default:break;}}});} }來(lái)觀察按鈕的點(diǎn)擊事件中的代碼,我們并沒(méi)有在子線程里直接進(jìn)行UI操作,而是創(chuàng)建了一個(gè)Message(android.os.Message)對(duì)象,并將它的what字段指定為UPDATE_TEXT,然后調(diào)用Handler的sendMessage()方法將這條Message發(fā)送出去。Handler會(huì)收到這條Message,并在handlerMessage()方法中對(duì)它進(jìn)行處理,注意此時(shí)的handlerMessage()方法中的代碼就是在主線程中運(yùn)行的了,所以我們放心在這里進(jìn)行UI操作。
運(yùn)行之后,我們會(huì)發(fā)現(xiàn)內(nèi)容被替換成Nice to meet you 。
3、解析異步消息處理機(jī)制
Android中的異步消息處理主要分為4個(gè)部分:Message、Handler、MessageQueue和Looper。
? ? (1)Message:Message是在線程之間傳遞的消息,它可以在內(nèi)部攜帶少量的信息,用于在不同線程之間交換數(shù)據(jù),可以使用Message的what字段,還可以使用arg1和arg2字段來(lái)攜帶一些整型數(shù)據(jù),使用obj字段攜帶一個(gè)Object對(duì)象。
? ? (2)Handler:處理者的意思,主要用于發(fā)送和處理消息的,發(fā)送消息一般是使用Handler的sendMessage()方法,而發(fā)出的消息經(jīng)過(guò)一系列的輾轉(zhuǎn)處理后,最終會(huì)傳遞到Handler的handleMessage()方法中。
????(3)MessageQueue:消息隊(duì)列,主要用于存放所有通過(guò)Handler發(fā)送的消息。這部分消息會(huì)一直存放在消息隊(duì)列中,等待被處理。每個(gè)線程中只有一個(gè)MessageQueue對(duì)象。
? ? (4)Looper:每個(gè)線程中的MessageQueue的管家,調(diào)用Looper的loop()方法后,就會(huì)進(jìn)入到一個(gè)無(wú)限循環(huán)當(dāng)中,然后每當(dāng)發(fā)現(xiàn)MessageQueue中存在一條消息,就會(huì)將它取出,并傳遞到Handler的handlerMessage()方法中。每個(gè)線程中也只有要給Looper對(duì)象。
我們把異步消息處理的整個(gè)流程再梳理一遍。首先需要在主線程中創(chuàng)建一個(gè)Handler對(duì)象,并重寫(xiě)handlerMessage()方法,這個(gè)方法里寫(xiě)你的邏輯。當(dāng)主線程中需要進(jìn)行UI操作時(shí),就創(chuàng)建一個(gè)Message對(duì)象,并通過(guò)Handler把這條消息發(fā)送出去。之后這條消息會(huì)被添加到MessageQueue的隊(duì)列中等待被處理,而Looper則會(huì)一直嘗試從MessageQueue中取出待處理消息,最后分發(fā)回Handler的handlerMessage()方法中。由于Handler是在主線程中創(chuàng)建的,所以此時(shí)handlerMessage()方法中的代碼也會(huì)在主線程中運(yùn)行,于是我們?cè)谶@里可以進(jìn)行UI操作了。
一條Message經(jīng)過(guò)這樣一個(gè)流程的輾轉(zhuǎn)調(diào)用后,也就從子線程進(jìn)入到了主線程,從不能更新UI變成了更新UI,整個(gè)異步消息處理的核心思想就是如下。
4、使用AsyncTask
總結(jié)
以上是生活随笔為你收集整理的Android 服务(Service)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: mybatis学习(23):分页1 多参
- 下一篇: Android网络小说阅读器的实现