如何在 Android 上正确使用 AsyncTask?

How to properly use AsyncTask on Android?

我需要帮助检查 phone 我的 运行 应用程序是否已连接到互联网。我从 ping 一个 IP 开始检查连接。它看起来像这样:

    protected Boolean checkInternetConnection(Void... params) {
        try {
            InetAddress ipAddr = InetAddress.getByName("https://www.google.com");

            if (!ipAddr.isReachable(10000)) {
                return false;
            } else {
                return true;
            }

        } catch (Exception e) {
            Log.e("exception", e.toString());
            return false;
        }
    }
}

然而,它总是抛出 NetworkOnMainThreadException,所以我使用了 AsyncTask:

private class CheckConnectionTask extends AsyncTask<Void, Void, Boolean> {
    @Override
    protected Boolean doInBackground(Void... params) {
        try {
            InetAddress ipAddr = InetAddress.getByName("https://www.google.com");

            if (!ipAddr.isReachable(10000)) {
                return false;
            } else {
                return true;
            }

        } catch (Exception e) {
            Log.e("exception", e.toString());
            return false;
        }
    }
}

这段代码正确吗?因为我不知道怎么称呼它。我试过了:

new CheckConnectionTask().execute();

那里有什么东西不见了吗?因为它不起作用。另请注意,我已经看到了很多以前的问题,但我没有找到这个问题的任何答案,所以我问了我自己的问题。如果您看到可以解决我的问题的已回答问题,您可以在此处 link,但请记住,我对 Android 或 Java 没有经验,因此可能不清楚大部头书。我会更喜欢正确的代码作为答案,并简要解释为什么我没有工作。另外,我需要知道 phone 是否连接到 INTERNET,而不是 NETWORK,所以 ConnectivityManager 对我不起作用。

编辑 - 谢谢大家的回答。首先,我拥有所需的所有权限。此外,我目前无法获得任何结果,因为 Android Studio 突出显示了以下代码:

Boolean internetConnection;
internetConnection = new     CheckConnectionTask().execute();

不正确,它根本不允许我调用该函数。它有什么问题?它是否缺少任何参数?因为我将 params 定义为 Void 所以这似乎不合逻辑。

编辑 2 - 我按照@vandaics 的建议使用了 onPostExecute,现在看起来像这样:

private class CheckConnectionTask extends AsyncTask<Void, Void, Boolean> {
    @Override
    protected Boolean doInBackground(Void... params) {
        try {
            InetAddress ipAddr = InetAddress.getByName("google.com");

            if (!ipAddr.isReachable(10000)) {
                return false;
            } else {
                return true;
            }

        } catch (Exception e) {
            Log.e("exception", e.toString());
            return false;
        }
    }
    @Override
    protected void onPostExecute(Boolean result) {
        super.onPostExecute(result);
        internetConnection = result;
    }
}

有效,我是在调用onCreate方法的时候调用的:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    new CheckConnectionTask().execute();
}

它有效,我的应用程序会检查 Internet 是否已连接并做出正确反应。如果您认为某些事情可能行不通,或者有更简单的方法,请告诉我。非常感谢你们,尤其是@vandaics 和@Sunil。另外,我需要像这里一样使用超类吗?:

    @Override
    protected void onPostExecute(Boolean result) {
        super.onPostExecute(result);
        internetConnection = result;
    }

它有什么作用,有必要吗?

如果您要使用 AsyncTaks,您将缺少 onPostExecute 方法:

 protected void onPostExecute(Boolean result) {
     //your code here
 }

您还可以添加可选的 onProgressUpdate 方法:

 protected void onProgressUpdate(Integer... progress) {
    //do something on update
 }

然后执行你的操作:

新的 DownloadFilesTask().execute();

这是一个很好的例子,您可以使用:http://developer.android.com/reference/android/os/AsyncTask.html

您目前没有看到任何内容,因为您没有日志语句或者您没有真正检查任何内容。

来电

new CheckConnectionTask().execute()

是运行 AsyncTask。只是任务没有输出显示。

您可以检查输出,看看它是否是您想要的。

private class CheckConnectionTask extends AsyncTask<Void, Void, Boolean> {
    @Override
    protected Boolean doInBackground(Void... params) {
        try {
            InetAddress ipAddr = InetAddress.getByName("https://www.google.com");

            if (!ipAddr.isReachable(10000)) {
                return false;
            } else {
                return true;
            }

        } catch (Exception e) {
            Log.e("exception", e.toString());
            return false;
        }
    }

    @Override
    public void onPostexecute(Boolean result) {
        // TO DO on the UI thread
        Log.i("AsyncTask", "Result = " + result");
    }
}

编辑: 调用:

new CheckConnectionTask().execute()

returns 它正在执行的 AsyncTask 实例,而不是布尔值(尽管您确实指定布尔值应该是输出)。因此,您在这里看到编译错误。 AsyncTask 被设计成自包含的——它完成它应该做的所有事情然后终止。如果您确实必须修改 class 级别的实例变量(来自包含 AsyncTask 作为内部任务的 class)可以完成但不建议。

要检查互联网连接是否可用,您可以这样做:

private boolean isNetworkAvailable() {
    ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
    return activeNetworkInfo != null && activeNetworkInfo.isConnectedOrConnecting();
    //return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}

你不能打电话给

Boolean internetConnection;
internetConnection = new CheckConnectionTask().execute();

excute() 的 return 值不是您想要的。如果你想使用异步任务,你可以在 onPostExecute(...) 中设置一个布尔变量:

private boolean isConnect = false;
private class CheckConnectionTask extends AsyncTask<Void, Void, Boolean> {
@Override
protected Boolean doInBackground(Void... params) {
    try {
        InetAddress ipAddr = InetAddress.getByName("https://www.google.com");

        if (!ipAddr.isReachable(10000)) {
            return false;
        } else {
            return true;
        }

    } catch (Exception e) {
        Log.e("exception", e.toString());
        return false;
    }
}
@Override
protected void onPostExecute(Boolean result) {
    super.onPostExecute(aVoid);
    isConnect = result;
}
}

但是,我从来没有使用这种方法来获取互联网连接的状态,因为我必须先 运行 这个异步任务才能获得准确的状态。