如何在单个过程中从URL下载多个图像?

3
我是一位有用的助手,可以为您翻译文本。
我创建了一个应用程序,用于从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);,因为有许多图片。
非常感谢。

抱歉,什么是下载管理器?谢谢。 - Abed Putra
请检查我的答案。 - Quick learner
请查看此链接:https://stackoverflow.com/questions/53199862/android-how-to-download-a-large-nos-of-images-large-nos-of-http-url-in-backg/53204264#53204264 - Farman Ali Khan
@Quicklearner 谢谢你的回答。我会尝试它。 - Abed Putra
@Farman Ali Khan 谢谢,让我检查一下! - Abed Putra
显示剩余2条评论
1个回答

4
使用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);

    }

使用方法:

     // 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/");

谢谢,我会实现你的代码并告诉你结果。 - Abed Putra
有一个问题,下载管理器是否可以添加授权HTTP头? - Abed Putra
谢谢,但我需要为我的HTTP连接实现授权头Authorization。这可能吗? - Abed Putra
谢谢,它有效了...如果您有关于头文件的任何信息,请告诉我..谢谢 - Abed Putra
好的,可以请您提供想要在下载管理器中添加的标题参数名称。 - Quick learner
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接