1. 程式人生 > >[Java][Android][Process] ProcessBuilder與Runtime區別

[Java][Android][Process] ProcessBuilder與Runtime區別

在Android中想要進行Ping,在不Root機器的情況下似乎還只能進行底層命呼叫才能實現。

因為在Java中要進行ICMP包傳送需要Root許可權。

於是只能通過建立程序來解決了,建立程序在Java中有兩種方式,分別為:

1. 呼叫ProcessBuilder的建構函式後執行start()
2. 用Runtime.getRuntime().exec()方法執行


經過使用後發現兩者有區別但是也並不是很大,兩個例子說明:


1.呼叫ProcessBuilder的建構函式後執行start():

Process process = new ProcessBuilder("/system/bin/ping").redirectErrorStream(true).start();
OutputStream stdout = process.getOutputStream();
InputStream stdin = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(stdin));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdout));


2.用Runtime.getRuntime().exec()方法執行:

Process process = Runtime.getRuntime().exec("/system/bin/ping");
OutputStream stdout = process.getOutputStream();
InputStream stderr = process.getErrorStream();
InputStream stdin = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(stdin));
BufferedReader err= new BufferedReader(new InputStreamReader(stderr));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdout));

兩者在執行效率上沒啥區別,可能是我沒有發現。兩種測試的區別在於是否可以重定向錯誤流。

使用ProcessBuilder,可以通過redirectErrorStream(true)將錯誤輸出流轉移到標準輸出流中,這樣使用一次process.getInputStreamReader()就能讀出該程序的所有輸出。

而使用Runtime.getRuntime().exec()方法時,錯誤的輸出流還需通過process.getErrorStream()來獲得。

分享一個自己集合的一個程序執行後銷燬的類:

import java.io.InputStream;
import java.io.OutputStream;

public class ProcessModel {

    /**
     * 通過Android底層實現程序關閉
     *
     * @param process
     */
    public static void killProcess(Process process) {
        int pid = getProcessId(process.toString());
        if (pid != 0) {
            try {
                android.os.Process.killProcess(pid);
            } catch (Exception e) {
                try {
                    process.destroy();
                } catch (Exception ex) {
                }
            }
        }
    }

    /**
     * 獲取當前程序的ID
     *
     * @param str
     * @return
     */
    public static int getProcessId(String str) {
        try {
            int i = str.indexOf("=") + 1;
            int j = str.indexOf("]");
            String cStr = str.substring(i, j).trim();
            return Integer.parseInt(cStr);
        } catch (Exception e) {
            return 0;
        }
    }


    /**
     * 關閉程序的所有流
     *
     * @param process
     */
    public static void closeAllStream(Process process) {
        try {
            InputStream in = process.getInputStream();
            if (in != null)
                in.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            InputStream in = process.getErrorStream();
            if (in != null)
                in.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            OutputStream out = process.getOutputStream();
            if (out != null)
                out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 銷燬一個程序
     *
     * @param process
     */
    public static void processDestroy(Process process) {
        if (process != null) {
            try {
                if (process.exitValue() != 0) {
                    closeAllStream(process);
                    killProcess(process);
                }
            } catch (IllegalThreadStateException e) {
                closeAllStream(process);
                killProcess(process);
            }
        }
    }


    /**
     * 通過執行緒進行非同步銷燬
     *
     * @param process
     */
    public static void asyncProcessDestroy(final Process process) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                processDestroy(process);
            }
        });
        thread.setDaemon(true);
        thread.start();
    }
}


奇怪的是,當使用執行緒進行大量的程序建立,最後達到一定數量(大約為1000個左右)的時候將會出現無法建立程序的情況;

此情況我不知怎麼解決,自己想的是弄一個執行緒池裡邊放20個已經建立的程序,而外部的執行緒重複利用以及建立的程序,不知這樣是否可行?

望大家探討一下解決方法,謝謝了。