关于httpurlconnection getcontentlength返回值为-1的问题

来源:互联网 发布:windows 7 系统还原 编辑:程序博客网 时间:2024/06/05 08:01

在做AsyncTask异步任务读取网络数据的时候,发现了httpUrlConnection的获取数据内容长度(connection.getContentLength())总是为-1。导致进度条一直为灰色状态。预期结果应如图所示:


而现在的效果是这样的:


MainActivity代码如下:

import android.os.AsyncTask;import android.support.v7.app.ActionBarActivity;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.ProgressBar;import android.widget.TextView;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStream;import java.net.MalformedURLException;import java.net.URL;import java.net.URLConnection;public class MainActivity extends ActionBarActivity {    private Button executeBtn;    private Button cancelBtn;    private MyTask myTask;    private TextView resultTxt;    public ProgressBar progressBar;    private View.OnClickListener executeBtnListener = new View.OnClickListener() {        @Override        public void onClick(View v) {           myTask = new MyTask();            myTask.execute("https://www.baidu.com");            executeBtn.setEnabled(false);            cancelBtn.setEnabled(true);        }    };    private View.OnClickListener cancelBtnListener = new View.OnClickListener() {        @Override        public void onClick(View v) {            myTask.cancel(true);        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        executeBtn = (Button) findViewById(R.id.executeBtn);        cancelBtn = (Button) findViewById(R.id.cancelBtn);        progressBar = (ProgressBar) findViewById(R.id.progressBar);        resultTxt = (TextView) findViewById(R.id.resultTxt);        executeBtn.setOnClickListener(executeBtnListener);        cancelBtn.setOnClickListener(cancelBtnListener);    }    public class MyTask extends AsyncTask<String,Integer,String> {        private static final String TAG = "ASYNC_TASK";        /**         * Override this method to perform a computation on a background thread. The         * specified parameters are the parameters passed to {@link #execute}         * by the caller of this task.         * <p/>         * This method can call {@link #publishProgress} to publish updates         * on the UI thread.         *         * @param params The parameters of the task.         * @return A result, defined by the subclass of this task.         * @see #onPreExecute()         * @see #onPostExecute         * @see #publishProgress         */        @Override        protected String doInBackground(String... params) {            try {                URL url = new URL(params[0]);                URLConnection connection = url.openConnection();//                connection.setRequestProperty("Accept-Encoding", "identity");                long total = connection.getContentLength();                InputStream inputStream = connection.getInputStream();                ByteArrayOutputStream baos = new ByteArrayOutputStream();                byte[] buf = new byte[256];                int count = 0;                int length = -1;                while((length = inputStream.read(buf)) != -1){                    baos.write(buf,0,length);                    count += length;                    publishProgress((int)((count/(float)total)*100));                    Thread.sleep(500);                }                inputStream.close();                return new String(baos.toByteArray(),"utf-8");            } catch (MalformedURLException e) {                e.printStackTrace();            } catch (IOException e) {                e.printStackTrace();            } catch (InterruptedException e) {                e.printStackTrace();            }            return null;        }        @Override        protected void onPreExecute() {            super.onPreExecute();        }        @Override        protected void onPostExecute(String s) {            super.onPostExecute(s);            resultTxt.setText(s);            executeBtn.setEnabled(true);            cancelBtn.setEnabled(false);        }        @Override        protected void onProgressUpdate(Integer... values) {            Log.i(TAG, "onProgressUpdate(Progress... progresses) called");            progressBar.setProgress(values[0]);//            System.out.print(values[0]);        }        @Override        protected void onCancelled(String s) {            super.onCancelled(s);        }        @Override        protected void onCancelled() {            super.onCancelled();            resultTxt.setText("cancelled!");            progressBar.setProgress(0);            executeBtn.setEnabled(true);            cancelBtn.setEnabled(false);        }    }}
使用System.out.println()输出total为-1,肯定是connection.getContentLength()有问题,现在来看一下这个方法的api:By default, this implementation of HttpURLConnection requests that servers use gzip compression. Since getContentLength() returns the number of bytes transmitted, you cannot use that method to predict how many bytes can be read from getInputStream(). Instead, read that stream until it is exhausted: whenread() returns -1.原来获取的数据是采用gzip压缩的格式的,所以读不出来数据。找到了问题就该找解决办法了,在connection.getContentLength()前面加上使用
connection.setRequestProperty("Accept-Encoding", "identity");
setRequestProperty主要是设置HttpURLConnection请求头里面的属性,比如请求内容格式、Cookie、User-Agent(浏览器类型)等等。

最后实现效果如图所示:



最终结果:


0 0