天天看點

Process子程序和主程序間互傳資訊--及遇到的問題解決

最近公司新上了一個自動化測試的項目,需要在我們的App裡面開啟一個程序去調用測試的App,在這工程中,主程序可能随時向子程序發送一些指令,而子程序在測試完成後也要把結果傳回給子程序,因為本人以前對Process相當陌生,是以寫的過程出現各種問題,而且發生網上的一些解決方法對自己也并不适用,是以就寫了這篇文章。
我們先來看一下怎麼啟動一個子程序。
           

其中ProcessField.COMMAND_SU=”su”;//當成功擷取root後可以通路系統檔案的程序

ProcessField.COMMAND_SH=”sh”;//未Root擷取的程序

Process有三個方法,可以擷取到程序裡的流,

BufferedReader successResult = null;
    BufferedReader errorResult = null;
    DataOutputStream os = null;
    os = new DataOutputStream(process.getOutputStream());
    successResult = new BufferedReader(new InputStreamReader(process.getInputStream()));
    errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));
           

這樣就可以擷取到Process裡的輸入流、輸出流、和錯誤流了。

有了這三個流我們就可以和子程序進行資料的發送與接受了。

1、首選往子程序發生資訊:

os.writeBytes(COMMAND_EXIT);
    os.flush();
           
上面這兩句,就可以向子程序發送消息了,當然os可以寫好幾種格式的,都可以。
           

2、子程序接受主程序發送過來的消息:

InputStream is=System.in;
if ((length=is.read(buffer))!=-) {
String string=new String(buffer, , length);
}
           

上面語句就可以接受到主程序發過來的資訊了,不過要記得開啟子線程進行接收,因為is.read()方法是堵塞的,當主程序沒有消息發送時,is.read()便一直堵塞在這裡了。

is還有一個方法是is.available(),當時system.in時,這個方法代表的含義是,判斷is中是否有内容,如果is.available()==0的話證明主程序沒有發送消息,根據這個方法的傳回值我們可以選擇跳過is.read()方法。

3、子程序向主程序發送消息:

隻需要這一句就OK了,就發送給主程序了。

4、主程序接收消息:

String s;
                while ((s = successResult.readLine()) != null) {
                    Log.getInstance().debugFun("ShellUtil", s);
                    successMsg.append(s);
                    successMsg.append("\n");
                }
                while ((s = errorResult.readLine()) != null) {
                    errorMsg.append(s);
                }
           

其中successResult和errorResult輸入流、錯誤流;這兩個流我們在上面已經建立了,主程序就是通過這兩個流來接收子程序發送過來的消息的,包括錯誤資訊。

5、在這因為我們開啟了一個子程序,一般都會有需求,要求主程序等待子程序結束,并收到子程序傳回資訊,這時process提供了下面一個方法:

這個方法就是主程序會一直等待子程序執行完後才會結束,否則主程序一直等待,這個方法傳回是一個int指。

6、可能會遇到的問題,堵塞,就是執行之後發現,process.waitfor()這個方法堵塞了,擁有結束不了,我在網上搜了下大部分都是說因為子程序發送消息太多,而Process的輸入流和緩沖流的接受内容有限,造成堵塞,解決方法是在process.waitFor()方法調用前,開啟一個子線程,來一直讓Process的輸入流和錯誤流讀取消息。

new Thread(new Runnable() {

                @Override
                public void run() {
                  String s;
                while ((s = successResult.readLine()) != null) {
                    Log.getInstance().debugFun("ShellUtil", s);
                    successMsg.append(s);
                    successMsg.append("\n");
                }
                while ((s = errorResult.readLine()) != null) {
                    errorMsg.append(s);
                }
                }).start();
process.waitFor();
           

但是我這子程序發送給主程序的消息并不多,隻是很少的字元串而已,是以這個方法對我根本不管用。

因為這個問題我也是找了半天,在子程序強制把System.in.close()了也不行,強制system.exit()也不行,最後發現問題了。我在主程序這邊主動發Process的輸出流os.close()關了就可以了。

原理是:Process這邊的輸出流os如果不關閉的話,子程序那邊的輸入流就會一直嘗試讀取,這就造成一直堵塞的結果。

好不容易找到這問題了,子程序和主程序也可以互相傳遞消息了,但是一個問題來了,我們的需求是伺服器會不定的發送給主程序一些消息,然後主程序需要發送給子程序,而因為在開啟子程序後,我們調用了:

這個方法,是以一旦子程序開啟了,主程序就會等待,那麼伺服器發送過來的消息,主程序隻要等到子程序結束了才能接受到,這樣就不行了,我就不能實時向子程序發送消息了。後來我試了一下将process.waitFor()注釋掉,然後用一個boolean型變量,來判斷子程序是否結束了(因為我這邊子程序結束了會發送特定的标志);這時一運作程式發送子程序調不起來了,這證明process.waitFor()這個方法是必須的,不能去掉,那就嘗試換個方法取代,經過嘗試,使用process.wait(10000)取代process.waitFor()可以實作我想要的效果,具體裡面的時間寫多少,可看情況而定。

最後我這邊使用了一個boolean型的标志位+process.wait(10000)實作了我需要的效果,在process.wait(10000)前面,我開啟了一個子線程來一直去讀子程序傳回的資料,當收到結束标志時,我把boolean型的标志位改變,同時process.destroy()掉,同時還會再開啟一個子線程,當主程序接收到伺服器發送的消息時,及時使用os寫給子程序。

可能不太好,但是我現在隻找到了這麼一個方法。

總結:

主程序發送和接受消息的三個方法

process.getErrorStream();
process.getOutputStream();
process.getInputStream();
           

子程序接收和發送消息的方法

system.in;
system.out;
           

繼續閱讀