简体   繁体   English

Android:使用简单的警报对话框处理AsyncTask中的SocketTimeoutException

[英]Android: Handling SocketTimeoutException inside AsyncTask with a simple Alert Dialog

I use AsyncTask in my Android app to fetch some data from a server. 我在Android应用程序中使用AsyncTask从服务器获取一些数据。 To make the connection, I use the HttpURLConnection class with a timeout of 10 seconds. 要建立连接,我使用HttpURLConnection类,超时为10秒。 Now, I would like to show a simple AlertDialog when (if) that time expires, with an OK button that takes the user back to Main Activity. 现在,我想在(如果)该时间到期时显示一个简单的AlertDialog,使用OK按钮将用户带回到Main Activity。 Right now, this is what the relevant part of my app (DoorActivity) looks like: 现在,这就是我的应用程序(DoorActivity)的相关部分:

    protected String doInBackground(String... params) {

        try {

            URL url = new URL(params[0]);
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setConnectTimeout(10000);
            urlConnection.setRequestMethod("GET");
            if (urlConnection.getResponseCode() != 200) {
                throw new IOException(urlConnection.getResponseMessage());
            }

            BufferedReader read = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
            jsonString = read.readLine().toString();

        } catch (MalformedURLException malformedUrlException) {
            System.out.println(malformedUrlException.getMessage());
            malformedUrlException.printStackTrace();

        } catch (SocketTimeoutException connTimeout) {
            showTimeoutAlert();

showTimeoutAlert() method is located in the root class of DoorActivity, and looks like this: showTimeoutAlert()方法位于DoorActivity的根类中,如下所示:

protected void showTimeoutAlert(){
    TextView timeoutWarning = new TextView(this);
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    AlertDialog alertDialog;
    timeoutWarning.setText(R.string.conn_timeout_warning);
    builder.setView(timeoutWarning);
    builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {

        @Override
        public void onClick(DialogInterface dialog, int which) {
            Intent intent = new Intent(DoorActivity.this, MainActivity.class);
            startActivity(intent);
        }
    });
    alertDialog = builder.create();
    alertDialog.show();
}

Now, when I run this app, with the server deliberately offline, I get the following exception: 现在,当我运行此应用程序时,服务器故意脱机,我得到以下异常:

java.lang.RuntimeException: An error occured while executing doInBackground() java.lang.RuntimeException:执行doInBackground()时发生错误

Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() 引起:java.lang.RuntimeException:无法在未调用Looper.prepare()的线程内创建处理程序

showTimeoutAlert(); should not be called in doInBackground() . 不应该在doInBackground()调用。 Any code related to UI should go in onPostExecute() instead. 任何与UI相关的代码都应该放在onPostExecute()

For example: 例如:

private boolean socketTimedOut = false;

@Override
protected String doInBackground(String... params) {
    try {
        ...
    } catch (SocketTimeoutException connTimeout) {
        this.socketTimedOut = true;
    }
}


@Override
protected void onPostExecute(String result) {
    if(this.socketTimedOut){
        showTimeoutAlert();
    }
}

Alternative solution (not recommended): 替代解决方案(不推荐):

@Override
protected String doInBackground(String... params) {
    try {
        ...
    } catch (SocketTimeoutException connTimeout) {
        runOnUiThread(new Runnable() {
            public void run() {
                showTimeoutAlert();
            }
        });
    }
}       

You can not show popups/dialogs within doInBackground method. 您无法在doInBackground方法中显示弹出窗口/对话框。 Return null if you get any exceptions and check the return in postExecute method. 如果出现任何异常,则返回null并检查postExecute方法中的返回值。 There you can show the relevant popup/dialogs 在那里,您可以显示相关的弹出/对话框

You have to call showTimeoutAlert() in the postExecute method because you cannot change the UI in the doInBackground dialog. 您必须在postExecute方法中调用showTimeoutAlert(),因为您无法在doInBackground对话框中更改UI。 Return a relsut and then call the method there. 返回一个relsut,然后在那里调用该方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM