使用 AsyncTask 加载图像时行为不一致

发布于 2024-10-04 19:28:33 字数 7236 浏览 6 评论 0原文

该应用程序的作用非常简单。它加载两个 RSS 源,并且在每个 RSS 源上,它包含两个带有标题、图像和链接的项目。然后它下载图像,将其保存到本地文件夹并显示它们。两个 RSS 提要和 4 个图像下载。

我使用 AsyncTask 来执行此操作。因此,调用两个 AsyncTasks 对象来加载两个 RSS feed,调用 4 个 AsyncTasks 来加载 4 个图像。当它尝试下载图像时会出现问题。对于第一次运行,效果很好。但如果我继续重新加载它们,有时 AsyncTask 不会执行任何操作。有时它无法读取输入流......非常奇怪。

使用 AsyncTask 是否缺少任何规则?

下面是我的代码片段。

public class TunesAppsWidgetProvider extends AppWidgetProvider {

private Intent taService = null;
private static boolean widgetEnabled = false;

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    taService = new Intent(context, UpdateService.class);
    context.startService(taService);
}

public static class UpdateService extends Service {


    @Override
    public void onStart(Intent intent, int startId) {
        Log.d(Constants.TAG, "Service: onStart()");
        Context context = getApplicationContext();
        mViews = new RemoteViews(context.getPackageName(), R.layout.tunesappswidget);

        thisWidget = new ComponentName(this, TunesAppsWidgetProvider.class);
        manager = AppWidgetManager.getInstance(this);

        buildFeedUpdate();

        this.stopSelf();
        Log.d(Constants.TAG, "Stop Service");
    }

    public void buildFeedUpdate() {
        Log.d(Constants.TAG, "buildFeedUpdate");
        Context context = getApplicationContext();

        feedParser_0 = new FeedParser(context, Constants.FEED_ID_0);
        feedParser_1 = new FeedParser(context, Constants.FEED_ID_1);

        feedTask_0 = new LoadFeedTask();
        feedTask_0.execute(
                new LoadFeedTask.Payload(
                        feedParser_0,
                        UpdateService.this
                )
        );

        feedTask_1 = new LoadFeedTask();
        feedTask_1.execute(
                new LoadFeedTask.Payload(
                        feedParser_1,
                        UpdateService.this
                )
        );
    }

    public void buildCoverUpdate(byte feedID, List<Message> feedRSS, String operator) {
        Context context = getApplicationContext();

        Log.d(Constants.TAG, "buildCoverUpdate: " + feedID);
        try {
            switch(feedID) {
                case Constants.FEED_ID_0:
                        coverImage_0 = new CoverImage(context, feedRSS.get(Constants.ITEM_IDX_0).getImageLink(), Constants.SLOT_0);

            coverImageTask_0 = new LoadCoverImageTask();
                        coverImageTask_0.execute(
                            new LoadCoverImageTask.Payload(
                                    coverImage_0,
                                    UpdateService.this
                            )
                        );

                        coverImage_1 = new CoverImage(context, feedRSS.get(Constants.ITEM_IDX_1).getImageLink(), Constants.SLOT_1);

                        coverImageTask_1 = new LoadCoverImageTask();
                            coverImageTask_1.execute(
                                new LoadCoverImageTask.Payload(
                                    coverImage_1,
                                    UpdateService.this
                                )
                        );
                    break;

                case Constants.FEED_ID_1:
                        coverImage_2 = new CoverImage(context, feedRSS.get(Constants.ITEM_IDX_0).getImageLink(), Constants.SLOT_2, operator);
                    coverImageTask_2 = new LoadCoverImageTask();
                        coverImageTask_2.execute(
                                new LoadCoverImageTask.Payload(
                                        coverImage_2,
                                        UpdateService.this
                                )
                        );

                        coverImage_3 = new CoverImage(context, feedRSS.get(Constants.ITEM_IDX_1).getImageLink(), Constants.SLOT_3, operator);
                        bm_3 = coverImage_3.getDefaultCoverImage();
                            coverImageTask_3 = new LoadCoverImageTask();
                            coverImageTask_3.execute(
                                new LoadCoverImageTask.Payload(
                                    coverImage_3,
                                    UpdateService.this
                                )
                        );
                    break;

                default:
                    break;
            }
        }
        catch(Exception e) {
            Log.d(Constants.TAG, "buildCoverUpdate: " + e.toString());
        }
    }

下面

的代码用于加载图像。有时,即使调用了“execute”,这个 doInBackground 也永远不会被调用。有时它会卡在'Bitmap bitmap = BitmapFactory.decodeStream(in)'这里并且永远不会逃脱。

