如何在单个进程中从 url 下载多个图像?

How to download multiple images from urls in a single process?

我创建用于下载多张图片的应用程序,来自 url,问题是当下载所有图片(有 3000 张图片)时它是多进程,而不是单进程。单进程我的意思是下载然后保存,下载然后保存等等。 单进程可以下载多图吗?

这是我的代码:

private CoordinatorLayout mCLayout;
private ProgressDialog mProgressDialog;
private LinearLayout mLLayout;

private AsyncTask mMyTask;

private final URL[] URLS = {
        stringToURL("https://d1rkccsb0jf1bk.cloudfront.net/products/3d/100009884/images/I_20.jpg"),
        stringToURL("https://d3inagkmqs1m6q.cloudfront.net/2280/media-photos/azk0w23602-black-new-calvin-klein-watches-k0w23602.jpg"),
        stringToURL("https://www.designerswatch.com.au/media/catalog/product/cache/1/image/800x800/9df78eab33525d08d6e5fb8d27136e95/k/2/k2y211c3-1.jpg"),
        stringToURL("http://demandware.edgesuite.net/sits_pod35/dw/image/v2/ABAD_PRD/on/demandware.static/-/Sites-calvinklein-hk-master/default/dw521470a6/images/hi-res/K7Y214CZ-000/K7Y214CZ-000-ITEM-1.jpg?sw=500"),
        stringToURL("https://ethos-cdn1.ethoswatches.com/pub/media/catalog/product/cache/749a04adc68de020ef4323397bb5eac7/c/a/calvin-klein-party-k8u2m116.jpg")
// and so on
    };
    int count;
// List of url image
List<URL> imageName = new ArrayList<>();

File file;
ContextWrapper wrapper;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    // Get the application context
    getApplicationContext();
    Activity mActivity = MainActivity.this;

    // Get the widget reference from XML layout
    mCLayout = findViewById(R.id.coordinator_layout);
    Button mButtonDo = findViewById(R.id.btn_do);
    mLLayout = findViewById(R.id.ll);

    //-------------------set image--------------------------
    ImageView setImage = findViewById(R.id.setImage);
    // Initialize ContextWrapper
    wrapper = new ContextWrapper(getApplicationContext());
    file = wrapper.getDir("Images",MODE_PRIVATE);
    file = new File(file, "I_20.jpg");

    if(file.exists()) {
        Bitmap myBitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
        setImage.setImageBitmap(myBitmap);
    }
    //-------------------set image--------------------------

    // Initialize the progress dialog
    mProgressDialog = new ProgressDialog(mActivity);
    mProgressDialog.setIndeterminate(false);
    // Progress dialog horizontal style
    mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    // Progress dialog title
    mProgressDialog.setTitle("AsyncTask");
    // Progress dialog message
    mProgressDialog.setMessage("Please wait, we are downloading your image files...");
    mProgressDialog.setCancelable(true);

    // Set a progress dialog dismiss listener
    mProgressDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
        @Override
        public void onDismiss(DialogInterface dialogInterface) {
            // Cancel the AsyncTask
            mMyTask.cancel(false);
        }
    });

    // Initialize a new click listener for positive button widget
    mButtonDo.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            // Execute the async task
            mMyTask = new DownloadTask().execute(URLS);
        }
    });
}

/*
 * First parameter URL for doInBackground
 * Second parameter Integer for onProgressUpdate
 * Third parameter List<Bitmap> for onPostExecute
 */
@SuppressLint("StaticFieldLeak")
private class DownloadTask extends AsyncTask<URL,Integer,List<Bitmap>>{
    // Before the tasks execution
    protected void onPreExecute(){
        // Display the progress dialog on async task start
        mProgressDialog.show();
        mProgressDialog.setProgress(0);
    }

    // Do the task in background/non UI thread
    protected List<Bitmap> doInBackground(URL...urls){
        Log.d("doInBackground", "doInBackground: ");
        count = urls.length;
        //URL url = urls[0];
        HttpURLConnection connection = null;
        List<Bitmap> bitmaps = new ArrayList<>();

        // Loop through the urls
        for(int i=0;i<count;i++){
            URL currentURL = urls[i];
            // So download the image from this url
            try{
                // Initialize a new http url connection
                connection = (HttpURLConnection) currentURL.openConnection();

                // Connect the http url connection
                connection.connect();

                // Get the input stream from http url connection
                InputStream inputStream = connection.getInputStream();

                // Initialize a new BufferedInputStream from InputStream
                BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);

                // Convert BufferedInputStream to Bitmap object
                Bitmap bmp = BitmapFactory.decodeStream(bufferedInputStream);

                // Add the bitmap to list
                bitmaps.add(bmp);
                // add the url to list URL
                imageName.add(currentURL);

                // Publish the async task progress
                // Added 1, because index start from 0
                publishProgress((int) (((i+1) / (float) count) * 100));
                if(isCancelled()){
                    break;
                }

            }catch(IOException e){
                e.printStackTrace();
            }finally{
                // Disconnect the http url connection
                assert connection != null;
                connection.disconnect();
            }
        }
        // Return bitmap list
        return bitmaps;
    }

    // On progress update
    protected void onProgressUpdate(Integer... progress){
        // Update the progress bar
        mProgressDialog.setProgress(progress[0]);
    }

    // On AsyncTask cancelled
    protected void onCancelled(){
        Snackbar.make(mCLayout,"Task Cancelled.",Snackbar.LENGTH_LONG).show();
    }

    // When all async task done
    protected void onPostExecute(List<Bitmap> result){
        // Hide the progress dialog
        mProgressDialog.dismiss();

        // Remove all views from linear layout
        mLLayout.removeAllViews();

        Log.d("result", String.valueOf(result));

        // Loop through the bitmap list
        for(int i=0;i<result.size();i++){
            Bitmap bitmap = result.get(i);
            // Save the bitmap to internal storage
            Uri imageInternalUri = saveImageToInternalStorage(bitmap, i);
            // Display the bitmap from memory
            addNewImageViewToLayout(bitmap);
            // Display bitmap from internal storage
//                addNewImageViewToLayout(imageInternalUri);
        }
    }
}

