【问题标题】:Download images with AsyncTask使用 AsyncTask 下载图像
【发布时间】:2012-12-21 02:30:49
【问题描述】:

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

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

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

次要问题:应用下载图片时弹出进度条,但进度条没有更新进度。它只是保持 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 里面运行它。但是我还能在哪里进行检查?知道如何作为错误消息返回并请求用户重试而不是使应用程序崩溃吗?

【问题讨论】:

  • 我没有遇到任何错误。
  • 哦,关于那个我拿出了一些 Log.i 和问题中的其他服务器内容。因此,获得您想看到的 Log.i 可能有点困难。我只是展示我遇到问题的部分。
  • 我添加了应该做什么的示例代码。
  • 接受您的编辑并提出另一个问题。这是一个不同的主题。

标签: android download android-asynctask progress-bar


【解决方案1】:

您在doInBackGround(...) 期间从未致电onProgressUpdate。请注意,运行多个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 实例,然后调用onProgressUpdate()

【讨论】:

  • 感谢您的解释和回答。很快就会尝试这个,一旦我尝试了就会更新你。
  • 成功了。谢谢你的回答,我编辑了这个问题。我还有一件事想问。你去那里看看可以吗?
【解决方案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 实例不是一个好主意,所以一个接一个。您可以使用 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()

【讨论】:

  • 但是如何声明下载未完成呢?因为现在一旦下载到一半没有连接,我的应用程序就会直接崩溃。
  • 同上一个问题,谢谢您的信息!
  • @IssacZH。开始时设置 downloadComplete = 0。下载完成后,将调用 onPostExecute()。设置 downloadComplete = 1。使用 CountDownTimer 类和 onFinish() 方法,检查布尔值,如果为 false,则抛出 toast/dialog 下载未完成。
  • @IssacZH。作为您的评论,我已经更新了我的答案。请查看编辑部分。
  • 但是如果下载不完整会崩溃。它在崩溃之前还会通过 onPostExecute() 吗?因为下载还没有完成。
【解决方案3】:

在下面一行:

SetConstant.CONTENT_ID = contentId[i];

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

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

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

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

【讨论】:

  • 所以这意味着我应该先将所有的 Url 存储在一个变量中,然后只使用该变量执行 AsyncTask?
  • 执行 AsyncTask.onProgressUpdate(...);在 UI 线程上运行?你为什么需要 Handler 呢?
  • @Sofi Software LLC 感谢您的解释。逻辑上我明白你的意思。
  • 有几种方法可以做到这一点。您可以创建一个具有匹配的 url 和文件和/或内容 ID 的小数据类,并列出您要处理的所有内容,并将其放入一个异步任务中。或者你可以让每个 asynctask 处理一个 url/file/content id 并启动多个 asynctask。
【解决方案4】:

首先创建一个单独的类,允许您访问图像地址

如下:

公共类 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 ==> deletedImg = (ImageView) findViewById(R.id.imageView); 2 - 通过用户界面中的按钮链接您创建的方法 ==> (public void downloadImage(View view){}) 3 - 在清单文件中请求许可

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-02-20
    • 1970-01-01
    • 2012-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多