9

http接続を使用してファイルをダウンロードするプロジェクトに取り組んでいます。ダウンロード中に進行状況バーのステータスを示す水平方向の進行状況バーを表示します。私の関数は次のようになります。

.......
try {           
        InputStream myInput = urlconnect.getInputStream();
        BufferedInputStream buffinput = new BufferedInputStream(myInput);

        ByteArrayBuffer baf = new ByteArrayBuffer(capacity);
        int current = 0;
        while((current = buffinput.read()) != -1) {
            baf.append((byte) current);
        }
File outputfile = new File(createRepertory(app, 0), Filename);
        FileOutputStream myOutPut = new FileOutputStream(outputfile);
        myOutPut.write(baf.toByteArray());
...
}

ファイルのサイズを事前に知っているので、ダウンロード中に(whileブロックで)サイズを取得する必要があります。したがって、プログレスバーのステータスを判別できます。

progressBarStatus = ((int) downloadFileHttp(url, app) * 100)/sizefile;

long downloadFileHttp(..、..)は私の関数の名前です。

私はすでにoutputfile.lengthを使用してそれを取得しようとしていますが、彼の値は「1」です。おそらく、ダウンロードしようとしているファイルの数です。

それを理解する方法はありますか?

更新1

私はこれを理解することを可能にするスレッドを持っていません。現在、中間値なしで0と100%のみを表示する水平プログレスバーがあります。別のアプローチを考えます。Wi-Fiの速度とファイルのサイズがわかれば、ダウンロードの時間を決定できます。

Wifi接続の情報とダウンロードするファイルのサイズを取得できることを知っています。

誰かがすでに働いているか、それにスレッドを持っていますか?

4

8 に答える 8

10

HttpURLConnectionを使用していると仮定します。その場合、 で getContentLength()メソッドを呼び出す必要がありますurlconnect

ただし、サーバーは有効なコンテンツの長さを送信する必要がないため、-1 になるように準備する必要があります。

于 2013-03-05T14:17:12.023 に答える
6

AsyncTask はあなたにとって完璧なソリューションかもしれません:

private class DownloadFileTask extends AsyncTask<URL, Integer, Long> {
 protected Long doInBackground(URL... urls) {
    Url url = urls[0];
    //connect to url here
    .......
    try {           
        InputStream myInput = urlconnect.getInputStream();
        BufferedInputStream buffinput = new BufferedInputStream(myInput);

        ByteArrayBuffer baf = new ByteArrayBuffer(capacity);
        int current = 0;
        while((current = buffinput.read()) != -1) {
            baf.append((byte) current);
            //here you can send data to onProgressUpdate
            publishProgress((int) (((float)baf.length()/ (float)sizefile) * 100));
        }
    File outputfile = new File(createRepertory(app, 0), Filename);
    FileOutputStream myOutPut = new FileOutputStream(outputfile);
    myOutPut.write(baf.toByteArray());
    ...
 }

 protected void onProgressUpdate(Integer... progress) {
     //here you can set progress bar in UI thread
     progressBarStatus = progress;
 }

}

メソッド内で AsyncTask 呼び出しを開始するには

new DownloadFileTask().execute(url);
于 2013-03-19T21:08:47.733 に答える
3

単純。以下のコード:

try {
    URL url = new URL(yourLinkofFile);
    URLConnection conn = url.openConnection();
    conn.connect();
    totalFileSize = conn.getContentLength();
} catch (Exception e) {
    Log.e(TAG, "ERROR: " + e.toString());
}
于 2013-03-20T09:26:04.983 に答える
2

応答の Content-Length ヘッダーを確認します。設定する必要があります。すべての主要な HTTP サーバーがこのヘッダーを使用します。

于 2013-03-05T15:23:53.470 に答える
2

HTTP 1.1 仕様では、chunk応答データは複数のラウンドにわたって引き戻されることになっています。availble実際には、チャンク レスポンスでは content-length が -1 であるため、Inputstream でメソッドを使用することはできません。ところで、メソッドはByteArrayInputStreamInputstream.availbleでコンテンツの長さを取得するためにのみ安定しています。

全長を取得したいだけの場合は、読み取りラウンドごとに自分で計算する必要があります。以下のapache commons-ioプロジェクトのIOUtilsクラスを参照してください。

//-----------------------------------------------------------------------
/**
 * Copy bytes from an <code>InputStream</code> to an
 * <code>OutputStream</code>.
 * <p>
 * This method buffers the input internally, so there is no need to use a
 * <code>BufferedInputStream</code>.
 * <p>
 * Large streams (over 2GB) will return a bytes copied value of
 * <code>-1</code> after the copy has completed since the correct
 * number of bytes cannot be returned as an int. For large streams
 * use the <code>copyLarge(InputStream, OutputStream)</code> method.
 * 
 * @param input  the <code>InputStream</code> to read from
 * @param output  the <code>OutputStream</code> to write to
 * @return the number of bytes copied
 * @throws NullPointerException if the input or output is null
 * @throws IOException if an I/O error occurs
 * @throws ArithmeticException if the byte count is too large
 * @since Commons IO 1.1
 */
public static int copy(InputStream input, OutputStream output) throws IOException {
    long count = copyLarge(input, output);
    if (count > Integer.MAX_VALUE) {
        return -1;
    }
    return (int) count;
}

/**
 * Copy bytes from a large (over 2GB) <code>InputStream</code> to an
 * <code>OutputStream</code>.
 * <p>
 * This method buffers the input internally, so there is no need to use a
 * <code>BufferedInputStream</code>.
 * 
 * @param input  the <code>InputStream</code> to read from
 * @param output  the <code>OutputStream</code> to write to
 * @return the number of bytes copied
 * @throws NullPointerException if the input or output is null
 * @throws IOException if an I/O error occurs
 * @since Commons IO 1.3
 */
public static long copyLarge(InputStream input, OutputStream output)
        throws IOException {
    byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
    long count = 0;
    int n = 0;
    while (-1 != (n = input.read(buffer))) {
        output.write(buffer, 0, n);
        count += n;
    }
    return count;
}

ダウンロードの進行状況を確認したい場合は、ディスクへのコッピングの過程で、InputStream入力からOutputStreamread出力までの各ラウンドでコールバックする必要があります。コールバックでは、データの一部をコピーして、プログレスバー機能で使用できるように設計されたカウンターに金額を追加できます。それは少し複雑です

于 2013-03-18T11:49:58.207 に答える
1

あなたはあなたの人生を複雑にしすぎていると思います:)

最初:progressBarStatus = ((int) downloadFileHttp(url, app) * 100)/sizefile;は常に 0 または 100 のいずれかであるため、値を正しく計算していない可能性があります。そこにメソッド全体を投稿しませんでしたが、int を扱っていることを忘れないでください。したがって、sizefile は常に int であり、sizefile 以上に除算すると常に 0 または 1 が返されます。調べる必要がある方向...また、中間バイトの読み取り後にプログレスバーを更新しているコードがわかりません。

2 番目: チャンクで読み取る方が効率的だと思います。読み取りはより効率的であり、ダウンロードされたバイトごとに UI スレッドに通知する必要はありません。このスレッドの Adamski からの回答 が役立つ場合があります。より小さなバイト配列を使用してください。私は通常 256 (3G) または 512 (Wi-Fi) を使用していますが、それほど詳しく説明する必要はないかもしれません。したがって、新しい配列を読み取ったら、読み取った合計バイト数をカウントし、UI に通知して、ストリームの最後まで読み取りを続けます。

3 番目:progressBar.setMax()ダウンロード前に sizeFile を設定し、「First」のコメントに基づいてダウンロードされたバイト数を適切に計算し、その計算された数値で setProgress を呼び出します。UI スレッドでプログレスバーを更新することを忘れないでください。AsyncTask には、それを支援する優れたメカニズムがあります。

幸運を!

于 2013-03-20T12:52:50.260 に答える
1

あなたの主な問題は、ファイルの長さを取得したり実際の値を把握したりすることではなく、ステータスバーを適切に更新できるように別のスレッドから現在の値にアクセスする方法のようです。

これを解決するには、いくつかのアプローチがあります。

1.) プログレス バー アイテムには、ダウンロード スレッドでカウントを更新するたびに値を設定してそのメソッドを呼び出すコールバックがあります。2.) 両方のスレッドからアクセスできるフィールドに値を入力します (スレッドセーフではない可能性があります)。

それが私だったら、プログレス バーの項目に、何らかの値で進行状況を更新できるメソッドがあります。次に、ファイルをダウンロードしているスレッドからそのメソッドを呼び出します。

したがって、基本的にユーザー->ダウンロードボタンをクリックします->ハンドラーはメソッドを呼び出してダウンロードを開始し、コールバックを更新進行状況バーメソッドに渡します->ダウンロードスレッドは、更新されたパーセンテージが完了した各反復サイクルでメソッドを呼び出します。

于 2013-03-19T20:05:46.453 に答える
0

さて、これはあなたを助けるはずです

URLConnection connection = servletURL.openConnection();
BufferedInputStream buff = new BufferedInputStream(connection .getInputStream());
ObjectInputStream input = new ObjectInputStream(buff );
int avail = buff .available();

System.out.println("Response content size = " + avail);
于 2013-03-05T14:49:53.570 に答える