    protected LoadCoverImageTask.Payload doInBackground(LoadCoverImageTask.Payload... param) {
    HttpURLConnection httpConn = null;
    InputStream in;
    File imageFile;
    FileOutputStream fos;
    int slotIdx = param[0].coverImage.getSlotIndex();
    System.setProperty("http.keepAlive", "false");

    try{
        URL fileURL = new URL(param[0].coverImage.getFileURL());
        httpConn = (HttpURLConnection) fileURL.openConnection();
        Log.d(Constants.TAG , "openConn: Slot " + slotIdx);

        httpConn.setConnectTimeout(10000);

        if(httpConn.getResponseCode() == HttpURLConnection.HTTP_OK) {
            Log.d(Constants.TAG , "200OK: Slot " + slotIdx + ": " + fileURL.toString());

            in = httpConn.getInputStream();
            imageFile = new File(param[0].coverImage.getFullFilePath());
            fos = new FileOutputStream(imageFile);

            try {
                Bitmap bitmap = BitmapFactory.decodeStream(in);
                Log.d(Constants.TAG , "200OK: Slot " + slotIdx + " decodeStream(in);");
                if(bitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos) == true) {
                    fos.flush();
                    fos.close();
                    in.close();
                    Log.d(Constants.TAG , "200OK-decodeOK: Slot " + slotIdx);
                    param[0].result = Constants.TRUE;
                }
                else {
                    fos.flush();
                    fos.close();
                    in.close();
                    Log.d(Constants.TAG , "200OK-decodeFail: Slot " + slotIdx);
                    param[0].result = Constants.FALSE;
                }
            }
            catch(NullPointerException e) {
                Log.d(Constants.TAG , "Slot " + slotIdx + ":" + e.toString());
                param[0].result = Constants.RETRY;
            }
        }
        else {
            Log.d(Constants.TAG , "Slot " + slotIdx + ":" + httpConn.getResponseCode());
            param[0].result = Constants.FALSE;
        }

    } catch(SocketTimeoutException e) {
        Log.d(Constants.TAG , "Time Out: " + slotIdx + ":" + e.toString());
    } catch(Exception e) {
        Log.d(Constants.TAG , "Slot " + slotIdx + ":" + e.toString());
        param[0].result = Constants.FALSE;
    }
    finally {
        if(httpConn != null) httpConn.disconnect();
        Log.d(Constants.TAG , "Slot " + slotIdx + ":httpConn.disconnect");
    }
    return param[0];
}

我被困在这个问题上几天了..请帮忙...

What the application does is very simple. It loads two RSS feeds and on each RSS feed, it contains two items with a title, an image and a link. And then it downloads the images, saves it on to local folder and display them. So two RSS feeds, and 4 images downloading.

I use AsyncTask to do this. So, two AsyncTasks objects are called to load two RSS feeds and 4 AsyncTasks to load 4 images. The problems happens when it tries to download images. For the first run, it works fine. but if I keep reloading them, sometimes AsyncTask doesn't do anything. And sometimes it fails to read inputstream... very weird.

Is there any rule that I am missing to use AsyncTask?

Below is the snippets of my code.

public class TunesAppsWidgetProvider extends AppWidgetProvider {

private Intent taService = null;
private static boolean widgetEnabled = false;

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    taService = new Intent(context, UpdateService.class);
    context.startService(taService);
}

public static class UpdateService extends Service {


    @Override
    public void onStart(Intent intent, int startId) {
        Log.d(Constants.TAG, "Service: onStart()");
        Context context = getApplicationContext();
        mViews = new RemoteViews(context.getPackageName(), R.layout.tunesappswidget);

        thisWidget = new ComponentName(this, TunesAppsWidgetProvider.class);
        manager = AppWidgetManager.getInstance(this);

        buildFeedUpdate();

        this.stopSelf();
        Log.d(Constants.TAG, "Stop Service");
    }

