通过循环泄漏数据

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");