1

Android アプリケーションでは、次のような画像 URL のリストがあります。

List<String> urls = new ArrayList<String>(100);
urls.add("http://www.example.org/1.jpg");
urls.add("http://www.example.org/2.png");
urls.add("http://www.example.org/3.jpg");
urls.add("http://www.example.org/4.jpg");
urls.add("http://www.example.org/5.png");
urls.add("http://www.example.org/6.png");
urls.add("http://www.example.org/7.png");
urls.add("http://www.example.org/8.jpg");
urls.add("http://www.example.org/9.jpg");
urls.add("http://www.example.org/10.gif");
    ...
urls.add("http://www.example.org/100.jpg");

ここで、これらすべての URL のファイル サイズと MIME タイプを取得する必要があります。もちろん、これはできるだけ速く行う必要があります。

私がしたことは次のとおりです。

for (String url : urls) {
    int fileSize;
    try {
        URLConnection urlConnection;
        urlConnection = new URL(url).openConnection();
        urlConnection.connect();
        final String mimeType = urlConnection.getContentType();
        final int fileSize = urlConnection.getContentLength();
        // do something with those two pieces of information
    }
    catch (MalformedURLException e) {
        continue;
    }
    catch (IOException e) {
        // some special handling
    }
}

しかし、これはひどく遅いです。これは、単一のスレッドを使用して URL を 1 つずつ要求しているのに対し、Web ブラウザーは常に一度に複数のファイルにアクセスするためですよね。

では、どうすれば速くなるでしょうか?

についてHttpClientは、インスタンスを再利用する必要があり、マルチスレッド環境でインスタンスを使用する方法がいくつかあることを読みました。

URLConnectionしかし、ファイルサイズと MIME タイプを提供する他のクラスでこれを行うにはどうすればよいでしょうか?

編集:

イメージはすべて同じホスト上にあるわけではありませんが、少数のサーバーのみに分散しています。たとえば、100 個のイメージが 5 つのホスト名に分散しています。

いくつかのスレッドを使用したり、ジョブを実行する複数の AsynTask を一度に実行したりできますか? リサイクルなど、気をつけていることはありますURLConnectionか?

複数のスレッドを使用してタスク リスト (100 個の画像ファイル) を共有し、後で結果 (MIME タイプとファイル サイズ) をマージする方法がよくわかりません。手伝ってくれますか?

4

3 に答える 3

3

作業を小さなピースに分割し、ワーカーThreadに処理させます。

労働者Thread

public class Downloader extends Thread {

    private final String mUrl;
    private String mMimeType;
    private int mFileSize;

    public Downloader(String url) {
        mUrl = url;
    }

    @Override
    public void run() {
        try {
            URLConnection urlConnection;
            urlConnection = new URL(mUrl).openConnection();
            urlConnection.connect();
            mMimeType = urlConnection.getContentType();
            mFileSize = urlConnection.getContentLength();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public String getMimeType() {
        return mMimeType;
    }

    public int getFileSize() {
        return mFileSize;
    }
}

ワーカーをインスタンス化して実行し、待機します。

ArrayList<String> urls = new ArrayList<String>(10);
// ...
ArrayList<Thread> threads = new ArrayList<Thread>(10);
for (String url : urls) {
    Thread t = new Downloader(url);
    threads.add(t);
    t.start();
}
for (Thread t : threads) {
    try {
        // do not wait for other threads  in main UI thread!
        t.join();
        //((Downloader) t).getMimeType();
        //((Downloader) t).getFileSize();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

ThreadUIでワーカーが待機することに注意してくださいThread

上記の回答は、少数の URL セットにのみ使用してください。ほとんどの場合、s は IO を待機するため、 AThreadPoolは必要ない場合があります。Thread


要求された回答はThreadPoolです。

上記の例と同じDownloaderクラスを 1 つだけ変更して使用しています。スポーンThreads は によって行われThreadPool、単一のタスクはもはや実数である必要はありThreadません。したがって、 aを拡張する代わりにa をDownloader実装しましょう:RunnableThread

public class Downloader implements Runnable {

うまくいけば、それはあなたが探しているものです。

public class ThreadedDownloader {

    private static final int KEEP_ALIVE_TIME = 1;
    private static final TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;
    private static int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
    private LinkedBlockingQueue<Runnable> mDecodeWorkQueue = new LinkedBlockingQueue<Runnable>();
    private ThreadPoolExecutor mDecodeThreadPool = new ThreadPoolExecutor(NUMBER_OF_CORES,
            NUMBER_OF_CORES, KEEP_ALIVE_TIME, KEEP_ALIVE_TIME_UNIT, mDecodeWorkQueue) {
        @Override
        protected void afterExecute(Runnable r, Throwable t) {
            super.afterExecute(r, t);
            Downloader d = (Downloader) r;
            // do something with finished Downloader d
            // like saving it's result to some sort of list
            // d.getMimeType();
            // d.getFileSize();

            if (mDecodeWorkQueue.isEmpty()) {
                onAllDownloadsFinised();
            }
        }
    };

    /** Download a list of urls and check it's mime time and file size. */
    public void download(List<String> urls) {
        for (String url : urls) {
            mDecodeThreadPool.execute(new Downloader(url));
        }
    }

    /** Calles when all downloads have finished. */
    private void onAllDownloadsFinised() {
        // do whatever you want here
        // update UI or something
    }
}
于 2013-09-12T04:16:19.277 に答える
2

サンプル コードはありませんが、HTTP 動詞 HEAD が探しているものです。コンテンツの本文を転送せずに、ヘッダー (mime と content-length を含む) を取得します。

この回答では、HEAD の機能について詳しく説明しています。

于 2013-09-20T21:58:35.353 に答える
1

すでに提出された回答には、ソリューションのすべてではないにしても、ほとんどの部分があると思います。

これが私がすることです:

1) Executors.newCachedThreadPool(); を使用して head リクエストを作成します。

2) 応答を Map に保存する

3) ペイロード マップを作成する

4) AsyncTask インスタンスを使用して実際の画像をロードする

5) 各ビットマップの読み込みが完了したら、結果をペイロード マップに格納します。

ちょうど私の考え。

于 2013-09-21T05:08:56.810 に答える