1四、四大組件--Service

1、Service

1.一、Service簡介

Service是一種長生命週期的組件,是一個沒有界面的Activity,它是Activity的叔叔。
java

·Service長期在後臺運行,用來訪問網絡、播放音樂、操做文件或與內容提供者交互等無關界面的操做。android

·Service和Thread相似,可是Thread不安全也不嚴謹。程序員

·Service是運行在主線程中,所以不能用來作耗時的操做。api

1.二、Android進程

進程優先級由高到低的順序:
緩存

·前臺進程(Foreground progress)安全

·可視進程(Visible process),能夠看見,可是不能夠交互。網絡

·服務進程(Service process)異步

·後臺進程(Background process)ide

·空進程(Empty process)當程序退出時,進程沒有被銷燬,而是變成了空進程函數

1.三、進程回收

Android系統有一套內存回收機制,會根據優先級進行回收。Android系統會盡量的維持程序的進程, 可是終究仍是須要回收一些舊的進程節省內存提供給新的或者重要的進程使用。
· 進程的回收順序是:從低到高
· 當系統內存不夠用時, 會把空進程一個一個回收掉
· 當系統回收全部的完空進程不夠用時, 繼續向上回收後臺進程, 依次類推
· 可是當回收服務, 可視, 前臺這三種進程時, 系統非必要狀況下不會輕易回收, 若是須要回收掉這三種進程, 那麼在系統內存夠用時, 會再給從新啓動進程;可是服務進程若是

   用戶手動的關閉服務, 這時服務不會再重啓了

1.四、生命週期

標準方式開啓服務,服務會執行onCreate方法,若是服務已經被建立,就不會再去執行onCreate方法。屢次的開啓服務會執行onStartCommand()方法,它替代了過期的onStart()方法。

中止服務,服務會執行ondestry()方法。

1.標準模式

Intent intent = new Intent(MainActivity.this,PhoneServer.class);
startService(intent);

Activity經過標準模式開啓的服務長期在後臺運行,不能夠調用服務裏的方法。

oncreate() -->onstartCommand()--->onstartCommand()--->onDestory();

2.綁定模式

Intent intent = new Intent(MainActivity.this, PhoneService.class);
/**
 * service:intent
 * conn 服務的通信頻道
 * 服務若是在綁定的時候不存在,會自動建立
 * */
bindService(intent, new MyConn(), BIND_AUTO_CREATE);

Activity經過綁定模式開啓的服務能夠調用服務的方法,可是不能長期運行在後臺。

onCreate()-->onbind()-->onUnbind()-->ondestroy();

·若是obind方法返回值是null,onServerConnected方法不會被調用。

·綁定的服務在系統設置界面,正在運行條目是看不到的。

·綁定的服務和Activity不求同時生,但求同時死。

·解除綁定服務後,服務會當即中止,且服務只能夠被解除綁定一次,屢次解除綁定代碼會拋出異常。

3.混合模式

Activity經過混合模式開啓服務便可以長期在後臺運行,也能夠調用服務中的方法。

·首先經過標準模式啓動服務,這樣服務就長期在後臺運行。

·若是須要調用服務中的方法,則再使用綁定模式綁定服務。

·若是須要解綁服務則調用unbindService()解綁服務。

·若是須要中止服務,則調用stopService()中止服務。

注:有時候咱們解綁服務後,發現仍是能夠調用服務中的方法,是由於垃圾回收器尚未回收調用該方法的對象。

1.五、Service通訊

由上面能夠知道,Activity只有綁定模式開啓服務才能調用服務中的方法,別忘記解綁服務:

image

咱們須要在服務中建立一個類,繼承iBinder的子類Binder,來充當咱們的代理類

861de8f3-1cda-4fe6-a3ab-2250a5bf5385

除此以外,還可使用接口解耦,建立一個接口充當代理類的父類,讓定義的代理類實現該接口中的方法再調用服務中的方法,而後在onBind中返回代理類,

在MainActivity中的再進行強制類型轉換,和以上實現方法同樣。

1.六、遠程服務

aidl()Android Interface definition language),它是一種android內部進程通訊接口的描述語言,經過它咱們能夠定義進程間的通訊接口

IPC(interprocess communication)內部進程通訊,知足兩個進程之間接口數據的交換。

1.使用方法

a) .java的接口文件後綴修改爲.aidl文件,並刪除piblic訪問修飾符。

b) 在工程目錄gen目錄下會自動編譯成Iservice.java的接口文件。

c) 遠程服務代碼

private class MyBinder extends IService.Stub

d) 本地服務代碼

IService = IService.Stub.asInterface(setvice)

e)IService.callMethodInService()

這裏很少講述,在後面的IPC機制講解時進行詳細說明。

1.七、IntentService

一、簡介

IntentService是繼承於Service並處理異步請求的一個類,在IntentService內有一個工做線程來處理耗時操做,啓動IntentService的方式和啓動傳統Service同樣

