Android 實(shí)現(xiàn) IPC 的幾種方式:Messenger、匿名共享內(nèi)存使用

Android跨進(jìn)程(跨APP)調(diào)度有多種方式,四大組件都是支持跨進(jìn)程角度。

IPC方式

Activity

我們可以通過(guò)startActivity打開(kāi)其他進(jìn)程的頁(yè)面,并且?guī)弦恍﹨?shù),數(shù)據(jù)大小限制在1MB(1020KB)

BroadcastReceiver

廣播不僅可以在APP內(nèi)部實(shí)現(xiàn)通信,也可以實(shí)現(xiàn)跨跨進(jìn)程調(diào)度,系統(tǒng)提供了很多基于廣播的接口,比如實(shí)現(xiàn)電話監(jiān)聽(tīng)、WIFI狀態(tài)等。

Service

可以通過(guò)Service和AIDL實(shí)現(xiàn)IPC,這種方式是APP內(nèi)部跨進(jìn)程最常用的方式。

ContentProvider

ContentProvider 也是很常見(jiàn)的IPC方式,比如系統(tǒng)提供的手機(jī)通訊錄就是基于ContentProvider實(shí)現(xiàn)的。ContentProvider是基于數(shù)據(jù)庫(kù)增刪改查的思路來(lái)提供服務(wù)的。

Socket

通過(guò)四大組件可以實(shí)現(xiàn)IPC,另辟途徑,我們還可以利用網(wǎng)絡(luò)的特性,使用Socket實(shí)現(xiàn)IPC。

數(shù)據(jù)傳輸方式

通常實(shí)現(xiàn)IPC主要的功能就是消息傳遞和數(shù)據(jù)傳輸,實(shí)現(xiàn)數(shù)據(jù)傳輸?shù)姆绞揭彩怯卸喾N。

Bundle

Activity、Service、Receiver都支持Intent中傳遞Bundle數(shù)據(jù),由于Bundle實(shí)現(xiàn)了Parcelable接口,所以它可以方便的在不同的進(jìn)程間傳輸,可以傳遞基本類型、基本類型數(shù)組、序列化對(duì)象,但是大小是有限的,不能傳遞過(guò)大的文件,比如大圖片。

如果要傳遞Bitmap,記得要對(duì)圖片進(jìn)行壓縮,并且不要傳PNG圖片。

文件共享

也可以通過(guò)把數(shù)據(jù)寫(xiě)入文件中,比如SharedPreferences,然后通知其他進(jìn)程讀取數(shù)據(jù),這種方式可以實(shí)現(xiàn)任意圖片大小的傳遞,非常適合APP內(nèi)部的多進(jìn)程調(diào)度,如果是跨APP調(diào)度就要考慮到sdcard的存儲(chǔ)權(quán)限問(wèn)題了,所以這種方式的適用性不廣。

Messenger

messenger來(lái)實(shí)現(xiàn)跨app通信也就是在兩個(gè)不同的app中實(shí)現(xiàn)雙向通信。其實(shí)Messenger底層也是使用aidl的方式來(lái)實(shí)現(xiàn)的,只不過(guò)其使用handler來(lái)處理消息。
教程

class MessengerService : Service() {
    class MessengerHandler : Handler() {
        override fun handleMessage(msg: Message?) {
            // 來(lái)自客戶端的消息
            if (msg != null) {
                Log.i("MessengerService", msg.data.getString("msg"))
            }
        }
    }
    private val messenger = Messenger(MessengerHandler())
    override fun onBind(intent: Intent?): IBinder? {
        return messenger.binder
    }
}

在AndroidManifest.xml添加注冊(cè)

<application>
    <service android:name=".MessengerService" android:process=":messenger"/>
</application>

在Activity實(shí)現(xiàn)綁定服務(wù)

class MainActivity : AppCompatActivity() {
    private val conn = object : ServiceConnection {
        override fun onServiceDisconnected(name: ComponentName?) {
        }

        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            val messenger = Messenger(service)
            // 發(fā)送消息
            val message = Message()
            message.data = Bundle()
            message.data.putString("msg", "Wiki")
            messenger.send(message)
        }
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        bindService(Intent(this, MessengerService::class.java), conn, Context.BIND_AUTO_CREATE)
    }
}

AIDL+匿名共享內(nèi)存(Ashmem)

如果我們需要通過(guò)IPC實(shí)現(xiàn)大文件傳遞,除了可以通過(guò)寫(xiě)入文件讀取文件的方式實(shí)現(xiàn),也可以同匿名內(nèi)存的方式,這種方式可以實(shí)現(xiàn)不同的App之間傳遞大文件內(nèi)容。
創(chuàng)建一個(gè)IMemoryAidlInterface.aidl文件,然后make Project 就會(huì)生成一個(gè)IMemoryAidlInterface.java文件

// IMemoryAidlInterface.aidl
package com.taoweiji.camerax.androidipcexample;
import android.os.ParcelFileDescriptor;

interface IMemoryAidlInterface {
    ParcelFileDescriptor getParcelFileDescriptor();
}

創(chuàng)建服務(wù)

class MemoryFetchService : Service() {
    override fun onBind(intent: Intent?): IBinder? {
       return MemoryFetchStub()
    }

    class MemoryFetchStub : IMemoryAidlInterface.Stub() {
        override fun getParcelFileDescriptor(): ParcelFileDescriptor {
            val data = "這里匿名共享內(nèi)存".toByteArray()
            val memoryFile = MemoryFile("test", data.size)
            memoryFile.outputStream.write(data)
            val method = memoryFile.javaClass.getDeclaredMethod("getFileDescriptor")
            val fileDescriptor = method.invoke(memoryFile) as FileDescriptor
            return ParcelFileDescriptor.dup(fileDescriptor)
        }
    }
}

Activity 通過(guò)AIDL讀取MemoryFetchService寫(xiě)入匿名共享內(nèi)存的信息

class MemoryExampleActivity : AppCompatActivity() {
    private val conn = object : ServiceConnection {
        override fun onServiceDisconnected(name: ComponentName?) {
        }
        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            val memoryAidlInterface = IMemoryAidlInterface.Stub.asInterface(service)
            val fileDescriptor = memoryAidlInterface!!.parcelFileDescriptor.fileDescriptor
            val fis = FileInputStream(fileDescriptor)
            Log.i("匿名共享內(nèi)存信息", String(fis.readBytes()))
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        bindService(Intent(this, MemoryFetchService::class.java), conn, Context.BIND_AUTO_CREATE)
    }
}

如果需要不不同的App之間使用AIDL,必須要復(fù)制生成后的.java文件到Activity所在的App,包名也要保持一致。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容