    public void buildFeedUpdate() {
        Log.d(Constants.TAG, "buildFeedUpdate");
        Context context = getApplicationContext();

        feedParser_0 = new FeedParser(context, Constants.FEED_ID_0);
        feedParser_1 = new FeedParser(context, Constants.FEED_ID_1);

        feedTask_0 = new LoadFeedTask();
        feedTask_0.execute(
                new LoadFeedTask.Payload(
                        feedParser_0,
                        UpdateService.this
                )
        );

        feedTask_1 = new LoadFeedTask();
        feedTask_1.execute(
                new LoadFeedTask.Payload(
                        feedParser_1,
                        UpdateService.this
                )
        );
    }

    public void buildCoverUpdate(byte feedID, List<Message> feedRSS, String operator) {
        Context context = getApplicationContext();

        Log.d(Constants.TAG, "buildCoverUpdate: " + feedID);
        try {
            switch(feedID) {
                case Constants.FEED_ID_0:
                        coverImage_0 = new CoverImage(context, feedRSS.get(Constants.ITEM_IDX_0).getImageLink(), Constants.SLOT_0);

            coverImageTask_0 = new LoadCoverImageTask();
                        coverImageTask_0.execute(
                            new LoadCoverImageTask.Payload(
                                    coverImage_0,
                                    UpdateService.this
                            )
                        );

                        coverImage_1 = new CoverImage(context, feedRSS.get(Constants.ITEM_IDX_1).getImageLink(), Constants.SLOT_1);

                        coverImageTask_1 = new LoadCoverImageTask();
                            coverImageTask_1.execute(
                                new LoadCoverImageTask.Payload(
                                    coverImage_1,
                                    UpdateService.this
                                )
                        );
                    break;

                case Constants.FEED_ID_1:
                        coverImage_2 = new CoverImage(context, feedRSS.get(Constants.ITEM_IDX_0).getImageLink(), Constants.SLOT_2, operator);
                    coverImageTask_2 = new LoadCoverImageTask();
                        coverImageTask_2.execute(
                                new LoadCoverImageTask.Payload(
                                        coverImage_2,
                                        UpdateService.this
                                )
                        );

                        coverImage_3 = new CoverImage(context, feedRSS.get(Constants.ITEM_IDX_1).getImageLink(), Constants.SLOT_3, operator);
                        bm_3 = coverImage_3.getDefaultCoverImage();
                            coverImageTask_3 = new LoadCoverImageTask();
                            coverImageTask_3.execute(
                                new LoadCoverImageTask.Payload(
                                    coverImage_3,
                                    UpdateService.this
                                )
                        );
                    break;

                default:
                    break;
            }
        }
        catch(Exception e) {
            Log.d(Constants.TAG, "buildCoverUpdate: " + e.toString());
        }
    }

}

And below code is for loading image. Sometimes this doInBackground never being called even though 'execute' is called. Sometimes it's stuck on 'Bitmap bitmap = BitmapFactory.decodeStream(in)' here and never escape.

    protected LoadCoverImageTask.Payload doInBackground(LoadCoverImageTask.Payload... param) {
    HttpURLConnection httpConn = null;
    InputStream in;
    File imageFile;
    FileOutputStream fos;
    int slotIdx = param[0].coverImage.getSlotIndex();
    System.setProperty("http.keepAlive", "false");

    try{
        URL fileURL = new URL(param[0].coverImage.getFileURL());
        httpConn = (HttpURLConnection) fileURL.openConnection();
        Log.d(Constants.TAG , "openConn: Slot " + slotIdx);

        httpConn.setConnectTimeout(10000);

        if(httpConn.getResponseCode() == HttpURLConnection.HTTP_OK) {
            Log.d(Constants.TAG , "200OK: Slot " + slotIdx + ": " + fileURL.toString());

            in = httpConn.getInputStream();
            imageFile = new File(param[0].coverImage.getFullFilePath());
            fos = new FileOutputStream(imageFile);

            try {
                Bitmap bitmap = BitmapFactory.decodeStream(in);
                Log.d(Constants.TAG , "200OK: Slot " + slotIdx + " decodeStream(in);");
                if(bitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos) == true) {
                    fos.flush();
                    fos.close();
                    in.close();
                    Log.d(Constants.TAG , "200OK-decodeOK: Slot " + slotIdx);
                    param[0].result = Constants.TRUE;
                }
                else {
                    fos.flush();
                    fos.close();
                    in.close();
                    Log.d(Constants.TAG , "200OK-decodeFail: Slot " + slotIdx);
                    param[0].result = Constants.FALSE;
                }
            }
            catch(NullPointerException e) {
                Log.d(Constants.TAG , "Slot " + slotIdx + ":" + e.toString());
                param[0].result = Constants.RETRY;
            }
        }
        else {
            Log.d(Constants.TAG , "Slot " + slotIdx + ":" + httpConn.getResponseCode());
            param[0].result = Constants.FALSE;
        }

    } catch(SocketTimeoutException e) {
        Log.d(Constants.TAG , "Time Out: " + slotIdx + ":" + e.toString());
    } catch(Exception e) {
        Log.d(Constants.TAG , "Slot " + slotIdx + ":" + e.toString());
        param[0].result = Constants.FALSE;
    }
    finally {
        if(httpConn != null) httpConn.disconnect();
        Log.d(Constants.TAG , "Slot " + slotIdx + ":httpConn.disconnect");
    }
    return param[0];
}

