在Android上以编程方式运行shell命令的任何方法?

44

有没有办法在我的应用程序上运行终端命令,然后访问我的UI上的数据?具体地说是 top 命令。

5个回答

40

可以参考Log Collector作为例子。这里是相关文件的链接

关键在于:

ArrayList<String> commandLine = new ArrayList<String>();
commandLine.add("logcat");//$NON-NLS-1$
[...]

Process process = Runtime.getRuntime().exec(commandLine);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));

所以基本上如果我想运行top命令,我只需要用top替换commandLine,它应该可以正常工作,对吗?我遇到了一个错误,所以我想我需要更多的帮助...谢谢。 - Shouvik
我是否需要在Process process = Runtime.getRuntime().exec(commandLine);周围加上try和catch,因为我一直得到这个throws IOException。我已经查看了Java示例,似乎都是这样处理的... - Shouvik
是的..再次确认链接以查看他们所做的一切。您绝对需要进行错误检查-不要期望所有手机都有“top”。 - EboMike
1
现在谷歌已经禁止了这个。 - Andy M

21

好的,以下是我亲测可行的代码,如果有人将来需要,可以使用它... :)

在try和catch块中包裹代码

try {
    Process process = Runtime.getRuntime().exec("top -n 1 -d 1");
    BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
} catch (InterruptedException e) {
    e.printStackTrace();
}

2
当我执行以下代码时:String result = null; result = bufferedReader.readLine(); Log.i("OnClickListener", "result: " + result); 它只显示“result:”(即'result'字符串为空)。你有什么想法为什么会这样?另外,当我尝试使用process = Runtime.getRuntime().exec("/system/bin/ping abc");时,'result'字符串为空。这两个命令在'adb shell'终端中都能正常工作。 - David Doria
抱歉@DavidDoria,我已经有两年没有接触安卓了。那是我在大学期间尝试过的东西。你最好将其发布为一个问题。 - Shouvik
2
我已经解决了。问题在于“top”的第一行是空的(一个新行,用于创建表格)。当实际有输出时返回null的情况是因为我需要获取stderror(getErrorStream)而不是stdout(getInputStream)。 - David Doria

11

我们可以按照以下方式执行命令,我在执行这个命令时成功了...尝试像这样,这里我们需要指定命令的完整路径。要获取命令的完整路径,在您的终端(Android)中键入

*$ which ls

/system/bin*

try {

    // Executes the command.

    Process process = Runtime.getRuntime().exec("/system/bin/ls /sdcard");

    // Reads stdout.
    // NOTE: You can write to stdin of the command using
    //       process.getOutputStream().
    BufferedReader reader = new BufferedReader(
            new InputStreamReader(process.getInputStream()));
    int read;
    char[] buffer = new char[4096];
    StringBuffer output = new StringBuffer();
    while ((read = reader.read(buffer)) > 0) {
        output.append(buffer, 0, read);
    }
    reader.close();

    // Waits for the command to finish.
    process.waitFor();

    return output.toString();
} catch (IOException e) {

    throw new RuntimeException(e);

} catch (InterruptedException e) {

    throw new RuntimeException(e);
}

5

这也取决于您在终端中运行的内容...如果您正在对文件运行"cat"命令,您也可以像这样执行。

final private String MEM_FILE = "/proc/meminfo";

public Long readMem() {
    String[] segs;
    FileReader fstream;
    try {
        fstream = new FileReader(MEM_FILE);
    } catch (FileNotFoundException e) {
        Log.e("readMem", "Could not read " + MEM_FILE);
        return false;
    }
    BufferedReader in = new BufferedReader(fstream, 500);
    String line;
    try {
        while ((line = in.readLine()) != null) {
            if (line.indexOf("MemTotal:") > 0) {
                Log.e("MemTotal", line);
                segs = line.trim().split("[ ]+");
                memTotal = Long.parseLong(segs[1]);
            }
            if (line.indexOf("MemFree:") > 0) {
                Log.e("MemFree", line);
                segs = line.trim().split("[ ]+");
                memFree = Long.parseLong(segs[1]);
            }
        }
        updateMem(); //call function to update textviews or whatever
        return true;
    } catch (IOException e) {
        Log.e("readMem", e.toString());
    }
    return false;
}

编辑: 在android实验室项目netmeter中有一个完美的例子供您参考。有一个名为Top.java的类,它实际上正是您想要的,并且在TaskList.java中用于显示。 http://code.google.com/p/android-labs/source/browse/#svn/trunk/NetMeter/src/com/google/android/netmeter


不是cat命令,我想要运行top命令并将实时结果显示在屏幕上。我知道有一些应用程序可以模拟终端,在这些终端上我已经成功运行了top命令,所以我想知道如何只获取top命令的结果并将其显示在用户界面上。 - Shouvik
请查看我上面的编辑,那里有一个可行的示例,正是你想要的。 - androidworkz
嘿,谢谢...需要花点时间在这里,但我觉得这就是答案...你帮了我大忙! - Shouvik
line.indexOf 应该是 > -1 而不是 > 0。-1 表示未找到。 - fangzhzh

2
对于 Kotlin 爱好者,您可以使用以下内容。
fun executeShell() {
    val command: String = "top -n 1"
    try {
        val process: Process = Runtime.getRuntime().exec(command)
        // Read the lines using BufferedReader
        BufferedReader(InputStreamReader(process.inputStream)).forEachLine {
            // Do something on each line read
            Log.d(this::class.java.canonicalName, "$it")
        }
    } catch (e: InterruptedException) {
        Log.w(this::class.java.canonicalName, "Cannot execute command [$command].", e)
    } catch (e: Exception) {
        Log.e(this::class.java.canonicalName, "Cannot execute command [$command].", e)
    }
}

您甚至不需要担心关闭缓冲区,因为forEachLine扩展函数会自动处理。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接