Использование AsyncTask для загрузки изображений в ListView в AppWidget

Я пытаюсь адаптировать шаблон из Google I/O, используя AsyncTask для загрузки изображений из сети и размещения их в элементах ListView в AppWidget. Я не нашел много ресурсов на такие вещи, кроме этого поста.

Проблема в том, что у постера не было представления коллекции, только один элемент. Когда я пытаюсь следовать этому шаблону, весь appwidget обновляется только одним элементом списка каждый раз, когда запускается onPostExecute(), а не тем, что мне нужно. Если вы удалите вызов updateAppWidget() в onPostExecute(), представления не будут обновлены, я полагаю, из-за межпроцессного взаимодействия, которое должно произойти. Я не совсем уверен, куда идти отсюда, кто-нибудь может помочь?

Вот мое определение AsyncTask:

public ThumbnailAsyncTask(RemoteViews rv, int appWidgetID, AppWidgetManager appWidgetManager)
{
    mTarget = rv;
    this.widgetID = appWidgetID;
    this.widgetManager = appWidgetManager;  
}

@Override
protected Bitmap doInBackground(String... params)
{
    String url = params[0];
    return getBitmapFromURL(url);
}

@Override
protected void onPostExecute(Bitmap result)
{
    mTarget.setImageViewBitmap(R.id.thumbnail, result);
    widgetManager.updateAppWidget(widgetID, mTarget);
}

private Bitmap getBitmapFromURL(String str)
{
    Bitmap bmp = null;
    HttpURLConnection connection = null;

    try
    {
        URL url = new URL(str);
        connection = openConnectionWithTimeout(url);
        bmp = BitmapFactory.decodeStream(connection.getInputStream());
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }
    finally
    {
        connection.disconnect();
    }
    return bmp;
}
}

и getViewAt() из RemoteViewsFactory:

public RemoteViews getViewAt(int position)
{
    RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.list_item);
    ArrayList<ResultDetails> mResults = mJSONParser.getResults();

    if (mResults.get(position).hasHeading())
        rv.setTextViewText(R.id.title, mResults.get(position).getHeading());
    if (mResults.get(position).hasBody())
        rv.setTextViewText(R.id.description, mResults.get(position).getBody(true));
    if (mResults.get(position).hasTimestamp())
        rv.setTextViewText(R.id.date, mResults.get(position).getTimestamp(true));

    Bundle extras = new Bundle();
    extras.putString(LINK_ITEM, mResults.get(position).getExternalURL());
    Intent fillInIntent = new Intent();
    fillInIntent.putExtras(extras);
    rv.setOnClickFillInIntent(R.id.list_item, fillInIntent);

    if (mResults.get(position).hasThumbnailURL())
    {
        AppWidgetManager mgr = AppWidgetManager.getInstance(mContext);
        new ThumbnailAsyncTask(rv, mAppWidgetId, mgr).execute(mResults.get(position).getThumbnailURL());
    }

    return rv;
}

2 ответа

Решение

Я не был доволен длительным временем загрузки, поэтому я нашел способ быстро загрузить изображение-заполнитель, а затем загрузить миниатюры в AsyncTask, а затем один раз вызвать notifyAppWidgetViewDataChanged(), чтобы обновить appwidget после того, как все они будут загружены. Это приводит к мгновенному появлению данных без изображений и является довольно хорошим решением для моего приложения. Я использовал логическое значение в RemoteViewsFactory, чтобы указать, что я уже загрузил данные без изображений, чтобы они не застревали в бесконечном цикле обновления.

class ThumbnailAsyncTask extends AsyncTask<Void, Void, Void>
{
private AppWidgetManager widgetManager;
private List<ResultDetails> details;
private Context context;

public ThumbnailAsyncTask(AppWidgetManager
        appWidgetManager, List<ResultDetails> details, Context context)
{
    this.details = details;
    this.context = context;
    this.widgetManager = appWidgetManager;
}

@Override
protected Void doInBackground(Void... params)
{
    for (ResultDetails item : details)
    {
        if (item.hasThumbnailURL())
        {
            item.setThumbnail(getBitmapFromURL(item.getThumbnailURL()));
        }
    }
    return null;
}
@Override
protected void onPostExecute(Void result)
{
    widgetManager.notifyAppWidgetViewDataChanged(widgetManager.getAppWidgetIds(
                        new ComponentName(context, WidgetProvider.class)), R.id.list_view);

}

public RemoteViews getViewAt(int position)
{
    RemoteViews rv;
    rv = new RemoteViews(mContext.getPackageName(), R.layout.list_item);
    ArrayList<ResultDetails> mResults = mSearchResultsGenerator.getResults();
    ResultDetails result = mResults.get(position);

    if (result.hasHeading())
        rv.setTextViewText(R.id.title, result.getHeading());
    if (result.hasBody())
        rv.setTextViewText(R.id.description, result.getBody(true));
    if (result.hasTimestamp())
        rv.setTextViewText(R.id.date, result.getTimestamp(true));
    if (result.hasPrice())
        rv.setTextViewText(R.id.price, result.getPrice());

    Bundle extras = new Bundle();
    extras.putString(LINK_ITEM, result.getExternalURL());
    Intent fillInIntent = new Intent();
    fillInIntent.putExtras(extras);
    rv.setOnClickFillInIntent(R.id.list_item, fillInIntent);

    if (result.hasThumbnail())
    {
        rv.setImageViewBitmap(R.id.thumbnail, result.getThumbnail());
    }
    else
    {
        rv.setImageViewBitmap(R.id.thumbnail, noImageBitmap);
    }

    return rv;
}
public void onDataSetChanged()
{
    if (isOnline(mContext))
    {
        if (!hasData)
        {
            mSearchResultsGenerator.generate();
            if (mSearchResultsGenerator.isUpdateSucceeded())
            {
                AppWidgetManager mgr = AppWidgetManager.getInstance(mContext);
                hasData = true;
                new ThumbnailAsyncTask(mgr, mSearchResultsGenerator.getResults(), mContext).execute();
            }
            else
                makeNoConnectionToast();
        }
        else
        {

        }
    }
    else
        makeNoConnectionToast();
}

Я считаю, что вам нужно позвонить AppWidgetManager.notifyAppWidgetViewDataChanged() обновить представления коллекции в AppWidget

Другие вопросы по тегам