从 AsyncTask 填充 ListView 的 Android 小部件

Posted

技术标签:

【中文标题】从 AsyncTask 填充 ListView 的 Android 小部件【英文标题】:Android Widget with ListView populated from AsyncTask 【发布时间】:2018-03-25 22:34:28 【问题描述】:

我正在为我的应用程序创建一个小部件,但是当我必须填充列表视图时我被卡住了。我使用我在 WidgetDataProvider(实现 RemoteViewsService.RemoteViewsFactory)的 onCreate() 中调用的 asynctask 从我的 web db 中获取每个项目。 问题是,通常当我创建小部件时,它不会填充列表,我必须等待几秒钟才能在主屏幕中释放小部件。

如果我抓住并释放小部件,它会如下所示:empty widget

如果我等待,它会像这样显示:right widget

这是我的代码:

AppWidget

public class AppWidget extends AppWidgetProvider 
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) 
    RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.app_widget);

    Intent intent = new Intent(context, LoginActivity.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
    views.setOnClickPendingIntent(R.id.widget_title, pendingIntent);

    views.setRemoteAdapter(R.id.widget_listView, new Intent(context, WidgetService.class));
    appWidgetManager.updateAppWidget(appWidgetId, views);


@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) 
    super.onUpdate(context, appWidgetManager, appWidgetIds);
    for (int appWidgetId : appWidgetIds) 
        updateAppWidget(context, appWidgetManager, appWidgetId);
    


@Override
public void onEnabled(Context context) 


@Override
public void onDisabled(Context context) 

**WidgetService **

public class WidgetService extends RemoteViewsService 
@Override
public RemoteViewsFactory onGetViewFactory(Intent intent) 
    return new WidgetDataRemote(this, intent);

WidgetDataRemote

public class WidgetDataRemoteimplements RemoteViewsService.RemoteViewsFactory 
Context context;
Intent intent;
ArrayList<String> date = new ArrayList<>();
ArrayList<String> subj = new ArrayList<>();
ArrayList<String> type = new ArrayList<>();
ArrayList<String> comment = new ArrayList<>();
JSONParser jsonParser = new JSONParser();
ArrayList<String> subjFromDb = new ArrayList<>();
int pippo = 0;

public WidgetDataRemote(Context context, Intent intent) 
    this.context = context;
    this.intent = intent;


@Override
public RemoteViews getViewAt(int position) 
    RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.item_widget);
    remoteViews.setTextViewText(R.id.task_data, date.get(position));
    remoteViews.setTextViewText(R.id.task_subject, subj.get(position));
    remoteViews.setTextViewText(R.id.task_type, type.get(position));
    remoteViews.setTextViewText(R.id.task_comment, comment.get(position));
    return remoteViews;


@Override
public void onCreate() 
    new LoadSubjects().execute();


@Override
public void onDataSetChanged() 


@Override
public void onDestroy() 
    date.clear();
    subj.clear();
    type.clear();
    comment.clear();


@Override
public int getCount() 
    return date.size();


@Override
public RemoteViews getLoadingView() 
    return null;


@Override
public int getViewTypeCount() 
    return 1;


@Override
public long getItemId(int id) 
    return id;


@Override
public boolean hasStableIds() 
    return true;


class LoadSubjects extends AsyncTask<String, String, String> 
    @Override
    protected void onPreExecute() 
        super.onPreExecute();
        subjFromDb.clear();
        pippo = 0;
    

    @Override
    protected String doInBackground(String... args) 
        List<NameValuePair> params = new ArrayList<>();
        params.add(new BasicNameValuePair("class", User.getClasse()));
        JSONArray json = jsonParser.makeHttpRequestArray(Constants.URL_LOAD_SUBJECTS, "POST", params);
        try 
            if (!json.toString().equals("[null]")) 
                for (int i = 0; i < json.length(); i++) 
                    JSONObject c = json.getJSONObject(i);
                    String subj = c.getString(Constants.TAG_NAME);
                    subjFromDb.add(subj);
                
             else 
                pippo = 1;
            
         catch (JSONException e) 
            e.printStackTrace();
        
        return null;
    

    protected void onPostExecute(String file_url) 
        if (pippo == 0) 
            new LoadTasks().execute();
        
    

    class LoadTasks extends AsyncTask<String, String, String> 
        @Override
        protected void onPreExecute() 
            super.onPreExecute();
            pippo = 0;
        

        @Override
        protected String doInBackground(String... args) 
            List<NameValuePair> params = new ArrayList<>();
            params.add(new BasicNameValuePair("id_class", User.getClasse()));
            JSONArray json = jsonParser.makeHttpRequestArray(Constants.URL_LOAD_TASKS, "POST", params);
            try 
                if (!json.toString().equals("[null]")) 
                    for (int i = 0; i < json.length(); i++) 
                        JSONObject c = json.getJSONObject(i);
                        Date data = null;
                        try 
                            data = new SimpleDateFormat("yyyy-MM-dd").parse(c.getString(Constants.TAG_DATE));
                         catch (ParseException e) 
                            e.printStackTrace();
                        
                        String newDate = new SimpleDateFormat("dd/MM/yyyy").format(data);
                        if (subjFromDb.contains(c.getString(Constants.TAG_SUBJECT))) 
                            date.add(newDate);
                            subj.add(c.getString(Constants.TAG_SUBJECT));
                            type.add(c.getString(Constants.TAG_TYPE));
                            comment.add(c.getString(Constants.TAG_COMMENT));
                        
                    
                 else 
                    pippo = 1;
                
             catch (JSONException e) 
                e.printStackTrace();
            
            return null;
        

        protected void onPostExecute(String file_url) 
            if (pippo == 0)
                AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
                ComponentName thisWidget = new ComponentName(context, WidgetDataProvider.class);
                int[] appWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
                appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.widget_listView);
                // I use this to update the listview after fetch data. Is it correct?
            
        
    

