通过循环泄漏数据
Data leakage through loop
我正在尝试通过 AsyncTask
下载网页的 html,然后在日志中显示 html。
这是我的代码。但是,当我 运行 代码时,循环永远不会停止。
public class MainActivity extends AppCompatActivity {
public class DownloadTask extends AsyncTask<String,Void,String>{
@Override
protected String doInBackground(String... urls) {
String result = "";
HttpURLConnection connection = null;
URL myUrl;
try{
myUrl = new URL(urls[0]);
connection = (HttpURLConnection) myUrl.openConnection();
InputStream in = connection.getInputStream();
InputStreamReader reader = new InputStreamReader(in);
int data = reader.read();
while(data != -1){
char current = (char) data;
result += current;
data = reader.read();
}
return result;
}
catch(Exception e){
e.printStackTrace();
return "Failed";
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DownloadTask task = new DownloadTask();
try {
String result = task.execute("http://www.posh24.com/celebrities").get();
Log.i("asd",String.valueOf(result));
}
catch(Exception e){
e.printStackTrace();
}
}
}
我的日志充满了:
D/dalvikvm: GC_FOR_ALLOC freed 297K, 20% free 2582K/3200K, paused 4ms, total 4ms
知道代码有什么问题吗?
可能是因为在收到的每个字符上都创建了一个新字符串。不要这样做:
result += current;
相反,创建一个 StringBuilder
并附加到它。
或者,更好的是,不要一次读取一个字符,而是创建一个 BufferedReader
并读入一个相当大的缓冲区,例如1024 字节。
你的代码的问题是 data
在你用一个 read()
调用初始化它之后不会改变,所以它永远不会是 -1
(因此无限循环)。
您需要在循环内调用 read()
。
替换以下内容:
int data = reader.read();
while(data != -1){
// ...
像这样:
int data;
while ((data = reader.read()) != -1) {
// ...
为了加快速度,您可以使用 BufferedReader
:
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line = null;
StringBuilder builder = new StringBuilder();
while((line = reader.readLine()) != null) {
builder.append(line);
}
String data = builder.toString();
我可以用你的代码获取数据。我相信您在测试时已经添加了互联网权限。
但是由于 task.execute().get(),您的代码阻塞了 UI 线程。我稍微改了一下:
public class DownloadTask extends AsyncTask<String, Void, String> {
private Listener mListener;
DownloadTask(Listener listener) {
mListener = listener;
}
@Override
protected String doInBackground(String... urls) {
String result = "";
HttpURLConnection connection = null;
URL myUrl;
try {
myUrl = new URL(urls[0]);
connection = (HttpURLConnection) myUrl.openConnection();
InputStream in = connection.getInputStream();
InputStreamReader reader = new InputStreamReader(in);
int data = reader.read();
while (data != -1) {
char current = (char) data;
result += current;
data = reader.read();
}
return result;
} catch (Exception e) {
e.printStackTrace();
return "Failed";
}
}
@Override
protected void onPostExecute(String s) {
mListener.deliverResult(s);
}
public interface Listener {
void deliverResult(String result);
}
}
Activity 中的代码如下所示:
DownloadTask task = new DownloadTask(new DownloadTask.Listener() {
@Override
public void deliverResult(String result) {
Log.i("asd",String.valueOf(result));
}
});
task.execute("http://www.posh24.com/celebrities");
我正在尝试通过 AsyncTask
下载网页的 html,然后在日志中显示 html。
这是我的代码。但是,当我 运行 代码时,循环永远不会停止。
public class MainActivity extends AppCompatActivity {
public class DownloadTask extends AsyncTask<String,Void,String>{
@Override
protected String doInBackground(String... urls) {
String result = "";
HttpURLConnection connection = null;
URL myUrl;
try{
myUrl = new URL(urls[0]);
connection = (HttpURLConnection) myUrl.openConnection();
InputStream in = connection.getInputStream();
InputStreamReader reader = new InputStreamReader(in);
int data = reader.read();
while(data != -1){
char current = (char) data;
result += current;
data = reader.read();
}
return result;
}
catch(Exception e){
e.printStackTrace();
return "Failed";
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DownloadTask task = new DownloadTask();
try {
String result = task.execute("http://www.posh24.com/celebrities").get();
Log.i("asd",String.valueOf(result));
}
catch(Exception e){
e.printStackTrace();
}
}
}
我的日志充满了:
D/dalvikvm: GC_FOR_ALLOC freed 297K, 20% free 2582K/3200K, paused 4ms, total 4ms
知道代码有什么问题吗?
可能是因为在收到的每个字符上都创建了一个新字符串。不要这样做:
result += current;
相反,创建一个 StringBuilder
并附加到它。
或者,更好的是,不要一次读取一个字符,而是创建一个 BufferedReader
并读入一个相当大的缓冲区,例如1024 字节。
你的代码的问题是 data
在你用一个 read()
调用初始化它之后不会改变,所以它永远不会是 -1
(因此无限循环)。
您需要在循环内调用 read()
。
替换以下内容:
int data = reader.read();
while(data != -1){
// ...
像这样:
int data;
while ((data = reader.read()) != -1) {
// ...
为了加快速度,您可以使用 BufferedReader
:
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line = null;
StringBuilder builder = new StringBuilder();
while((line = reader.readLine()) != null) {
builder.append(line);
}
String data = builder.toString();
我可以用你的代码获取数据。我相信您在测试时已经添加了互联网权限。
但是由于 task.execute().get(),您的代码阻塞了 UI 线程。我稍微改了一下:
public class DownloadTask extends AsyncTask<String, Void, String> {
private Listener mListener;
DownloadTask(Listener listener) {
mListener = listener;
}
@Override
protected String doInBackground(String... urls) {
String result = "";
HttpURLConnection connection = null;
URL myUrl;
try {
myUrl = new URL(urls[0]);
connection = (HttpURLConnection) myUrl.openConnection();
InputStream in = connection.getInputStream();
InputStreamReader reader = new InputStreamReader(in);
int data = reader.read();
while (data != -1) {
char current = (char) data;
result += current;
data = reader.read();
}
return result;
} catch (Exception e) {
e.printStackTrace();
return "Failed";
}
}
@Override
protected void onPostExecute(String s) {
mListener.deliverResult(s);
}
public interface Listener {
void deliverResult(String result);
}
}
Activity 中的代码如下所示:
DownloadTask task = new DownloadTask(new DownloadTask.Listener() {
@Override
public void deliverResult(String result) {
Log.i("asd",String.valueOf(result));
}
});
task.execute("http://www.posh24.com/celebrities");