㈠ 如何在兩個app之間傳遞參數
有時候需要從一個APP中啟動另外一個APP,比如Twitter/微信等。 如果你不知道那個APP的Activity,但是知道包名(package name),那麼可以使用如下的方法: Intent LaunchIntent = getPackageManager().getLaunchIntentForPackage("com.package.address"); startActivity(LaunchIntent); 如果APP之間有合作關系,可以獲得合作APP的清單文件(manifest),那麼可以從該文件中獲知package/activity, 可使用如下的方法來啟動該APP特定活動界面: Intent intent = new Intent(Intent.ACTION_MAIN); intent.setComponent(new ComponentName("com.package.address","com.package.address.MainActivity")); startActivity(intent); 如果要在啟動APP時傳遞參數,可以在意圖(Intent)中設置: intent.putExtra("firstKeyName","FirstKeyValue"); intent.putExtra("secondKeyName","SecondKeyValue");
㈡ 如何在兩個程序之間傳遞消息
一般來說在常用的操作系統中有以下幾種方式實現進程間通信
管道法(即把一個程序的輸入和另一個程序的輸出對接起來,實現方式根據自己使用編程語言的不同各異)
信號法,(利用操櫻肆作系統自帶的信號操作,讓一個程序給戚頌梁另一個發信號高運....但是信號的種類有限,所以很少用
共享資料庫,安裝資料庫軟體,兩個程序能訪問同一個資料庫,在資料庫里放消息
共享網路埠,(可以理解成一個進程使用一個網路埠,另一個想跟他通信的時候就直接去訪問這個埠
㈢ android跨進程通信
本文整理和引用他人的筆記,旨在個人復習使用。
參考鏈接:
https://blog.csdn.net/fanleiym/article/details/83894399
https://github.com/274942954/AndroidCollection/blob/master/Docs/Android%E7%9F%A5%E8%AF%86%E7%82%B9%E6%B1%87%E6%80%BB.md#%E8%BF%9B%E7%A8%8B%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F
https://www.kaelli.com/4.html
https://carsonho.blog.csdn.net/article/details/73560642?utm_medium=distribute.pc_relevant.none-task-blog--1.e_weight&depth_1-utm_source=distribute.pc_relevant.none-task-blog--1.e_weight
默認情況下,一個app只會運行在一個進程中,進程名為app的包名。
1. 分散內存的佔用
Android系統對每個應用進程的內存佔用是有限制的,佔用內存越大的進程,被系統殺死的可能性就越大。使用多進程可以減少主進程佔用的內存,避免OOM問題,降低被系統殺死的概率。
2. 實現多模塊
一個成熟的應用一定是多模塊化的。項目解耦,模塊化,意味著開辟新的進程,有獨立的JVM,帶來數據解耦。模塊之間互不幹預,團隊並行開發,同時責任分工也很明確。
3. 降低程序奔潰率
子進程崩潰不會影響主進程的運行,能降低程序的崩潰率。
4. 實現一些特殊功能
比如可以實現推送進程,使得主進程退出後,能離線完成消息推送服務。還可以實現守護進程,來喚醒主進程達到保活目的。還可以實現監控進程專門負責上報bug,進而提升用戶體驗。
android:process 屬性的值以冒號開頭的就是 私有進程 ,否則就是 公有進程 。當然命名還需要符合規范,不能以數字開頭等等。
1. 前台進程
2. 可見進程
3. 服務進程
4. 後台進程
5. 空進程
Android 會將進程評定為它可能達到的最高級別。另外服務於另一進程的進程其級別永遠不會低於其所服務的進程。
創建新的進程時會創建新的Application對象,而我們通常在Application的onCreate方法中只是完成一些全局的初始化操作,不需要多次執行。
解決思路:獲取當前進程名,判斷是否為主進程,只有主進程的時候才執行初始化操作
獲取當前進程名的兩種方法:
Application中判斷是否是主進程(方法1例子):
Serializable 和 Parcelable是數據序列化的兩種方式,Android中只有進行序列化過後的對象才能通過intent和Binder傳遞。
通常序列化後的對象完成傳輸後,通過反序列化獲得的是一個新對象,而不是原來的對象。
Serializable是java介面,位於java.io的路徑下。Serializable的原理就是把Java對象序列化為二進制文件後進行傳遞。Serializable使用起來非常簡單,只需直接實現該介面就可以了。
Parcelable是Google為了解決Serializable效率低下的問題,為Android特意設計的一個介面。Parcelable的原理是將一個對象完全分解,分解成可以傳輸的數據類型(如基本數據類型)再進行傳遞。
通常需要存到本地磁碟的數據就使用Serializable,其他情況就使用效率更高的Parcelable。
IPC 即 Inter-Process Communication (進程間通信)。Android 基於 Linux,而 Linux 出於安全考慮,不同進程間不能之間操作對方的數據,這叫做「進程隔離」。
每個進程的虛擬內存空間(進程空間)又被分為了 用戶空間和內核空間 , 進程只能訪問自身用戶空間,只有操作系統能訪問內核空間。
由於進程只能訪問自身用戶空間,因此在傳統的IPC中,發送進程需要通過_from_user(系統調用)將數據從自身用戶空間拷貝到內核空間,再由接受進程通過_to_user從內核空間復拷貝到自身用戶空間,共需要拷貝2次,效率十分低下。Android採用的是Binder作為IPC的機制,只需復制一次。
Binder翻譯過來是粘合劑,是進程之間的粘合劑。
Binder IPC通信的底層原理是 通過內存映射(mmap),將接收進程的用戶空間映射到內核空間 ,有了這個映射關系,接收進程就能通過用戶空間的地址獲得內核空間的數據,這樣只需發送進程將數據拷貝到內核空間就可完成通訊。
一次完整的Binder IPC通信:
從IPC的角度看,Binder是一種跨進程通信機制(一種模型),Binder 是基於 C/S 架構的,這個通信機制中主要涉及四個角色:Client、Server、ServiceManager和Binder驅動。
Client、Server、ServiceManager都是運行在用戶空間的進程,他們通過系統調用(open、mmap 和 ioctl)來訪問設備文件/dev/binder,從而實現與Binder驅動的交互。Binder驅動提供進程間通信的能力(負責完成一些底層操作,比如開辟數據接受緩存區等),是Client、Server和ServiceManager之間的橋梁。
Client、Server就是需要進行通信兩個的進程,通信流程:
細心的你一定發現了,注冊服務和獲得服務本身就是和ServiceManager進行跨進程通信。其實和ServiceManager的通信的過程也是獲取Binder對象(早已創建在Binder驅動中,攜帶了注冊和查詢服務等介面方法)來使用,所有需要和ServiceManager通信的進程,只需通過0號引用,就可以獲得這個Binder對象了。
AIDL內部原理就是基於Binder的,可以藉此來分析Binder的使用。
AIDL是介面定義語言,簡短的幾句話就能定義好一個復雜的、內部有一定功能的java介面。
先看看ICallBack.aidl文件,這里定義了一個介面,表示了服務端提供的功能。
被定義出來的java介面繼承了IInterface介面,並且內部提供了一個Stub抽象類給服務端(相當於封裝了一下,服務端只需繼承這個類,然後完成功能的裡面具體的實現)。
參考: https://www.cnblogs.com/sqchen/p/10660939.html
(以下是添加了回調的最終實現,可以看參考鏈接一步一步來)
為需要使用的類,創建aidl文件。
系統會自動在main文件下生成aidl文件夾,並在該文件夾下創建相應目錄。
在java相同路徑下創建Student類,這里不能使用@Parcelize註解,否則會報錯
創建IStudentService.aidl,定義了一個介面,該介面定義了服務端提供的功能。創建完後rebuild一下項目 (每次創建和修改定義介面文件都要rebuild一下)
創建在服務端的StudentService
可以看見有回調,說明客戶端也提供了介面給服務端來回調(雙向通信,此時客戶端的變成了服務端),即ICallBack.aidl
客戶端是通過Binder驅動返回的Binder調用StudentService里的具體實現方法
AIDL使用注意:
Messenger可以在不同進程中傳遞 Message 對象,在Message中放入我們需要傳遞的數據,就可以輕松地實現數據的進程間傳遞了。Messenger 是一種輕量級的 IPC 方案,是對AIDL的封裝,底層實現是 AIDL。
使用詳見: https://blog.csdn.net/qq951127336/article/details/90678698
㈣ Android APP調起另外一個APP並傳值
第一種:
第二種:
setClassName內部也是調用的setComponent。
調用方:
被調用方在AndroidManifest的Activity中添加自定義action:
被調用方數據接收:
第一銀敗種:
調用方通過點擊H5網頁上按鈕
這種方法存在著弊端就是沒辦法判斷手機上是否安裝APP時,更適合打開自己APP中Activity。一般建議js與java進行交互調用原生的方法: WebViewJavascriptBridge 使用簡單方便,並且避免了一些js腳本注入漏洞。
第二種:隱式調用
被調用方在AndroidManifest的Activity中添加自定義action:
被調用Activity中數據接收:
注意: 這兩種方式只適合針對某個頁面,都只是在自己應用中跳轉第三方應用,並不是真正的喚醒,比如應用A已經在後台存在了,應用B調用以上兩種方式後,只是在應用B中重新打開了一個應用A,此時的應用A是相當與存在兩個,一前搏基個是在後台單獨存在,一個是依存應用B存在,是添加到應用B的棧中的,當點擊A頁面裡面的跳轉按鈕時才真正調起跳轉到A應慧謹用。
㈤ 如何在兩個app之間傳遞參數
把窗體的某部信息(控制項或屬性)設置為public static即可。。。
在窗體里的InitializeComponent();初始化方法里。。。你可以找到所有已添加的控制項的創建信息。其它在最底部有控制項的聲明信息。。。你只要把private 改成public static即可。。。
不過還有一個問題。改成static靜態成員的話。也相應的要把當前窗體內所有關於該對象的調用的「this.」都刪除掉。因為static不屬於任何對象。他是公用的對象。
而且,調用該對象的時候,可以用他所在的:類名.static對象名.。。。在該static聲明的類中,可以不用類名。static對象名,直接static對象名即可,對象,方法,屬性,都可以這樣用,這是static的特點。
不過調用static對象的對象也得是static才可以。。。相關更具體對static的了解,你可以到網上查看。
如果你現在在Form1里的某個TextBox控制項值改變時,相應的Form2的某個TextBox控制項值也相應變化,可以這樣寫。
Form1:
要把該TextBox1的聲明改成:
public static TextBox TextBox1;
指導到TextBox的TextChanged事件。
添加該事件:
private void TextBox1_TextChanged(object sender,Evetn..... e)
{
Form2.TextBox1.Text=Form2.TextBox1.Text;
}
Form2:
要把該TextBox1的聲明改成:
public static TextBox TextBox1;
再用以上的代碼即可。
㈥ android兩個activity之間傳值
Activity之間是沒有辦法直接傳遞數據的。Android的設計原則是,用Intent在不同的Activity和進程之間進行通信,但是通常來講,Intent中只能存入基本數據類型和系統默認支持的比如Uri之類的。那麼對於用戶自己定義的數據結構是無法直接用Intent來傳送的,如果想要通過Intent來傳遞自定義數據,可以讓數據結構實現Parcelable介面,這樣就可以把數據放入Intent。但是Intent的傳送效率也不是很高,特別是當傳遞一些如Bitmap的大數據,用Intent傳遞超過500K的Bitmap,就會造成Framework層的Java Binder掛掉,結果就是傳遞不成功。
這點可以算成是Android的一個弊端,沒有很好的解決方案。能做到的就是盡量設計的時候注意,盡量讓Activity之間共享基本數據類型。
Android本身的應用中也深受其害,可以看到有很多應用程序的源代碼中的主要的類在三千行以上的不在少數,比如Browser中的BrowserActivity有四千多行;Mms中的ComposeMessageActivity也有四千多行,等等。為什麼一個類會如此之大,就是因為它們是程序的主頁面,是業務的核心邏輯所在,裡面也控制著很多的其他的數據結構,而又無法與另外的Activity共享,所以就只能在一個Activity裡面做所的事情。
㈦ android開發中跨進程通信有幾種方式
Android進程間通信的幾種方式 定義多進程
第一:Android應用中使用多進程只有一個辦法(用NDK的fork來做除外),就是在AndroidManifest.xml中聲明組件時,用android:process屬性來指定。
不知定process屬性,則默認運行在主進程中,主進程名字為包名。
android:process = package:remote,將運行在package:remote進程中,屬於全局進程,其他具有相同shareUID與簽名的APP可以跑在這個進程中。
android:process = :remote ,將運行在默認包名:remote進程中,而且是APP的私有進程,不允許其他APP的組件來訪問。
第二:多進程引發的問題
靜態成員和單例失效:每個進程保持各自的靜態成員和單例,相互獨立。
線程同步機制失效:每個進程有自己的線程鎖。
SharedPreferences可靠性下降:不支持並發寫,會出現臟數據。
Application多次創建:不同進程跑在不同虛擬機,每個虛擬機啟動會創建自己的Application,自定義Application時生命周期會混亂。
綜上,不同進程擁有各自獨立的虛擬機,Application,內存空間,由此引發一系列問題。
第三: 進程間通信
Bundle/Intent傳遞數據:
可傳遞基本類型,String,實現了Serializable或Parcellable介面的數據結構。Serializable是Java的序列化方法,Parcellable是Android的序列化方法,前者代碼量少(僅一句),但I/O開銷較大,一般用於輸出到磁碟或網卡;後者實現代碼多,效率高,一般用戶內存間序列化和反序列化傳輸。
文件共享:
對同一個文件先後寫讀,從而實現傳輸,Linux機制下,可以對文件並發寫,所以要注意同步。順便一提,Windows下不支持並發讀或寫。
Messenger:
Messenger是基於AIDL實現的,服務端(被動方)提供一個Service來處理客戶端(主動方)連接,維護一個Handler來創建Messenger,在onBind時返回Messenger的binder。
雙方用Messenger來發送數據,用Handler來處理數據。Messenger處理數據依靠Handler,所以是串列的,也就是說,Handler接到多個message時,就要排隊依次處理。
AIDL:
AIDL通過定義服務端暴露的介面,以提供給客戶端來調用,AIDL使伺服器可以並行處理,而Messenger封裝了AIDL之後只能串列運行,所以Messenger一般用作消息傳遞。
通過編寫aidl文件來設計想要暴露的介面,編譯後會自動生成響應的java文件,伺服器將介面的具體實現寫在Stub中,用iBinder對象傳遞給客戶端,客戶端bindService的時候,用asInterface的形式將iBinder還原成介面,再調用其中的方法。
ContentProvider:
系統四大組件之一,底層也是Binder實現,主要用來為其他APP提供數據,可以說天生就是為進程通信而生的。自己實現一個ContentProvider需要實現6個方法,其中onCreate是主線程中回調的,其他方法是運行在Binder之中的。自定義的ContentProvider注冊時要提供authorities屬性,應用需要訪問的時候將屬性包裝成Uri.parse("content://authorities")。還可以設置permission,readPermission,writePermission來設置許可權。 ContentProvider有query,delete,insert等方法,看起來貌似是一個資料庫管理類,但其實可以用文件,內存數據等等一切來充當數據源,query返回的是一個Cursor,可以自定義繼承AbstractCursor的類來實現。
Socket:
學過計算機網路的對Socket不陌生,所以不需要詳細講述。只需要注意,Android不允許在主線程中請求網路,而且請求網路必須要注意聲明相應的permission。然後,在伺服器中定義ServerSocket來監聽埠,客戶端使用Socket來請求埠,連通後就可以進行通信。
㈧ 怎樣把數據從一個程序傳給另一個程序
有好幾種基本的方法可以完成這項任務----你可以通過文件或內存來傳遞這些數據。這些方法的步驟都相當簡潔:首先,定義在何處存放數據,如何獲取數據,以及如何通知另一個程序來獲取或設置數據;然後,你就可以獲取或設置數據了,盡管使用文件的技術定義和實現起來都比較簡單,但它的速度往往比較慢(並且容易引起混亂)。因此,這里重點討論內存數據轉移技術。下面將依次詳細地分析這一過程的每一個環節: 定義在何處存放數據。當你編寫要共享數據的兩個程序時,你應該讓程序知道要訪問的數據存放在何處。這個環節同樣有幾種實現方法:你可以在一個(或每個)程序中建立一個固定的內部緩沖區,並在兩個程序之間傳遞指向這個緩沖區的指針;你也可以為數據分配動態內存,並在兩個程序之間傳遞指向該數據的指針;如果要傳遞的數據很小,你還可以通過CPU的通用寄存器來傳遞數據(這種可能性很小,因為x86結構的寄存器很少)。分配動態內存是最靈活和模塊性最強的方法。 定義獲取數據的方法。這個環節非常簡潔——你可以使用fmemcpy()或等價的內存拷貝函數。顯然,在獲取和設置數據時都可以使用這個函數。 定義通知另一個程序的方法。因為DOS並不是一個多任務操作系統,所以其中一個(或兩個)程序的一部分必須已經駐留在內存中,並且可以接受來自另一個程序的調用。同樣,這個環節也有幾種方法可供選擇:第一個程序可以是一個列入CONFIG.SYS中的驅動程序,它在系統啟動時就被裝入內存;第一個程序也可以是一個TSR(終止並駐留)程序,在它退出時會把與第二個程序相互作用的那部分程序駐留在內存中;此外,你也可以在第一個程序中利用system()或spawn()函數(見20.11)來啟動第二個程序。你可以根據需要選擇合適的方法。因為有關DOS驅動程序的數據傳遞在DOS文檔中已經有詳盡的描述,而有關system()和spawn()函數的內容也已經在前文中介紹過,因此下面介紹TSR方法。 下面的例子給出了兩個程序:第一個程序是一個完整的TSR程序,但為了突出整個過程中的關鍵環節,它寫得比較單薄(見20.15中的解釋)。這個TSR程序先是安裝了一個中斷63H的中斷服務程序,然後調用終止並駐留退出函數,在執行這個TSR程序後,執行下文給出的另一個程序。這個程序只是簡單地初始化一個對中斷63H的調用(類似於使用中斷21H調用),並且把「Hello There」傳送給上述TSR程序 # include <stdlib. h> # include <dos. h> # include <string. h> void SetupPointers (void) ; void OutputString(char * ); # define STACKSIZE 4096 unsigned int near OldStackPtr; unsigned int near OldStackSeg; unsigned int _near MyStackOff ; unsigned int _near MyStackSeg; unsigned char_near MyStack[STACKSIZE]; unsigned char far * MyStackPtr= (unsigned char_far * )MyStack; unsigned short AX, BX,CX, DX,ES; / * My interrupt handler * / void_interrupt_far_cdecl NewCommVector ( unsigned short es, unsigned short ds, unsigned short di, unsigned short si, unsigned short bp, unsigned short sp, unsigned short bx, unsigned short dx, unsigned short cx, unsigned short ax, unsigned short ip, unsigned short cs, unsigned short flags) ; / * Pointers to the previous interrupt handier * / void(_interrupt_far_cdecl * CommVector)(); union REGS regs; struet SREGS segregs ; # define COMM_VECTOR 0x63 / * Software interrupt vector * / / * This is where the data gets passed into the TSR * / char_far * eallerBufPtr; char localBuffer[255]; / * Limit of 255 bytes to transfer * / char_far * localBufPtr=(ehar_far * )loealBuffer; unsigned int ProgSize= 276; / * Size of the program in paragraphs * / void main(int argc,char * * argv) { int i, idx; / * Set up all far pointers * / SetupPointers () ; / * Use a cheap hack to see if the TSR is already loaded tf it is, exit,doing nothing * / comm_veetor =_dos_getvect (COMM_VECTOR) ; if(((long)eomm_vector & 0xFFFFL) == ((long) NewCommVector & OxFFFFL ) ) { OutputString("Error :TSR appears to already be loaded. \n"); return ; / * If everything's set,then chain in the TSR * / _dos_setvect (COMM_VECTOR ,NewCommVector) ; / * Say we are loaded * / OutputString("TSR is now loaded at 0x63\n"); / * Terminate, stay resident * / dos_keep (0, ProgSize ) ; } / * Initializes all the pointers the program will use * / void Set upPointers ( ) { int idx ; / * Save segment and offset of MyStackPtr for stack switching * / MyStackSeg = FP_SEG (MyStackPtr) ; MyStackOff = FP_OFF (MyStackPtr) ; / * Initialize my stack to hex 55 so I can see its footprint if I need to do debugging * / for (idx = 0 ;idx<STACKSIZE ; idx ++ ) { MyStack [idx] = 0x55 ; } } void _interrupt_ far_cdecl NewCommVector ( unsigned short es, unsigned short ds, unsigned short di, unsigned short si, unsigned short bp, unsigned short sp, unsigned short bx, unsigned short dx, unsigned short cx, unsigned short ax, unsigned short ip, unsigned short cs, unsigned short flags) { AX = ax; BX = bx ; CX = cx; DX = dx ; ES = es ; / * Switch to our stack so we won't run on somebody else's * / _asm { ;set up a local stack eli ; stop interrupts mov OldStackSeg,ss ; save stack segment mov OldStackPtr,sp ; save stack pointer (offset) mov ax,ds ; replace with my stack s mov ss,ax ; ditto mov ax,MyStackOff ; replace with my stack s add ax,STACKSIZE-2 ;add in my stack size mov sp ,ax ; ditto sti ; OK for interrupts again } switch (AX) { case 0x10; / * print string found in ES:BX */ / * Copy data from other application locally * / FP_ SEG (callerBufPtr) = ES ; FP_OFF (callerBufPtr) = BX ; _fstrcpy (localBufPtr, callerBufPtr ) ; / * print buffer 'CX' number of times * / for(; CX>0; CX--) OutputString (localBufPtr) ; AX=1; /* show success */ break ; case 0x30: /* Unload~ stop processing interrupts * / _dos_setvect (COMM_VECTOR ,comm_vector) ; AX=2; /* show success */ break ; default : OutputString (" Unknown command\r\n" ) ; AX= 0xFFFF; / * unknown command-1 * / break ; } / * Switch back to the caller's stack * / asm { cli ;turn off interrupts mov ss,OldStackSeg ;reset old stack segment mov sp,OldStackPtr ;reset old stack pointer sti ;back on again } ax=AX; /* use return value from switch() */ } / * avoids calling DOS to print characters * / void OutputString(char * str) { int i ; regs. h. ah = 0x0E ; regs. x. bx = 0 ; for(i=strlen(str) ; i>0; i--,str++){ regs. h. al= * str; int86 (0xl0, ®s, ®s) ; } } 上述程序是這兩個程序中的TSR程序。這個程序中有一個NewCommVector()函數,它被安裝在中斷63H(63H通常是一個可用的向量)處作為中斷服務程序。當它被安裝好後,它就可以接收命令了。switch語句用來處理輸入的命令,並作出相應的反應。筆者隨意選擇了0x1O和0x30來代表這樣兩條命令:「從ES:BX處復制數據,並列印到屏幕上,CX中的數值為列印次數」;「脫離中斷63H,並停止接收命令」。下面是第二個程序——向中斷63H發送命令的程序(注意它必須在Large模式下編譯)。 # include <stdlib. h> # include <dos. h> # define COMM VECTOR 0x63 union REGS regs; struct SREGS segregs ; char buffer[80]; char _far * buf=(char_far *)buffer; main (int argc,char * * argv) { intcnt; cnt = (argo= =1 ? 1:atoi(argv[1])) ; strcpy (bur, "Hello There\r\n" ) ; regs. x. ax= 0x10; regs. x. cx=cnt ; regs. x. bx=FP OFF(buf); segregs, es=FP SEG(buf) ; int86x(COMM_VECTOR ,®s, &segregs) ; printf ("TSR returned %d\n" ,regs. x. ax) ; } 你可能會認為這個短小的程序看上去和那些通過調用int 21或int 10來在DOS中設置或檢索信息的程序差不多。如果你真的這么想,那就對了。唯一的區別就是現在你所用的中斷號是63H,而不是21H或10H。上述程序只是簡單地調用前文中的TSR程序,並要求後者把es:bX所指向的字元串列印到屏幕上,然後,它把中斷處理程序(即那個TSR程序)的返回值列印到屏幕上。 當字元串"Hello There」被列印到屏幕上後,在兩個程序之間傳遞數據的全部必要步驟就都完成了。這個例子的真正價值在於它能夠舉一反三。現在你能很輕松地編寫一個這樣的程序,它將發送一條類似於「把要求你列印的最後一個字元串傳遞給我」的命令。你所要做的就是在前述TSR程序的switch語句中加入這條命令,然後再寫一個程序來發送這條命令。此外,你也可以在第二個程序中利用20.11中所介紹的system()或spawn()函數來啟動前述TSR程序。由於TSR程序會檢查自己是否已被裝入,因此你只需裝入一次TSR程序,就可以多次運行第二個程序了。在所有要和前述TSR程序通信的程序中,你都可以使用這里所說的方法。 在建立前述TSR程序時,需要有幾個前提條件。其一就是沒有其它重要的中斷服務程序也在處理中斷63H。例如,筆者原來在程序中使用的是中斷67H,結果該程序能正常裝入並運行,但此後筆者就無法編譯程序了,因為Microsoft用來運行C編譯程序的DOS擴展程序也要使用中斷67H。在筆者發送了命令0x30(讓程序卸載自身)後,編譯程序又能正常運行了,因為DOS擴展程序的中斷處理程序已被該程序恢復了。 第二個前提條件與駐留檢查在關。筆者假設永遠不會有另一個中斷處理程序使用和NewCommVector()相同的近程型地址,盡管這種巧合的可能性極小,但讀者應該知道該程序並不是萬無一失的。在該程序中,筆者特意讓NewCommVector()使用自己的棧,以避免它運行在調用它的程序的棧上,但是,筆者還是假設調用所需的任何函數都是安全的。注意,該程序沒有調用printf(),因為它佔用較多的內存,並且要調用DOS(int 21)來列印字元。在該程序中,當中斷63H發生時,筆者不知道DOS是否可以被調用,因此不能假設可以使用DOS調用。 注意,在該程序中,可以調用那些沒有用到DOS int21服務程序的函數來完成所需的任務,如果必須使用一個DOS服務程序,你可以在中斷63H發生時檢查DOS忙標志,以確定當時DOS是否可以被調用。最後,對dos_keep()作一點說明:該函數要求知道在程序退出時要在內存中保留多少段(每段16位元組)數據。在本例這個TSR程序中,提供給該函數的段數(276)稍大於整個可執行程序的大小。當你的程序變大時,提供給該函數的段數也必須增大,否則就會出現一些異常現象。
希望採納
㈨ Android 進程間通信的幾種實現方式
Android 進程間通信的幾種實現方式
主要有4種方式:
這4種方式正好對應於android系統中4種應用程序組件:Activity、Content Provider、Broadcast和Service。
主要實現原理:
由於應用程序之間不能共享內存。為了在不同應用程序之間交互數據(跨進程通訊),AndroidSDK中提供了4種用於跨進程通訊的方式進行交互數據,實現進程間通信主要是使用sdk中提供的4組組件根據實際開發情況進行實現數據交互。
詳細實現方式:
Acitivity實現方式
Activity的跨進程訪問與進程內訪問略有不同。雖然它們都需要Intent對象,但跨進程訪問並不需要指定Context對象和Activity的 Class對象,而需要指定的是要訪問的Activity所對應的Action(一個字元串)。有些Activity還需要指定一個Uri(通過 Intent構造方法的第2個參數指定)。 在android系統中有很多應用程序提供了可以跨進程訪問的Activity,例如,下面的代碼可以直接調用撥打電話的Activity。
IntentcallIntent=newIntent(Intent.ACTION_CALL,Uri.parse("tel:12345678");
startActivity(callIntent);
Content Provider實現方式
Android應用程序可以使用文件或SqlLite資料庫來存儲數據。Content Provider提供了一種在多個應用程序之間數據共享的方式(跨進程共享數據)
應用程序可以利用Content Provider完成下面的工作
1. 查詢數據
2. 修改數據
3. 添加數據
4. 刪除數據
Broadcast 廣播實現方式
廣播是一種被動跨進程通訊的方式。當某個程序向系統發送廣播時,其他的應用程序只能被動地接收廣播數據。這就象電台進行廣播一樣,聽眾只能被動地收聽,而不能主動與電台進行溝通。在應用程序中發送廣播比較簡單。只需要調用sendBroadcast方法即可。該方法需要一個Intent對象。通過Intent對象可以發送需要廣播的數據。
Service實現方式
常用的使用方式之一:利用AIDL Service實現跨進程通信
這是我個人比較推崇的方式,因為它相比Broadcast而言,雖然實現上稍微麻煩了一點,但是它的優勢就是不會像廣播那樣在手機中的廣播較多時會有明顯的時延,甚至有廣播發送不成功的情況出現。
注意普通的Service並不能實現跨進程操作,實際上普通的Service和它所在的應用處於同一個進程中,而且它也不會專門開一條新的線程,因此如果在普通的Service中實現在耗時的任務,需要新開線程。
要實現跨進程通信,需要藉助AIDL(Android Interface Definition Language)。Android中的跨進程服務其實是採用C/S的架構,因而AIDL的目的就是實現通信介面。
總結
跨進程通訊這個方面service方式的通訊遠遠復雜於其他幾種通訊方式,實際開發中Activity、Content Provider、Broadcast和Service。4種經常用到,學習過程中要對沒種實現方式有一定的了解。
㈩ android 組件間、進程間數據傳輸和限制
1、Bunder 傳遞對象為什麼需要序列化?
1》因為 bundle 傳遞數據時只支持基本數據類型,所以在傳遞對象時需要序列化轉
換成可存儲或可傳輸的本質狀態(位元組流)。序列化後的對象可以在網路、IPC
(比如啟動另一個進程的 Activity、Service 和 Reciver)之間進行傳輸,也可以 存儲到本地。
2》序列化,表示將一個對象轉換成可存儲或可傳輸的狀態。序列化的原因基本三種 情況:
1.永久性保存對象,保存對象的位元組序列到本地文件中; 2.對象在網路中傳遞;
3.對象在 IPC 間傳遞。
2、序列化Serializable 和Parcelable 的區別
Serializable(Java 自帶):
1》Serializable 是序列化的意思,表示將一個對象轉換成存儲或可傳輸的狀態。序列化後的對象可以在網路上進傳輸,也可以存儲到本地。
2》Serializable 會使用反射,序列化和反序列化過蠢臘程需要大量 I/O 操作。
Parcelable(android 專用):
1》除了 Serializable 之外,使用 Parcelable 也可以實現相同的效果,不過不同於將 對象進行序列化,Parcelable 方式的實現原理是將一個完整的對象進行分解,而分解後的每一部分都是 Intent 所支持的數據類型,這也就實現傳遞對象的功能 了。
2》Parcelable 自已實現封送和解封(marshalled &unmarshalled)操作不需要用反 射,數據也存放在 Native 內存中,效率要快很多。
兩者最大的區別在於 存儲媒介的不同,Serializable 使用 I/O 讀寫存儲在硬碟 上,而 Parcelable 是直接 在內存中讀寫。很明顯,內存的讀寫速度通常大於納激 IO 讀寫,所以在 Android 中傳遞數據優先選擇 Parcelable。
3、bundle傳輸的數據是否有限制,是多少,為什麼要限制?
1》Intent 在傳遞數據時是有大小限制的,大約限制在 1MB 之內,你用 Intent 傳遞 數據,實際上走的是跨進程通信(IPC),跨進程通信需要把數據從內核 到進程中,每一個進程有一帶茄滑個接收內核數據的緩沖區,默認是 1M;如果一次傳 遞的數據超過限制,就會出現異常。
2》不同廠商表現不一樣有可能是廠商修改了此限制的大小,也可能同樣的對象在不 同的機器上大小不一樣。
3》傳遞大數據,不應該用 Intent;考慮使用 ContentProvider 或者直接匿名共享內 存。簡單情況下可以考慮分段傳輸。
4、匿名共享內存(https://www.jianshu.com/p/d9bc9c668ba6)