Skip to content

Commit 9f6deba

Browse files
committed
执行命令
1 parent c991b8e commit 9f6deba

File tree

8 files changed

+397
-1
lines changed

8 files changed

+397
-1
lines changed

AndroidExecLibrary/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,6 @@ dependencies {
2929
testImplementation 'junit:junit:4.12'
3030
androidTestImplementation 'com.android.support.test:runner:1.0.2'
3131
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
32+
implementation 'io.reactivex.rxjava2:rxjava:2.2.0'
33+
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
3234
}
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
package com.excellence.exec;
2+
3+
import java.io.BufferedReader;
4+
import java.io.InputStreamReader;
5+
import java.util.LinkedList;
6+
import java.util.List;
7+
8+
import io.reactivex.Observable;
9+
import io.reactivex.ObservableEmitter;
10+
import io.reactivex.ObservableOnSubscribe;
11+
import io.reactivex.schedulers.Schedulers;
12+
13+
/**
14+
* <pre>
15+
* author : VeiZhang
16+
* blog : http://tiimor.cn
17+
* time : 2018/8/16
18+
* desc :
19+
* </pre>
20+
*/
21+
public class Command {
22+
23+
private static final String TAG = Command.class.getSimpleName();
24+
25+
protected static final int DEFAULT_TIME_OUT = 10 * 1000;
26+
27+
private final LinkedList<CommandTask> mTaskQueue;
28+
private int mParallelTaskCount = 0;
29+
private int mTimeOut = 0;
30+
31+
protected Command(int parallelTaskCount, int timeOut) {
32+
mTaskQueue = new LinkedList<>();
33+
mParallelTaskCount = parallelTaskCount;
34+
if (mParallelTaskCount <= 0) {
35+
mParallelTaskCount = Integer.MAX_VALUE;
36+
}
37+
mTimeOut = timeOut;
38+
if (mTimeOut <= 0) {
39+
mTimeOut = DEFAULT_TIME_OUT;
40+
}
41+
}
42+
43+
public CommandTask addTask(List<String> command, IListener listener) {
44+
CommandTask task = new CommandTask(command, listener);
45+
synchronized (mTaskQueue) {
46+
mTaskQueue.add(task);
47+
}
48+
schedule();
49+
return task;
50+
}
51+
52+
private synchronized void schedule() {
53+
// count running task
54+
int runningTaskCount = 0;
55+
for (CommandTask task : mTaskQueue) {
56+
if (task.isRunning) {
57+
runningTaskCount++;
58+
}
59+
}
60+
61+
if (runningTaskCount >= mParallelTaskCount) {
62+
return;
63+
}
64+
65+
// deploy task to fill parallel task count
66+
for (CommandTask task : mTaskQueue) {
67+
task.deploy();
68+
if (++runningTaskCount == mParallelTaskCount) {
69+
return;
70+
}
71+
}
72+
}
73+
74+
private synchronized void remove(CommandTask task) {
75+
mTaskQueue.remove(task);
76+
schedule();
77+
}
78+
79+
/**
80+
* 关闭所有下载任务
81+
*/
82+
public synchronized void clearAll() {
83+
while (!mTaskQueue.isEmpty()) {
84+
mTaskQueue.get(0).cancel();
85+
}
86+
}
87+
88+
public class CommandTask {
89+
90+
private List<String> mCommand = null;
91+
private Process mProcess = null;
92+
private boolean isRunning = false;
93+
private IListener mIListener = null;
94+
95+
private CommandTask(List<String> command, final IListener listener) {
96+
mCommand = command;
97+
mIListener = new IListener() {
98+
@Override
99+
public void onPre(String command) {
100+
if (listener != null) {
101+
listener.onPre(command);
102+
}
103+
}
104+
105+
@Override
106+
public void onProgress(String message) {
107+
if (listener != null) {
108+
listener.onProgress(message);
109+
}
110+
}
111+
112+
@Override
113+
public void onError(Throwable t) {
114+
isRunning = false;
115+
if (listener != null) {
116+
listener.onError(t);
117+
}
118+
schedule();
119+
}
120+
121+
@Override
122+
public void onSuccess(String message) {
123+
isRunning = false;
124+
if (listener != null) {
125+
listener.onSuccess(message);
126+
}
127+
remove(CommandTask.this);
128+
}
129+
};
130+
}
131+
132+
void deploy() {
133+
try {
134+
isRunning = true;
135+
Observable.create(new ObservableOnSubscribe<String>() {
136+
@Override
137+
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
138+
StringBuilder cmd = new StringBuilder();
139+
for (String item : mCommand) {
140+
cmd.append(item).append(" ");
141+
}
142+
mIListener.onPre(cmd.toString());
143+
mProcess = new ProcessBuilder(mCommand).redirectErrorStream(true).start();
144+
145+
BufferedReader stdin = new BufferedReader(new InputStreamReader(mProcess.getInputStream()));
146+
StringBuilder result = new StringBuilder();
147+
String line = null;
148+
while ((line = stdin.readLine()) != null) {
149+
mIListener.onProgress(line);
150+
result.append(line);
151+
}
152+
stdin.close();
153+
154+
mIListener.onSuccess(result.toString());
155+
}
156+
}).observeOn(Schedulers.io()).subscribe();
157+
} catch (Exception e) {
158+
mIListener.onError(e);
159+
}
160+
}
161+
162+
private void cancel() {
163+
if (mProcess != null) {
164+
mProcess.destroy();
165+
}
166+
mTaskQueue.remove(this);
167+
}
168+
169+
public void discard() {
170+
if (mProcess != null) {
171+
mProcess.destroy();
172+
}
173+
remove(this);
174+
}
175+
176+
}
177+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package com.excellence.exec;
2+
3+
import android.support.annotation.NonNull;
4+
import android.util.Log;
5+
6+
import com.excellence.exec.Command.CommandTask;
7+
8+
import java.util.Arrays;
9+
import java.util.List;
10+
11+
import static com.excellence.exec.Command.DEFAULT_TIME_OUT;
12+
13+
/**
14+
* <pre>
15+
* author : VeiZhang
16+
* blog : http://tiimor.cn
17+
* time : 2018/8/16
18+
* desc :
19+
* </pre>
20+
*/
21+
public class Commander {
22+
23+
private static final String TAG = Commander.class.getSimpleName();
24+
25+
private static Commander mInstance = null;
26+
27+
private Command mCommand = null;
28+
29+
/**
30+
* 默认:不限制并发线程数;指令超时10s终止
31+
*/
32+
public static void init() {
33+
init(Integer.MAX_VALUE, DEFAULT_TIME_OUT);
34+
}
35+
36+
/**
37+
* 初始化
38+
*
39+
* @param parallelTaskCount 并发线程数
40+
* @param timeOut 执行命令超时时间(存在某些命令会需要人为输入确认,此时命令会一直卡住等待),默认10s超时,终止指令
41+
*/
42+
public static void init(int parallelTaskCount, int timeOut) {
43+
if (mInstance != null) {
44+
Log.i(TAG, "Commander initialized!!!");
45+
return;
46+
}
47+
mInstance = new Commander();
48+
mInstance.mCommand = new Command(parallelTaskCount, timeOut);
49+
}
50+
51+
private Commander() {
52+
53+
}
54+
55+
public static CommandTask addTask(@NonNull List<String> command, IListener listener) {
56+
checkCommander();
57+
return mInstance.mCommand.addTask(command, listener);
58+
}
59+
60+
public static CommandTask addTask(@NonNull String[] command, IListener listener) {
61+
checkCommander();
62+
return addTask(Arrays.asList(command), listener);
63+
}
64+
65+
public static CommandTask addTask(@NonNull String command, IListener listener) {
66+
checkCommander();
67+
return addTask(new String[]{command}, listener);
68+
}
69+
70+
public static CommandTask addUniqueTask() {
71+
return null;
72+
}
73+
74+
private static void checkCommander() {
75+
if (mInstance == null) {
76+
throw new RuntimeException("Commander not initialized!!!");
77+
}
78+
}
79+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.excellence.exec;
2+
3+
/**
4+
* <pre>
5+
* author : VeiZhang
6+
* blog : http://tiimor.cn
7+
* time : 2018/8/16
8+
* desc :
9+
* </pre>
10+
*/
11+
public interface IListener {
12+
13+
void onPre(String command);
14+
15+
void onProgress(String message);
16+
17+
void onError(Throwable t);
18+
19+
void onSuccess(String message);
20+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.excellence.exec;
2+
3+
/**
4+
* <pre>
5+
* author : VeiZhang
6+
* blog : http://tiimor.cn
7+
* time : 2018/8/16
8+
* desc :
9+
* </pre>
10+
*/
11+
public class Listener implements IListener {
12+
13+
@Override
14+
public void onPre(String command) {
15+
16+
}
17+
18+
@Override
19+
public void onProgress(String message) {
20+
21+
}
22+
23+
@Override
24+
public void onError(Throwable t) {
25+
26+
}
27+
28+
@Override
29+
public void onSuccess(String message) {
30+
31+
}
32+
}

README.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# AndroidExec
2+
3+
Android命令执行以及回调
4+
5+
## 使用
6+
7+
```
8+
// 初始化,默认:不限制并发线程数;指令超时10s终止
9+
Commander.init();
10+
11+
// 创建执行命令
12+
Commander.addTask("ls", new IListener() {
13+
@Override
14+
public void onPre(String command) {
15+
Log.i(TAG, "onPre: " + command);
16+
}
17+
18+
@Override
19+
public void onProgress(String message) {
20+
Log.i(TAG, "onProgress: " + message);
21+
}
22+
23+
@Override
24+
public void onError(Throwable t) {
25+
t.printStackTrace();
26+
}
27+
28+
@Override
29+
public void onSuccess(String message) {
30+
Log.i(TAG, "onSuccess: " + message);
31+
}
32+
});
33+
```
34+
35+
## Runtime
36+
37+
```
38+
// 执行命令
39+
Process process = Runtime.getRuntime().exec("command");
40+
41+
// 读取正常输出
42+
process.getInputStream()
43+
44+
// 读取错误输出
45+
process.getErrorStream()
46+
```
47+
48+
## ProcessBuilder
49+
50+
```
51+
// 执行命令,重定向输出流
52+
Process process = new ProcessBuilder("command").redirectErrorStream(true).start();
53+
54+
// 不设置重定向,则正常输出、错误输出如同Runtime;
55+
// 设置了重定向后,正常输出、错误输出都统一读取process.getInputStream()
56+
```
57+

sample/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ android {
55
defaultConfig {
66
applicationId "com.excellence.exec.sample"
77
minSdkVersion 15
8-
targetSdkVersion 25
8+
targetSdkVersion 21
99
versionCode 1
1010
versionName "1.0"
1111
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

0 commit comments

Comments
 (0)