【问题讨论】:

【参考方案1】:

我仅使用 TimerTask 并在 onPostExecute 中修改更新过程就解决了我的问题。这是我更改的文件:

WidgetDataRemote

public class WidgetDataRemote implements RemoteViewsService.RemoteViewsFactory 
final Context context;
Intent intent;
ArrayList<String> date = new ArrayList<>();
ArrayList<String> subj = new ArrayList<>();
ArrayList<String> type = new ArrayList<>();
ArrayList<String> comment = new ArrayList<>();
JSONParser jsonParser = new JSONParser();
ArrayList<String> subjFromDb = new ArrayList<>();
final Context sad;
int pippo = 0;

public WidgetDataRemote(Context context, Intent intent) 
    this.context = context;
    this.intent = intent;
    sad = context;
    final Handler handler = new Handler();
    Timer timer = new Timer();
    TimerTask doAsynchronousTask = new TimerTask() 
        @Override
        public void run() 
            handler.post(new Runnable() 
                public void run() 
                    try 
                        new LoadSubjects().execute();
                     catch (Exception ignored) 
                
            );
        
    ;
    timer.schedule(doAsynchronousTask, 0, 60000);


@Override
public RemoteViews getViewAt(int position) 
    RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.item_widget);
    if(date.size()>0) 
        remoteViews.setTextViewText(R.id.task_data, date.get(position));
        remoteViews.setTextViewText(R.id.task_subject, subj.get(position));
        remoteViews.setTextViewText(R.id.task_type, type.get(position));
        remoteViews.setTextViewText(R.id.task_comment, comment.get(position));
    else
        remoteViews.setTextViewText(R.id.task_data, "");
        remoteViews.setTextViewText(R.id.task_subject, "loading");
        remoteViews.setTextViewText(R.id.task_type, "");
        remoteViews.setTextViewText(R.id.task_comment, "");
    
    return remoteViews;


@Override
public void onCreate() 
    Toast.makeText(context, "Loading...", Toast.LENGTH_LONG).show();


@Override
public void onDataSetChanged() 


@Override
public void onDestroy() 
    date.clear();
    subj.clear();
    type.clear();
    comment.clear();


@Override
public int getCount() 
    return date.size();


@Override
public RemoteViews getLoadingView() 
    return null;


@Override
public int getViewTypeCount() 
    return 1;


@Override
public long getItemId(int id) 
    return id;


@Override
public boolean hasStableIds() 
    return true;


class LoadSubjects extends AsyncTask<String, String, String> 
    @Override
    protected void onPreExecute() 
        super.onPreExecute();
        subjFromDb.clear();
        pippo = 0;
    

    @Override
    protected String doInBackground(String... args) 
        List<NameValuePair> params = new ArrayList<>();
        params.add(new BasicNameValuePair("class", User.getClasse()));
        JSONArray json = jsonParser.makeHttpRequestArray(Constants.URL_LOAD_SUBJECTS, "POST", params);
        try 
            if (!json.toString().equals("[null]")) 
                for (int i = 0; i < json.length(); i++) 
                    JSONObject c = json.getJSONObject(i);
                    String subj = c.getString(Constants.TAG_NAME);
                    subjFromDb.add(subj);
                
             else 
                pippo = 1;
            
         catch (JSONException e) 
            e.printStackTrace();
        
        return null;
    

    protected void onPostExecute(String file_url) 
        if (pippo == 0) 
            new LoadTasks().execute();
        
    


class LoadTasks extends AsyncTask<String, String, String> 
    @Override
    protected void onPreExecute() 
        super.onPreExecute();
        date.clear();
        subj.clear();
        type.clear();
        comment.clear();
        pippo = 0;
    

    @Override
    protected String doInBackground(String... args) 
        List<NameValuePair> params = new ArrayList<>();
        params.add(new BasicNameValuePair("id_class", User.getClasse()));
        JSONArray json = jsonParser.makeHttpRequestArray(Constants.URL_LOAD_TASKS, "POST", params);
        try 
            if (!json.toString().equals("[null]")) 
                for (int i = 0; i < json.length(); i++) 
                    JSONObject c = json.getJSONObject(i);
                    Date data = null;
                    try 
                        data = new SimpleDateFormat("yyyy-MM-dd").parse(c.getString(Constants.TAG_DATE));
                     catch (ParseException e) 
                        e.printStackTrace();
                    
                    String newDate = new SimpleDateFormat("dd/MM/yyyy").format(data);
                    if (subjFromDb.contains(c.getString(Constants.TAG_SUBJECT))) 
                        date.add(newDate);
                        subj.add(c.getString(Constants.TAG_SUBJECT));
                        type.add(c.getString(Constants.TAG_TYPE));
                        comment.add(c.getString(Constants.TAG_COMMENT));
                    
                
             else 
                pippo = 1;
            
         catch (JSONException e) 
            e.printStackTrace();
        
        return null;
    

    protected void onPostExecute(String file_url) 
        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(sad);
        appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetManager.getAppWidgetIds(new ComponentName(sad, AppWidget.class)), R.id.widget_listView);
    

【讨论】:

以上是关于从 AsyncTask 填充 ListView 的 Android 小部件的主要内容,如果未能解决你的问题,请参考以下文章

从两个不同的 AsyncTask 更新一个 ListView

从 Asynctask 更新 MainActivity 上的 ListView

如何使用 AsyncTask 将图像从 drawable 加载到 listView

ListView 始终具有相同的意图

Android - 为列表视图填充适配器的异步任务

JSONArray 到 ListView - AsyncTask