使用AsyncTask下载图像

时间:2012-12-21 02:30:50

标签: android download android-asynctask progress-bar

我不确定我的代码或结构出了什么问题。我想使用AsyncTask下载图像并同时显示进度条。但我尝试了一些不同的方法。它仍然失败,不知道它有什么问题。我的结构流程是

ContentID是一个字符串数组,用于存储图像的内容ID。

主要问题:它设法从网址下载图片并存储到手机中,但下载的图片都是相同的图片。应该是不同的图像,这不是我的预期。

次要问题:应用程序下载图像时会弹出进度条,但进度条没有更新它的进度。它只是保持0%并在下载完成后被解雇。

我想知道是什么原因导致了我提到的主要问题和第二问题。如果您可能知道我的代码有什么问题,请发表评论或回答。任何帮助将不胜感激。

if(isSyncSuccess){

     SetConstant.IMAGE_EXIST = 1;
     pDialog = new ProgressDialog(GalleryScreen.this);
     pDialog.setMessage("Downloading file. Please wait...");
     pDialog.setIndeterminate(false);
     pDialog.setProgress(0);
     pDialog.setMax(contentId.length);
     pDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
     pDialog.setCancelable(true);


     if (contentId.length>0){
     Log.i(TAG, "contentid.length:" +contentId.length);
         for (int i=0;i<contentId.length;i++){
             if(helper.databaseChecking(useremail, contentId[i])){
                 contentdownload = i;
                 SetConstant.CONTENT_ID = contentId[i]; 

                 String URL = SetConstant.URL_DOWNLOAD_CONTENT+contentId[i];

                 DownloadFile downloadFile = new DownloadFile();
                 downloadFile.execute(URL);


                 }



    private class DownloadFile extends AsyncTask<String, Integer, String>{
    @Override
    protected String doInBackground(String... sUrl){
                Bitmap bm;
                InputStream in;

        try{

            in = new java.net.URL(sUrl[0]).openStream();
            bm = BitmapFactory.decodeStream(new PatchInputStream(in));
            File storage = new File(Environment.getExternalStorageDirectory() + File.separator + "/Image/");
            Log.i(TAG,"storage:" +storage);
            Log.i(TAG,"storage:" +storage.getAbsolutePath());
            if(!storage.exists()){
                storage.mkdirs();

            }
                String FileName = "/"+SetConstant.CONTENT_ID+".jpg"; 
                FileOutputStream fos = new FileOutputStream(storage + FileName);
                bm.compress(Bitmap.CompressFormat.JPEG, 85, fos);

                String filepath = storage + FileName;
                File filecheck = new File (filepath);
                long fileSize = filecheck.length();
                fos.flush();
                fos.close();

                Log.i(TAG, "bm:" +bm);
                Log.i(TAG, "fos:" +fos);
                Log.i(TAG, "filesize:" +fileSize);
                Log.i(TAG, "filepath:" +filepath);


        }
        catch(IOException e1){
                e1.printStackTrace();
                }   

        return null;
    }

    @Override
    protected void onPreExecute(){
        super.onPreExecute();
        pDialog.show();
    }

    @Override
    protected void onProgressUpdate(Integer... progress){
        super.onProgressUpdate(progress);
        pDialog.setProgress(progress[0]);
    }

    protected void onPostExecute(String result){
        super.onPostExecute(result);
        pDialog.dismiss();
    }
}

修改

现在应用程序可以根据进度条下载图像了!但我得到的另一个问题是当应用程序无法完成下载时如何返回错误消息。目前,当应用程序无法下载时,它将崩溃。我相信我不应该在doInBackground端运行它。但我还能在哪里进行检查?知道如何作为错误消息返回并请求用户重试而不是崩溃应用程序?

4 个答案:

答案 0 :(得分:5)

您在onProgressUpdate期间从未致电doInBackGround(...)。请注意,运行AsyncTask的多个实例是bad idea。以下是我的建议:

if(isSyncSuccess){
    SetConstant.IMAGE_EXIST=1;
    pDialog=new ProgressDialog(GalleryScreen.this);
    pDialog.setMessage("Downloading file. Please wait...");
    pDialog.setIndeterminate(false);
    pDialog.setProgress(0);
    pDialog.setMax(contentId.length);
    pDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    pDialog.setCancelable(true);

    new DownloadFile().execute();
}

private class DownloadFiles extends AsyncTask<String, Integer, String> {
    @Override
    protected String doInBackground(String... sUrl) {
        Bitmap bm;
        InputStream in;

        if (contentId.length > 0) {
            for (int i = 0; i < contentId.length; i++) {
                if (helper.databaseChecking(useremail, contentId[i])) {
                    contentdownload = i;
                    SetConstant.CONTENT_ID = contentId[i];

                    String URL = SetConstant.URL_DOWNLOAD_CONTENT + contentId[i];
                    //YOUR INTRESTING LOOP HERE.
                    publishProgress(30);
                    //SOME INTRESTING NUMBER FOR PROGRESS UPDATE
                }
            }

            try {
                in = new java.net.URL(sUrl[0]).openStream();
                bm = BitmapFactory.decodeStream(new PatchInputStream(in));
                File storage = new File(Environment.getExternalStorageDirectory() + File.separator + "/Image/");
                Log.i(TAG, "storage:" + storage);
                Log.i(TAG, "storage:" + storage.getAbsolutePath());
                if (!storage.exists()) {
                    storage.mkdirs();

                }
                String FileName = "/" + SetConstant.CONTENT_ID + ".jpg";
                FileOutputStream fos = new FileOutputStream(storage + FileName);
                bm.compress(Bitmap.CompressFormat.JPEG, 85, fos);

                String filepath = storage + FileName;
                File filecheck = new File(filepath);
                long fileSize = filecheck.length();
                fos.flush();
                fos.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }

            return null;
        }

        @Override
        protected void onPreExecute () {
            super.onPreExecute();
            pDialog.show();
        }

        @Override
        protected void onProgressUpdate (Integer...progress){
            super.onProgressUpdate(progress);
            pDialog.setProgress(progress[0]);
        }

        protected void onPostExecute (String result){
            super.onPostExecute(result);
            pDialog.dismiss();
        }
    }
}

当然,此代码不会运行,您需要修复范围。但我想建议的是,您的循环应该在doInBackGround(...)中,在这种情况下,您应该在给定时间只有AsyncTask的1个实例,并调用onProgressUpdate()

答案 1 :(得分:2)

在以下行中:

SetConstant.CONTENT_ID = contentId[i];

您正在将全局变量设置为值,然后基于该相同值创建字符串URL并将其传递给AsyncTask。执行,然后在完成下载时,它会创建一个名称基于全局变量SetConstant.CONTENT_ID的文件。

换句话说,您正在另一个线程中使用一个全局变量,其值由主线程更改。不要这样做,因为在不同的时间更新不同的线程会导致各种奇怪的问题。将输出文件的值或名称传递给AsyncTask。您可以在DownloadFile的构造函数中执行此操作,并将值存储在字段中。

如果您想要更新进度条,则必须更新其值;它不会更新自己。在任务期间(在doInBackground中)调用AsyncTask.publishProgress并实现onProgressUpdate以更新进度对话框。

[编辑:onProgressUpdate确实在UI线程中调用。]

答案 2 :(得分:2)

主要问题:

SetConstant.CONTENT_ID = contentId[i]; 
String URL = SetConstant.URL_DOWNLOAD_CONTENT+contentId[i];

在这里,你面临着麻烦。作为@Sofi Software LLC的回答,您正在使用一个全局变量,其值由主线程在另一个线程中更改。

次要问题:

  • 如果要更新进度条,则必须更新其值;
    它没有自我更新。

您需要在AsyncTask中下载图像(从URL下载)。有效地实现您的功能,您需要做

  • 创建AsyncTask以下载您的图像(实现下载) doInBackground()),也有一个布尔值(比如isImageDownloaded)来 跟踪是否在postExecute()中成功下载了图像。
  • 在开始之前不要忘记显示进度条 下载
  • 执行AsyncTask以启动下载
  • 创建android.os.CountDownTimer扩展名至少倒计时 时间
  • 在方法onFinish()上检查您跟踪的布尔值(如果是) false然后取消AsyncTask并抛出toast / dialog
  • 运行AsyncTask的multipule实例并不是一个好主意,所以要一个接一个地做。您可以使用executeOnExecutor()在Executor上执行AsyncTask。要确保线程以串行方式运行,请使用:SERIAL_EXECUTOR。

以下资源可以帮助您

如果您需要下载图像,请显示进度条并加载图像视图

如果您需要使用AsyncTask

下载多个文件(此处为图像)

修改

来自http://developer.aiwgame.com/imageview-show-image-from-url-on-android-4-0.html

new DownloadImageTask((ImageView) findViewById(R.id.imageView1))
            .execute("http://java.sogeti.nl/JavaBlog/wp-content/uploads/2009/04/android_icon_256.png"); }

public void onClick(View v) {
    startActivity(new Intent(this, IndexActivity.class));
    finish();

}

private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
    ImageView bmImage;

    public DownloadImageTask(ImageView bmImage) {
        this.bmImage = bmImage;
    }

    protected Bitmap doInBackground(String... urls) {
        String urldisplay = urls[0];
        Bitmap mIcon11 = null;
        try {
            InputStream in = new java.net.URL(urldisplay).openStream();
            mIcon11 = BitmapFactory.decodeStream(in);
        } catch (Exception e) {
            Log.e("Error", e.getMessage());
            e.printStackTrace();
        }
        return mIcon11;
    }

    protected void onPostExecute(Bitmap result) {
        bmImage.setImageBitmap(result);
    } }

