Android HTTP:通过向 Apache 服务器发送请求来摆脱无限循环
Android HTTP: get out of infinite while loop with sending requests to Apache server
这是我的项目的架构:
1) Android 应用 -> 2) RPi 上的 Apache 服务器 -> 3) Python 控制脚本 -> 4) 我的设备
1) Android app - 2 个简单的开关,每个开关向 RPi 上的 Apache 发送不同的请求:
public class MainActivity extends Activity{
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Switch switch_auto = findViewById(R.id.switch_auto);
Switch switch_manual = findViewById(R.id.switch_manual);
switch_auto.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
new Background_get().execute("led1=1");
} else {
new Background_get().execute("led1=0");
}
}
});
switch_manual.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
Log.d(TAG, "onCheckedChanged: SET TO TRUE");
new Background_get().execute("led2=1");
Log.d(TAG, "onCheckedChanged: EXIT");
} else {
Log.d(TAG, "onCheckedChanged: SET TO FALSE");
new Background_get().execute("led2=0");
Log.d(TAG, "onCheckedChanged: EXIT");
}
}
});
}
private class Background_get extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... params) {
try {
URL url = new URL("http://192.168.0.248/?" + params[0]);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder result = new StringBuilder();
String inputLine;
while ((inputLine = in.readLine()) != null)
result.append(inputLine).append("\n");
in.close();
connection.disconnect();
return result.toString();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
}
2) RPi 上的 Apache 服务器 - 非常简单 PHP 代码:
- 如果是 "led1=1",启动 Python 脚本使设备工作 10 秒 (
time.sleep(10)
)
- 如果是 "led1=0",只需打印一些内容
- 如果是 "led2=1",启动另一个 Python 脚本,使设备无限期工作 (
while True: time.sleep(1)
)
- 如果是 "led2=0",则启动第三个 Python 停止设备的脚本
我的问题:我可以通过网络浏览器使用这些脚本正确控制我的设备,例如:
- http://192.168.0.248/?led2=1 将打开设备并使其工作
- http://192.168.0.248/?led2=0 将关闭设备
出于测试目的,这是 Apache2 的 access.log for led1(=1 使其工作 10 秒,=0 仅打印一行):
192.168.0.10 - - [01/Mar/2018:10:42:01 +0100] "GET /?led1=1 HTTP/1.1" 200 411 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186
Safari/537.36"
(开始工作)
192.168.0.10 - - [01/Mar/2018:10:42:05 +0100] "GET /?led1=0 HTTP/1.1" 200 233 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186
Safari/537.36"
(4 秒后获取 led1=0 没问题,led1=1 的脚本还能再工作几秒)
不幸的是,我无法对我的 Android 应用程序 执行相同的操作。这是相同的 Apache 日志:
192.168.0.66 - - [01/Mar/2018:10:36:53 +0100] "GET /?led1=1 HTTP/1.1" 200 411 "-" "Dalvik/2.1.0 (Linux; U; Android 8.1.0; Nexus 5X
Build/OPM3.171019.014)"
(我在 5 秒后做了一个 "switch off" 但是...)
192.168.0.66 - - [01/Mar/2018:10:37:07 +0100] "GET /?led1=0 HTTP/1.1" 200 232 "-" "Dalvik/2.1.0 (Linux; U; Android 8.1.0; Nexus 5X
Build/OPM3.171019.014)"
(它没有!注意 14 秒的差异(它启动大约 3 秒然后工作 10 秒)。它在 led1=1 的脚本完成它的工作后收到 GET).
当脚本工作 10 秒 (led1) 时这是一个问题,但是当脚本在无限 while 循环 (led2) 中工作时这是一个大问题 - 在第一个脚本停止之前我无法中断它(但它是 while True 循环所以...)
我正在考虑在第二个脚本中使用 Python 的 subprocess.check_call()
来杀死第一个脚本,但它似乎没有帮助。
有什么解决办法吗?
终于,我成功了。终止无限 while 循环的想法是正确的,但首先我想在 Python 脚本上这样做是错误的。
我注意到当本地 .php 站点正在加载时(由于 while 循环),这些 GET 响应没有出现在日志中,因此需要中止当前的 GET。并且可以使用 Apache 的 httpcomponents 来完成。
因此,经过一些修改后,我的代码如下所示:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
boolean flagToggle = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Switch switch_auto = findViewById(R.id.switch_auto);
Switch switch_manual = findViewById(R.id.switch_manual);
switch_auto.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
HttpGet requestOn = new HttpGet();
HttpGet requestOff = new HttpGet();
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (!flagToggle) {
requestOn = new HttpGet();
requestOff = new HttpGet();
flagToggle = true;
}
Background_get switchOn = new Background_get(requestOn);
Background_get switchOff = new Background_get(requestOff);
if (isChecked) {
switchOn.execute("led1=1");
}
else {
requestOn.abort();
switchOff.execute("led1=0");
flagToggle = false;
}
}
});
switch_manual.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
HttpGet requestOn = new HttpGet();
HttpGet requestOff = new HttpGet();
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (!flagToggle) {
requestOn = new HttpGet();
requestOff = new HttpGet();
flagToggle = true;
}
Background_get switchOn = new Background_get(requestOn);
Background_get switchOff = new Background_get(requestOff);
if (isChecked) {
switchOn.execute("led2=1");
}
else {
requestOn.abort();
switchOff.execute("led2=0");
flagToggle = false;
}
}
});
}
public class Background_get extends AsyncTask<String, Void, String> {
private HttpGet mRequest = new HttpGet();
public Background_get(HttpGet newRequest) {
mRequest = newRequest;
}
public HttpGet getRequest() {
return mRequest;
}
public void setRequest(HttpGet newRequest) {
mRequest = newRequest;
}
@Override
protected String doInBackground(String... params) {
try {
URI url = new URI("http://192.168.0.248/?" + params[0]);
// HttpURLConnection connection = (HttpURLConnection) url.openConnection();
HttpClient httpclient = new DefaultHttpClient();
getRequest().setURI(url);
HttpResponse response = httpclient.execute(getRequest());
BufferedReader in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuilder result = new StringBuilder();
String inputLine;
while ((inputLine = in.readLine()) != null)
result.append(inputLine).append("\n");
in.close();
// response.close();
// httpclient.close();
return result.toString();
} catch (IOException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}
return null;
}
}
}
注意事项:
- 对于每个 toggle-switching 它需要单独的请求(新的 HttpGet())
- 与 BackgroundGet 相同(因为它是 AsyncTask)
- flagToggle 有助于多个 toggle-switching
这是我的项目的架构:
1) Android 应用 -> 2) RPi 上的 Apache 服务器 -> 3) Python 控制脚本 -> 4) 我的设备
1) Android app - 2 个简单的开关,每个开关向 RPi 上的 Apache 发送不同的请求:
public class MainActivity extends Activity{
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Switch switch_auto = findViewById(R.id.switch_auto);
Switch switch_manual = findViewById(R.id.switch_manual);
switch_auto.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
new Background_get().execute("led1=1");
} else {
new Background_get().execute("led1=0");
}
}
});
switch_manual.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
Log.d(TAG, "onCheckedChanged: SET TO TRUE");
new Background_get().execute("led2=1");
Log.d(TAG, "onCheckedChanged: EXIT");
} else {
Log.d(TAG, "onCheckedChanged: SET TO FALSE");
new Background_get().execute("led2=0");
Log.d(TAG, "onCheckedChanged: EXIT");
}
}
});
}
private class Background_get extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... params) {
try {
URL url = new URL("http://192.168.0.248/?" + params[0]);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder result = new StringBuilder();
String inputLine;
while ((inputLine = in.readLine()) != null)
result.append(inputLine).append("\n");
in.close();
connection.disconnect();
return result.toString();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
}
2) RPi 上的 Apache 服务器 - 非常简单 PHP 代码:
- 如果是 "led1=1",启动 Python 脚本使设备工作 10 秒 (
time.sleep(10)
) - 如果是 "led1=0",只需打印一些内容
- 如果是 "led2=1",启动另一个 Python 脚本,使设备无限期工作 (
while True: time.sleep(1)
) - 如果是 "led2=0",则启动第三个 Python 停止设备的脚本
我的问题:我可以通过网络浏览器使用这些脚本正确控制我的设备,例如:
- http://192.168.0.248/?led2=1 将打开设备并使其工作
- http://192.168.0.248/?led2=0 将关闭设备
出于测试目的,这是 Apache2 的 access.log for led1(=1 使其工作 10 秒,=0 仅打印一行):
192.168.0.10 - - [01/Mar/2018:10:42:01 +0100] "GET /?led1=1 HTTP/1.1" 200 411 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36"
(开始工作)
192.168.0.10 - - [01/Mar/2018:10:42:05 +0100] "GET /?led1=0 HTTP/1.1" 200 233 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36"
(4 秒后获取 led1=0 没问题,led1=1 的脚本还能再工作几秒)
不幸的是,我无法对我的 Android 应用程序 执行相同的操作。这是相同的 Apache 日志:
192.168.0.66 - - [01/Mar/2018:10:36:53 +0100] "GET /?led1=1 HTTP/1.1" 200 411 "-" "Dalvik/2.1.0 (Linux; U; Android 8.1.0; Nexus 5X Build/OPM3.171019.014)"
(我在 5 秒后做了一个 "switch off" 但是...)
192.168.0.66 - - [01/Mar/2018:10:37:07 +0100] "GET /?led1=0 HTTP/1.1" 200 232 "-" "Dalvik/2.1.0 (Linux; U; Android 8.1.0; Nexus 5X Build/OPM3.171019.014)"
(它没有!注意 14 秒的差异(它启动大约 3 秒然后工作 10 秒)。它在 led1=1 的脚本完成它的工作后收到 GET).
当脚本工作 10 秒 (led1) 时这是一个问题,但是当脚本在无限 while 循环 (led2) 中工作时这是一个大问题 - 在第一个脚本停止之前我无法中断它(但它是 while True 循环所以...)
我正在考虑在第二个脚本中使用 Python 的 subprocess.check_call()
来杀死第一个脚本,但它似乎没有帮助。
有什么解决办法吗?
终于,我成功了。终止无限 while 循环的想法是正确的,但首先我想在 Python 脚本上这样做是错误的。
我注意到当本地 .php 站点正在加载时(由于 while 循环),这些 GET 响应没有出现在日志中,因此需要中止当前的 GET。并且可以使用 Apache 的 httpcomponents 来完成。
因此,经过一些修改后,我的代码如下所示:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
boolean flagToggle = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Switch switch_auto = findViewById(R.id.switch_auto);
Switch switch_manual = findViewById(R.id.switch_manual);
switch_auto.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
HttpGet requestOn = new HttpGet();
HttpGet requestOff = new HttpGet();
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (!flagToggle) {
requestOn = new HttpGet();
requestOff = new HttpGet();
flagToggle = true;
}
Background_get switchOn = new Background_get(requestOn);
Background_get switchOff = new Background_get(requestOff);
if (isChecked) {
switchOn.execute("led1=1");
}
else {
requestOn.abort();
switchOff.execute("led1=0");
flagToggle = false;
}
}
});
switch_manual.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
HttpGet requestOn = new HttpGet();
HttpGet requestOff = new HttpGet();
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (!flagToggle) {
requestOn = new HttpGet();
requestOff = new HttpGet();
flagToggle = true;
}
Background_get switchOn = new Background_get(requestOn);
Background_get switchOff = new Background_get(requestOff);
if (isChecked) {
switchOn.execute("led2=1");
}
else {
requestOn.abort();
switchOff.execute("led2=0");
flagToggle = false;
}
}
});
}
public class Background_get extends AsyncTask<String, Void, String> {
private HttpGet mRequest = new HttpGet();
public Background_get(HttpGet newRequest) {
mRequest = newRequest;
}
public HttpGet getRequest() {
return mRequest;
}
public void setRequest(HttpGet newRequest) {
mRequest = newRequest;
}
@Override
protected String doInBackground(String... params) {
try {
URI url = new URI("http://192.168.0.248/?" + params[0]);
// HttpURLConnection connection = (HttpURLConnection) url.openConnection();
HttpClient httpclient = new DefaultHttpClient();
getRequest().setURI(url);
HttpResponse response = httpclient.execute(getRequest());
BufferedReader in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuilder result = new StringBuilder();
String inputLine;
while ((inputLine = in.readLine()) != null)
result.append(inputLine).append("\n");
in.close();
// response.close();
// httpclient.close();
return result.toString();
} catch (IOException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}
return null;
}
}
}
注意事项:
- 对于每个 toggle-switching 它需要单独的请求(新的 HttpGet())
- 与 BackgroundGet 相同(因为它是 AsyncTask)
- flagToggle 有助于多个 toggle-switching