androidimageandroid-asynctaskandroid-download-managerdownload-manager

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


I create app for download multi images, from url, the problem is when download all images (there's 3000 images) its multi process, not single process. Single process I mean download and then save, download and then save and so on. It's possible to download multi image with single process ?

this is my code :

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

my goal is to make it like this, because I got error, Clamp target GC heap I think the problem is BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream); because many images.

thanks a lot


Solution

  • Use DownloadManager to download multiple images

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

    To change path , edit this

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