来自Image download in an Android ImageView and Progressbar implementation

 // note that you could also use other timer related class in Android aside from this CountDownTimer, I prefer this class because I could do something on every interval basis
            // tick every 10 secs (or what you think is necessary)
            CountDownTimer timer = new CountDownTimer(30000, 10000) {

                @Override
                public void onFinish() {
                    // check the boolean, if it is false, throw toast/dialog
                }

                @Override
                public void onTick(long millisUntilFinished) {
                    // you could alternatively update anything you want every tick of the interval that you specified
                }

            };

            timer.start()

答案 3 :(得分:1)

首先创建一个分隔的类,它允许您访问图像地址

如下:

public class ImageDownloader扩展了AsyncTask {

    @Override
    protected Bitmap doInBackground(String... urls) {

        try {

            URL url = new URL(urls[0]);

            HttpURLConnection connection = (HttpURLConnection) url.openConnection();

            connection.connect();

            InputStream inputStream = connection.getInputStream();

            Bitmap myBitmap = BitmapFactory.decodeStream(inputStream);

            return myBitmap;

        } catch (Exception e) {

            e.printStackTrace();

        }

        return null;
    }
}

然后通过创建对象并执行Bitmap任务来访问该类(通过按钮调用的方法),如下所示:

公共类MainActivity扩展了Activity {

ImageView downloadedImg;

public void downloadImage(View view) {

    ImageDownloader task = new ImageDownloader();
    Bitmap myImage;

    try {
        myImage = task.execute("YOUR IMAGE ADDRESS ........").get();

        downloadedImg.setImageBitmap(myImage);

    } catch (Exception e) {

        e.printStackTrace();
    }

}  

不要忘记: 1 - 在onCreat方法中定义imageView ==&gt; downloadedImg =(ImageView)findViewById(R.id.imageView); 2 - 通过用户界面中的按钮链接您创建的方法==&gt; (public void downloadImage(View view){}) 3 - 在清单文件中请求权限