// Custom method to convert string to url
protected URL stringToURL(String urlString){
    try{
        return new URL(urlString);
    }catch(MalformedURLException e){
        e.printStackTrace();
    }
    return null;
}

// Custom method to save a bitmap into internal storage
protected Uri saveImageToInternalStorage(Bitmap bitmap, int index){

    Log.d("count", String.valueOf(count));

    // Initializing a new file
    // The bellow line return a directory in internal storage
    file = wrapper.getDir("Images",MODE_PRIVATE);

    // Create a file to save the image
    // First get name of image from url, and then saved with that name
    file = new File(file, getFileNameFromUrl(imageName.get(index)));

    Log.d("TAG", String.valueOf(file));

    try{
        // Initialize a new OutputStream
        OutputStream stream;

        // If the output file exists, it can be replaced or appended to it
        stream = new FileOutputStream(file);

        // Compress the bitmap
        bitmap.compress(Bitmap.CompressFormat.JPEG,100,stream);

        // Flushes the stream
        stream.flush();

        // Closes the stream
        stream.close();

    }catch (IOException e) // Catch the exception
    {
        e.printStackTrace();
    }

    // Parse the gallery image url to uri
    // Return the saved image Uri
    return Uri.parse(file.getAbsolutePath());
}

/**
 * This function will take an URL as input and return the file name.
 * Examples :
 * http://example.com/a/b/c/test.txt -> test.txt
 * http://example.com/ -> an empty string
 * http://example.com/test.txt?param=value -> test.txt
 * http://example.com/test.txt#anchor -> test.txt
 *
 * @param url The input URL
 * @return The URL file name
 */
public static String getFileNameFromUrl(URL url) {
    // String file
    String urlString = url.getFile();
    // Return image name
    return urlString.substring(urlString.lastIndexOf('/') + 1).split("\?")[0].split("#")[0];
}

// Custom method to add a new image view using bitmap
protected void addNewImageViewToLayout(Bitmap bitmap){
    // Initialize a new ImageView widget
    ImageView iv = new ImageView(getApplicationContext());

    // Set an image for ImageView
    iv.setImageBitmap(bitmap);

    // Create layout parameters for ImageView
    LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, 500);

    // Add layout parameters to ImageView
    iv.setLayoutParams(lp);

    // Finally, add the ImageView to layout
    mLLayout.addView(iv);
}

// Custom method to add a new image view using uri
protected void addNewImageViewToLayout(Uri uri){
    // Initialize a new ImageView widget
    ImageView iv = new ImageView(getApplicationContext());

    // Set an image for ImageView
    iv.setImageURI(uri);

    // Create layout parameters for ImageView
    LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, 300);

    // Add layout parameters to ImageView
    iv.setLayoutParams(lp);

    // Finally, add the ImageView to layout
    mLLayout.addView(iv);
}

我的目标是这样,因为我出错了,Clamp target GC heap我认为问题是BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);因为很多图像。

非常感谢

使用DownloadManager下载多张图片

 public static void downloadFile(String uRl, Context context) {
        File myDir = new File(Environment.getExternalStorageDirectory(), "MyApp/");
        if (!myDir.exists()) {
            myDir.mkdirs();
        }

        DownloadManager mgr = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);

        Uri downloadUri = Uri.parse(uRl);
        DownloadManager.Request request = new DownloadManager.Request(
                downloadUri);

        request.setAllowedNetworkTypes(
                DownloadManager.Request.NETWORK_WIFI
                        | DownloadManager.Request.NETWORK_MOBILE).setAllowedOverMetered(true)
                .setAllowedOverRoaming(true).setTitle("Myapp - " + "Downloading " + uRl).
                setVisibleInDownloadsUi(true)
                .setDestinationInExternalPublicDir("MyApp" + "/", uRl);

        mgr.enqueue(request);

    }

Usage:-

     // Initialize a new click listener for positive button widget
    mButtonDo.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            // Execute the async task
           // mMyTask = new DownloadTask().execute(URLS);
           for (int i = 0; i < URLS .size(); i++) {                   
                         downloadFile(urls[i],Activityname.this);
                   }
        }
    });

要更改路径,请编辑此

File myDir = new File(Environment.getExternalStorageDirectory(), "MyApp/");