,同時,當任務執行完後,

IntentService會自動中止,另外,能夠啓動IntentService屢次,而每個耗時操做會以工做隊列的方式在IntentService的onHandleIntent回調方法中執行,

而且,每次只會執行一個工做線程,

執行完第一個再執行第二個,以此類推。並且,全部請求都在一個單線程中,不會阻塞應用程序的主線程(UI Thread),同一時間只處理一個請求。

二、使用

服務是運行在主線程的,咱們不能在服務中作耗時操做,而IntentService卻恰好是用來解決該問題的,固然在服務中作耗時操做有兩種,

第一種直接開啓線程,第二種則是用IntentService。

@Override
protected void onHandleIntent(Intent intent) {
    // Intent是從Actvity發過來的,攜帶識別參數,根據參數不一樣執行不一樣人物
    String action = intent.getExtras().getString("param");
    if(action.equals("oper1")){
        System.out.println("Operation1");
    }else if (action.equals("oper2")) {
        System.out.println("Operation2");
    }
    SystemClock.sleep(2000);
}

onHandleIntent方法就是專門用來處理耗時操做的。

1.八、Android中的反射

1.反射掛斷電話


a)找到上下文的mBase引用的類,ContextImpl,經過查看getSystemService源碼能夠知道,全部的系統服務都在一個map集合中。

4d4f2bd4-9b7d-4a43-b78b-80a0583ca3eb

b)接下來去查找map集合SYSTEM_SERVERCE_MAP,發現它實際上是一個hashMap,這裏須要詳細解說:

441c513c-ef82-43a0-b6c7-e4ee4afff24d

爲何谷歌須要包裝上下文?假設在沒有上下文的狀況下,想要調一個服務,首先要綁定該服務,若是成功綁定會返回IBinder,拿到IBinder後還須要將它轉化成爲接口類型,

才能去調用它的函數,因此谷歌在設計的時候將經常使用的上下文都包裝好了,這樣對程序員開發更加的方便,快捷。

因爲某些服務被認爲不安全或侵犯用戶隱私,因此谷歌在包裝系統服務的時候,將某些服務進行了隱藏(@hide),好比掛斷電話。

咱們須要先拿到ServiceManager對象, 可是谷歌不但願咱們使用該對象,因此將該對象進行隱藏,因此參考下面的反射。

a2c921cb-93a6-4e83-98ce-5e9b1a7908f5

c) 經過當前的service類的字節碼來獲取ServiceManager的字節碼文件

eabe8ccf-de53-4c5d-bf32-d8a45fc9bad9

d) 下一步則是將iBinder轉成接口類型,須要兩個aidl文件,其中一個是依賴另一個存在的,注意保證包名一致

0738121f-c73d-466d-9330-dc848e854314

e) 這時系統會在gen目錄的com.android.internal.telephony包下自動生成一個ITelephony.java的接口文件

67b05a46-9c30-49c0-8012-c1c591e31932

f) 繼續代碼實現反射掛斷電話的操做,這時會出現不少高級的api能夠供咱們使用了

// IBinder iBinder = ServiceManager.getService(TELEPHONY_SERVICE)
try {
    Class clazz = CallSmsSafeService.class.getClassLoader().loadClass("android.os.ServiceManager");
    Method method = clazz.getDeclaredMethod("getService", String.class);
    IBinder iBinder = (IBinder) method.invoke(null, TELEPHONY_SERVICE);
    ITelephony iTelephony = ITelephony.Stub.asInterface(iBinder);
    iTelephony.endCall();
} catch (Exception e) {
    e.printStackTrace();
}

g)要掛斷電話還須要添加撥打電話的權限

<uses-permission android:name="android.permission.CALL_PHONE"/>

2.反射清除緩存

a)得到兩個aidl文件,一個是依賴另一個存在的

f9016bc9-4869-4015-b535-602743cbd6e0

b)這個時候,系統會自動生成一個接口文件,而後咱們就可使用它了

22b232fa-e850-421a-9267-52100eeee4ee

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        PackageManager manager = getPackageManager();
        Method[] methods = PackageManager.class.getDeclaredMethods();
        for (Method method : methods) {
            if ("getPackageSizeInfo".equals(method.getName())) {
                try {
                    method.invoke(manager, getPackageName(),new MyPackageStatsObserver());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    private class MyPackageStatsObserver extends IPackageStatsObserver.Stub {
        @Override
        public void onGetStatsCompleted(PackageStats pStats, boolean succeeded) throws RemoteException{
            long cacheSize = pStats.cacheSize; // 緩存大小
            long codeSize = pStats.codeSize;// 代碼大小
            long dataSize = pStats.dataSize;// 數據大小
        }
    }
}

d)記得添加權限

<uses-permission android:name="android.permission.GET_PACKAGE_SIZE"/>
相關文章
相關標籤/搜索