在android工作室中,当手机没有互联网时,如何防止缓冲阅读器从url读取错误



在我的应用程序中,当我按下按钮时,缓冲读取器应该在线读取文本文件中的一行文本。

作为测试,如果文本读得正确,我希望出现一个祝酒词,上面写着"成功"。如果读取失败,比如因为手机没有连接到互联网,我希望出现一个祝酒词,上面写着"失败"。

然而,如果我打开飞机模式,然后按下按钮,它似乎永远"挂起","失败"的吐司永远不会出现——或者它只是完全崩溃了应用程序。

这是我正在使用的代码:

button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new NotePadFileFromServer().execute();
}
});
public class NotePadFileFromServer extends AsyncTask<Void, Void, Void>{
@Override
protected Void doInBackground(Void... params) {
try {
url = new URL(TextFileURL);
bufferReader = new BufferedReader(new InputStreamReader(url.openStream()));
TextHolder = bufferReader.readLine();
bufferReader.close();
} catch (Exception e) {
Toast.makeText(MainActivity.this, "Fail!", Toast.LENGTH_SHORT).show();
}
return null;
}
@Override
protected void onPostExecute(Void finalTextHolder) {
Toast.makeText(MainActivity.this, "Success!", Toast.LENGTH_SHORT).show();
super.onPostExecute(finalTextHolder);
}
}

我尝试使用ConnectivityManager添加预检查,以根据以下代码测试是否存在互联网连接:https://stackoverflow.com/a/58146646/4250107,但只有当手机用户专门关闭了互联网时,这才有效,如果打开了wifi功能,但没有互联网,崩溃就会再次发生。然后我试着按照以下代码检查互联网连接:https://stackoverflow.com/a/58146896/4250107,但这也会使应用程序崩溃,因为显然(?(尝试ping服务器在三星手机上不起作用。

编辑:最终固定代码。

public class NotePadFileFromServer extends AsyncTask<Void, Void, String>{
@Override
protected String doInBackground(Void... params) {
try {
URLConnection url = new URL(TextFileURL).openConnection());
url.setConnectTimeout(1000);
url.setReadTimeout(1000);
bufferReader = new BufferedReader(new InputStreamReader(url.getInputStream()));
TextHolder = bufferReader.readLine();
bufferReader.close();
return "Success!";
} catch (Exception e) {
return "Fail!";
}
}
@Override
protected void onPostExecute(String success) {
Toast.makeText(MainActivity.this, success, Toast.LENGTH_SHORT).show();
super.onPostExecute(success);
}
}

应用程序正在崩溃,因为当出现异常时,您正试图在后台线程中执行与UI相关的任务。因此,以下是造成此次事故的原因,

catch (Exception e) {
Toast.makeText(MainActivity.this, "Fail!", Toast.LENGTH_SHORT).show(); 
}

因此,您可以通过以下方式重构代码来避免崩溃,

public class NotePadFileFromServer extends AsyncTask<Void, Void, String>{
@Override
protected String doInBackground(Void... params) {
try {
url = new URL(TextFileURL);
bufferReader = new BufferedReader(new InputStreamReader(url.openStream()));
TextHolder = bufferReader.readLine();
bufferReader.close();
return "Success!";
} catch (Exception e) {
return "Fail!";
}
}
@Override
protected void onPostExecute(String finalTextHolder) {
Toast.makeText(MainActivity.this, finalTextHolder, Toast.LENGTH_SHORT).show();
super.onPostExecute(finalTextHolder);
}
}

如果出现超时问题,您在这里将其描述为挂起,我建议您使用openConnection()(返回UrlConnection(而不是openStream()。这样您就可以设置更短的连接和读取超时。

是的,正如你所说,ConnectivityManager不会帮助你,因为如果你有wifi但没有互联网,它会崩溃。

但是,可以检查互联网连接。我不能用ping(和你一样(,但当我试图打开一些打开的端口(80或443(的套接字时,我可以。这里有一个使用rxjava的代码,但您可以根据您正在使用的内容进行调整。

fun isOnline(context: Context?): Single<Boolean> {
return Single.fromCallable {
try {
// Connect to Google DNS to check for connection
val timeoutMs = 2500
val socket = Socket()
val address = InetAddress.getByName("www.google.com")
val socketAddress = InetSocketAddress(address, 443)
socket.connect(socketAddress, timeoutMs)
socket.close()
true
} catch (e: Exception) {
false
}
}.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}

在我的情况下,我用后端打开了套接字,这样我也可以检查它是否工作。我放了www.google.com以防你没有后台。

使用方法是:

isOnline(context).subscribe { hasInternet -> 
//Conditional check
} 

最新更新