I am stuck on this for a couple of days.. please help...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

旧时模样 2024-10-11 19:28:33

也许问题不在你的代码中。 BitmapFactory.decodeStream 中存在一个错误,如果您通过 http 连接使用 InputStream,有时无法很好地加载图像。

请参阅 http://code.google.com/p/android/issues /detail?id=6066 了解更多信息

对我有用的简单解决方案是将整个内容数据下载到缓冲区中,然后
使用 BitmapFactory.decodeByteArray 方法:

InputStream is = httpCon.getInputStream();
byte [] content = inputStreamToByteArray2(is);
image = BitmapFactory.decodeByteArray(content, 0, content.length);


public static final byte[] inputStreamToByteArray(InputStream is) throws IOException {
    BufferedInputStream bis = new BufferedInputStream(is);
    ByteArrayOutputStream buf = new ByteArrayOutputStream();
    int result = bis.read();
    while(result !=-1) {
        byte b = (byte)result;
        buf.write(b);
        result = bis.read();
    }
    return buf.toByteArray();
}

或者如果您不想按 1 个字节读取:

public static final byte[] inputStreamToByteArray(InputStream is) throws IOException {
    BufferedInputStream bis = new BufferedInputStream(is);
    ByteArrayOutputStream buf = new ByteArrayOutputStream();
    byte[] buffer = new byte[256];
    int result = bis.read(buffer);
    while(result > 0) {
        buf.write(buffer, 0, result);
        result = bis.read(buffer);
    }
    return buf.toByteArray();
}

Maybe the problem is not in your code. There is a bug in BitmapFactory.decodeStream, and if you use InputStream from http connection, it sometimes doesn't load the image well.

Look at http://code.google.com/p/android/issues/detail?id=6066 for more information

Simple solution that works for me is downloading a whole content data into buffer and then
using BitmapFactory.decodeByteArray method:

InputStream is = httpCon.getInputStream();
byte [] content = inputStreamToByteArray2(is);
image = BitmapFactory.decodeByteArray(content, 0, content.length);


public static final byte[] inputStreamToByteArray(InputStream is) throws IOException {
    BufferedInputStream bis = new BufferedInputStream(is);
    ByteArrayOutputStream buf = new ByteArrayOutputStream();
    int result = bis.read();
    while(result !=-1) {
        byte b = (byte)result;
        buf.write(b);
        result = bis.read();
    }
    return buf.toByteArray();
}

or if you don't want to read by 1 byte:

public static final byte[] inputStreamToByteArray(InputStream is) throws IOException {
    BufferedInputStream bis = new BufferedInputStream(is);
    ByteArrayOutputStream buf = new ByteArrayOutputStream();
    byte[] buffer = new byte[256];
    int result = bis.read(buffer);
    while(result > 0) {
        buf.write(buffer, 0, result);
        result = bis.read(buffer);
    }
    return buf.toByteArray();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文