【问题标题】:Android HTTP: get out of infinite while loop with sending requests to Apache serverAndroid HTTP:通过向 Apache 服务器发送请求来摆脱无限循环
【发布时间】:2018-08-09 09:39:05
【问题描述】:

这是我项目的架构:

1) Android 应用 -> 2) RPi 上的 Apache 服务器 -> 3) 控制的 Python 脚本 -> 4) 我的设备

1) Android 应用 - 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 脚本来停止设备

我的问题:我可以通过网络浏览器使用这些脚本正确控制我的设备,例如:

出于测试目的,这是 Apache2 的 led1 的 access.log(=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,像 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,像 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 构建/OPM3.171019.014)"

我在 5 秒后“关闭”,但是......

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 构建/OPM3.171019.014)"

没有!注意到 14 秒的差异(它启动大约 3 秒,然后工作 10 秒)。它在 led1=1 的脚本完成工作后收到 GET)。 p>

当脚本工作 10 秒 (led1) 时,这是一个问题,但当脚本在无限循环 (led2) 中工作时,这是一个大问题 - 在第一个脚本停止之前我无法中断它(但它是 while True 循环所以。 ..)

我正在考虑在第二个脚本中使用 Python 的 subprocess.check_call() 来杀死第一个脚本,但它似乎没有帮助。

有什么办法解决这个问题吗?

【问题讨论】:

  • 你在说什么。它已经以if it was "led1=1", launch Python script that makes device work for 10 seconds (time.sleep(10)) 开头。设备?我想打开一个 LED 十秒钟。

标签: python android apache apache2


【解决方案1】:

最后,我成功了。杀死无限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;
    }
}
}

注意事项:

  • 每个切换开关都需要单独的请求(新的 HttpGet())
  • 与 BackgroundGet 相同(因为它是 AsyncTask)
  • flagToggle 有助于进行多次切换

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-13
    • 1970-01-01
    • 2022-01-15
    • 2014-04-30
    • 1970-01-01
    • 2018-08-22
    • 1970-01-01
    相关资源
    最近更新 更多