使用集合更新app小部件的问题

时间:2013-04-05 08:57:48

标签: android android-widget android-appwidget

我使用我的应用程序的集合创建了一个应用程序小部件,该小部件显示该特定日期的日期和项目列表。一切正常,窗口小部件正在根据需要进行更新。但有时,通过单击下一个和上一个按钮更改窗口小部件中的日期时会发生什么,列表不刷新意味着项目在该特定日期未更新。此行为是随机的,有时仅发生。那么为什么会发生这种情况,我的代码中出现了任何问题。

我使用的代码是:

WidgetProvider.class

public class WidgetProvider extends AppWidgetProvider 
{   
    private ThemeManager    m_ThemeManagerObject;

    private static String   WIDGET_NEXT_BUTTON = "in.test.widgetApp.WIDGET_NEXT_BUTTON";

    private static String   WIDGET_PREV_BUTTON = "in.test.widgetApp.WIDGET_PREV_BUTTON";    

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) 
    {               
        super.onUpdate(context, appWidgetManager, appWidgetIds);

        // Set Date to current Date
        NoteManager.getSingletonObject().setWidgetToCurrentDate();

        // Code to update the widget by current date 
        updateAppWidget(context, AppWidgetManager.getInstance(context), appWidgetIds);
    }   

    @Override
    public void onReceive(Context context, Intent intent) 
    {           
        super.onReceive(context, intent);

        int numOfDays = 1;

        ComponentName thisWidget = new ComponentName(context, WidgetProvider.class);
        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
        int[] appWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);

        if (intent.getAction().equals(WIDGET_NEXT_BUTTON)) 
        {
            // Increase no of days by one
            // Update the widget by new date 
            NoteManager.getSingletonObject().setWidgetDate(numOfDays);          
            updateAppWidget(context, AppWidgetManager.getInstance(context), appWidgetIds);
        }   
        else if (intent.getAction().equals(WIDGET_PREV_BUTTON)) 
        {
            // Decrease no of days by one
            // Update the widget by new date 
            NoteManager.getSingletonObject().setWidgetDate(-numOfDays);         
            updateAppWidget(context, AppWidgetManager.getInstance(context), appWidgetIds);
        }                   
    }

        public void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
{
    // Get the folder path of all-page-view
    ContextWrapper cw = new ContextWrapper(context.getApplicationContext());
    File customDirectoryPath = cw.getDir(Utilities.CUSTOM_DIRECTORY_NAME_PREFIX, Context.MODE_PRIVATE);
    File allPageDirectoryPath = new File(customDirectoryPath.getPath() + "/" + Utilities.All_PAGE_DIRECTORY_NAME_PREFIX); 

    if (!(allPageDirectoryPath.exists()))
        allPageDirectoryPath.mkdirs();

    // Create an singleton object of ThemeManager class
    m_ThemeManagerObject = ThemeManager.getSingletonObject();
    m_ThemeManagerObject.readTheme(allPageDirectoryPath.getPath());

    // Create an instance of SimpleDateFormat class
    SimpleDateFormat dateFormater = new SimpleDateFormat("dd-MMM, EEE", Locale.US);

    /* loop through all widget instances */
    for (int widgetId : appWidgetIds) 
    { 
        // Create an instance of remote view class
        RemoteViews remoteView = new RemoteViews(context.getPackageName(), R.layout.widget_list);       
        Intent svcIntent = new Intent(context, WidgetService.class);
        svcIntent.setData(Uri.fromParts("content", String.valueOf(widgetId), null));        
        remoteView.setRemoteAdapter(R.id.widget_list, svcIntent);   

        // Show day, month and week day inside the widget
        remoteView.setTextViewText(R.id.txt_date, dateFormater.format(NoteManager.getSingletonObject().getWidgetDate().getTime()));

        // If the list is empty. Show empty widget with juswrite-icon & empty text to the user          
        remoteView.setEmptyView(R.id.widget_list, R.id.widget_empty_text);              

        // On click of next button
        Intent nextButtonIntent = new Intent(WIDGET_NEXT_BUTTON);
        /* use widgetId as second parameter - it helped me to better address particular widget instance */
        PendingIntent nextButtonPendingIntent = PendingIntent.getBroadcast(context, widgetId, nextButtonIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        remoteView.setOnClickPendingIntent(R.id.btn_next_month, nextButtonPendingIntent);
        remoteView.setInt(R.id.btn_next_month, "setBackgroundResource", m_ThemeManagerObject.getNextButtonBgImage());

        // On click of previous button
        Intent prevButtonIntent = new Intent(WIDGET_PREV_BUTTON);
        /* use widgetId as second parameter - same as above */
        PendingIntent prevButtonPendingIntent = PendingIntent.getBroadcast(context, widgetId, prevButtonIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        remoteView.setOnClickPendingIntent(R.id.btn_prev_month, prevButtonPendingIntent);
        remoteView.setInt(R.id.btn_prev_month, "setBackgroundResource", m_ThemeManagerObject.getPrevButtonBgImage());

        // Open application on click of app widget
        Intent clickIntent = new Intent(context, AllPageViewActivity.class);
        PendingIntent clickPI = PendingIntent.getActivity(context, 0,clickIntent,PendingIntent.FLAG_UPDATE_CURRENT);
        remoteView.setOnClickPendingIntent(R.id.widget_empty_text, clickPI);
        remoteView.setOnClickPendingIntent(R.id.txt_date, clickPI);

        /* update one widget instance at a time*/
        appWidgetManager.updateAppWidget(widgetId, remoteView);
    }
}
}

WidgetService.class

public class WidgetService extends RemoteViewsService 
{
    @Override
    public RemoteViewsFactory onGetViewFactory(Intent intent) 
    {
        return(new WidgetDisplay(this.getApplicationContext(), intent));
    }
}

WidgetDisplay.class

public class WidgetDisplay implements RemoteViewsService.RemoteViewsFactory
{
    private File m_CustomDirectoryPath, m_AllPageDirectoryPath;

    private NoteManager m_NoteManagerObject;

    private ThemeManager m_ThemeManagerObject;

    private ArrayList<String>   m_AlarmItemNameArrayList;

    private ArrayList<Integer>  m_ItemIndexArray;

    private Context ctxt=null;

    int appWidgetId;

    Bitmap canvasBackground;

    public WidgetDisplay(Context ctxt, Intent intent) 
    {
        this.ctxt=ctxt;

        appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                AppWidgetManager.INVALID_APPWIDGET_ID);

        setImageInView(this.ctxt);

    }

    private void setImageInView(Context context) 
    {
        ContextWrapper cw = new ContextWrapper(ctxt.getApplicationContext());
        m_CustomDirectoryPath = cw.getDir(Utilities.CUSTOM_DIRECTORY_NAME_PREFIX, Context.MODE_PRIVATE);
        m_AllPageDirectoryPath = new File(m_CustomDirectoryPath.getPath() + "/" + Utilities.All_PAGE_DIRECTORY_NAME_PREFIX); 

        m_NoteManagerObject = NoteManager.getSingletonObject();
        m_ThemeManagerObject = ThemeManager.getSingletonObject();

        m_NoteManagerObject.readSettings(m_AllPageDirectoryPath.getPath());
        m_NoteManagerObject.readAllPageChangesFromFile(m_AllPageDirectoryPath.getPath());
        m_NoteManagerObject.readAlarmFromFile(m_AllPageDirectoryPath.getPath());
        m_ThemeManagerObject.readTheme(m_AllPageDirectoryPath.getPath());

        m_AlarmItemNameArrayList = new ArrayList<String>(m_NoteManagerObject.getAlarmCount());
        m_ItemIndexArray = new ArrayList<Integer>(m_NoteManagerObject.getAlarmCount());

        SimpleDateFormat sdFormatter = new SimpleDateFormat("dd-MMM-yyyy", Locale.US);      
        String selectedDate = sdFormatter.format(m_NoteManagerObject.getWidgetDate());

        for(int i=0; i<m_NoteManagerObject.getAlarmCount(); i++)
        {
            String ArrayDate = sdFormatter.format(m_NoteManagerObject.getAlarmTime(i));         
            if(selectedDate.equals(ArrayDate))
            {
                File noteDirectoryPath = new File(m_CustomDirectoryPath.getPath() + "/" + m_NoteManagerObject.getAlarmFolder(i));
                m_AlarmItemNameArrayList.add(noteDirectoryPath.getPath() + "/" + m_NoteManagerObject.getAlarmItem(i));

                m_ItemIndexArray.add(i);
            }
        }
    }

    @Override
    public int getCount() 
    {
        return(m_AlarmItemNameArrayList.size());
    }

    @Override
    public RemoteViews getViewAt(int position) 
    {       
        new ImageLoaderTask(position).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

        // Set combine image to the image view using remote view instance
        RemoteViews remoteView = new RemoteViews(ctxt.getPackageName(), R.layout.widget_list_item);
        remoteView.setImageViewBitmap(R.id.image_view, canvasBackground);

        // Set time text view using remote view instance
        SimpleDateFormat timeFormater;

        if(m_NoteManagerObject.get24HourFormat())
        {
            timeFormater = new SimpleDateFormat("HH:mm", Locale.US);
        }
        else
        {
            timeFormater = new SimpleDateFormat("hh:mm a", Locale.US );
        }

        // Show time on the top of each image view
        String time = timeFormater.format(m_NoteManagerObject.getAlarmTime(m_ItemIndexArray.get(position)));            
        remoteView.setTextViewText(R.id.text_alarm_time,  time);        

        Intent clickIntent = new Intent(ctxt, AllPageViewActivity.class);
        PendingIntent clickPI=PendingIntent.getActivity(ctxt, 0,clickIntent,PendingIntent.FLAG_UPDATE_CURRENT);
        remoteView.setOnClickPendingIntent(R.id.image_view, clickPI);

        return(remoteView);
    }

    class ImageLoaderTask extends AsyncTask<URL, Integer, Long>
    {
        private int position;

        ImageLoaderTask(int position)
        {
            this.position = position;
        }

        @Override
        protected void onPreExecute()
        {
            // Get foreground and background image
            Bitmap bitmapImage = BitmapFactory.decodeFile(m_AlarmItemNameArrayList.get(position)).copy(Bitmap.Config.ARGB_8888, true);
            canvasBackground = BitmapFactory.decodeResource(ctxt.getResources(), m_ThemeManagerObject.getWidgetListItemBgImage(m_ItemIndexArray.get(position), bitmapImage)).copy(Bitmap.Config.ARGB_8888, true);

            // Scaled foreground image and combine with the background image
            bitmapImage = Bitmap.createScaledBitmap(bitmapImage, 380, bitmapImage.getHeight() / 2, true);               
            Canvas comboImage = new Canvas(canvasBackground);
            comboImage.drawBitmap(bitmapImage, 0f, 0f, null);
        }

        @Override
        protected Long doInBackground(URL... urls)
        {
            return null;
        }

        @Override
        protected void onProgressUpdate(Integer... progress)
        {

        }

        @Override
        protected void onPostExecute(Long result)
        {

        }
    }

    @Override
    public void onCreate(){ 
    }

    @Override
    public void onDestroy(){
    }

    @Override
    public RemoteViews getLoadingView()
    {
        return(null);
    }

    @Override
    public int getViewTypeCount(){
        return(1);
    }

    @Override
    public long getItemId(int position){
        return(position);
    }

    @Override
    public boolean hasStableIds(){
        return(true);
    }

    @Override
    public void onDataSetChanged(){
    }
}

3 个答案:

答案 0 :(得分:5)

<强> WidgetProvider.class

public class WidgetProvider extends AppWidgetProvider 
{   
    private NoteManager         m_NoteManagerObject;

    private ThemeManager        m_ThemeManagerObject;

    private SimpleDateFormat    m_DateFormater;

    private static String       WIDGET_NEXT_BUTTON = "in.test.widgetApp.WIDGET_NEXT_BUTTON";

    private static String       WIDGET_PREV_BUTTON = "in.test.widgetApp.WIDGET_PREV_BUTTON";    

    public WidgetProvider()
    {
        // Create an singleton object of NoteManager class
        m_NoteManagerObject = NoteManager.getSingletonObject();
        // Create an singleton object of ThemeManager class
        m_ThemeManagerObject = ThemeManager.getSingletonObject();
        // Create an instance of SimpleDateFormat class
        m_DateFormater = new SimpleDateFormat("dd-MMM, EEE", Locale.US);
    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) 
    {               
        super.onUpdate(context, appWidgetManager, appWidgetIds);

        // Set Date to current Date
        m_NoteManagerObject.setWidgetToCurrentDate();

        // Get the folder path of all-page-view
        ContextWrapper cw = new ContextWrapper(context.getApplicationContext());
        File customDirectoryPath = cw.getDir(Utilities.CUSTOM_DIRECTORY_NAME_PREFIX, Context.MODE_PRIVATE);
        File allPageDirectoryPath = new File(customDirectoryPath.getPath() + "/" + Utilities.All_PAGE_DIRECTORY_NAME_PREFIX); 

        if (!(allPageDirectoryPath.exists()))
            allPageDirectoryPath.mkdirs();

        m_ThemeManagerObject.readTheme(allPageDirectoryPath.getPath());     

        // Set up the intent that starts the WidgetService, which will
        // provide the views for this collection.   
        // When intents are compared, the extras are ignored, so we need to embed the extras
        // into the data so that the extras will not be ignored.
        Intent intent  = new Intent(context, WidgetService.class);
        intent.setData(Uri.fromParts("content", String.valueOf(appWidgetIds), null));

        // Instantiate the RemoteViews object for the App Widget layout.
        // Set up the RemoteViews object to use a RemoteViews adapter. 
        // This adapter connects to a RemoteViewsService  through the specified intent.
        // This is how you populate the data.
        RemoteViews remoteView = new RemoteViews(context.getPackageName(), R.layout.widget_list);           
        remoteView.setRemoteAdapter(R.id.widget_list, intent);  

        // Show day, month and week day inside the widget
        remoteView.setTextViewText(R.id.txt_date, m_DateFormater.format(m_NoteManagerObject.getWidgetDate().getTime()));

        // The empty view is displayed when the collection has no items.        
        remoteView.setEmptyView(R.id.widget_list, R.id.widget_empty_text);              

        // On click of next button
        // This section makes it possible for items to have individualized behavior.
        // Set the action for the intent.
        // When the user touches a particular view, it will have the effect of
        // broadcasting ACTION.
        Intent nextButtonIntent = new Intent(context, WidgetProvider.class);            
        nextButtonIntent.setAction(WIDGET_NEXT_BUTTON);
        PendingIntent nextButtonPendingIntent = PendingIntent.getBroadcast(context, 0, nextButtonIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        remoteView.setOnClickPendingIntent(R.id.btn_next_month, nextButtonPendingIntent);
        remoteView.setInt(R.id.btn_next_month, "setBackgroundResource", m_ThemeManagerObject.getNextButtonBgImage());

        // On click of previous button
        // This section makes it possible for items to have individualized behavior.
        // Set the action for the intent.
        // When the user touches a particular view, it will have the effect of
        // broadcasting ACTION.
        Intent prevButtonIntent = new Intent(context, WidgetProvider.class);
        prevButtonIntent.setAction(WIDGET_PREV_BUTTON);
        PendingIntent prevButtonPendingIntent = PendingIntent.getBroadcast(context, 0, prevButtonIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        remoteView.setOnClickPendingIntent(R.id.btn_prev_month, prevButtonPendingIntent);
        remoteView.setInt(R.id.btn_prev_month, "setBackgroundResource", m_ThemeManagerObject.getPrevButtonBgImage());

        // Open application on click of app widget
        Intent clickIntent = new Intent(context, AllPageViewActivity.class);
        PendingIntent clickPI = PendingIntent.getActivity(context, 0,clickIntent,PendingIntent.FLAG_UPDATE_CURRENT);
        remoteView.setOnClickPendingIntent(R.id.widget_empty_text, clickPI);
        remoteView.setOnClickPendingIntent(R.id.txt_date, clickPI); 

        appWidgetManager.updateAppWidget(appWidgetIds, remoteView); 
    }   

    @Override
    public void onReceive(Context context, Intent intent) 
    {           
        super.onReceive(context, intent);

        int numOfDays = 1;

        ComponentName thisWidget = new ComponentName(context, WidgetProvider.class);
        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
        int[] appWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);

        if (intent.getAction().equals(WIDGET_NEXT_BUTTON)) 
        {
            // Increase no of days by one
            m_NoteManagerObject.setWidgetDate(numOfDays);

            // Update remote view
            RemoteViews remoteView = new RemoteViews(context.getPackageName(), R.layout.widget_list);               
            remoteView.setTextViewText(R.id.txt_date, m_DateFormater.format(m_NoteManagerObject.getWidgetDate().getTime()));
            appWidgetManager.updateAppWidget(appWidgetIds, remoteView); 

            // Update list content of the widget
           // This will call onDataSetChanged() method of WidgetDisplay class
            appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.widget_list);
        }   
        else if (intent.getAction().equals(WIDGET_PREV_BUTTON)) 
        {
            // Decrease no of days by one
            m_NoteManagerObject.setWidgetDate(-numOfDays);  

            // Update remote view
            RemoteViews remoteView = new RemoteViews(context.getPackageName(), R.layout.widget_list);               
            remoteView.setTextViewText(R.id.txt_date, m_DateFormater.format(m_NoteManagerObject.getWidgetDate().getTime()));
            appWidgetManager.updateAppWidget(appWidgetIds, remoteView); 

            // Update list content of the widget
              // This will call onDataSetChanged() method of WidgetDisplay class
            appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.widget_list);
        }                   
    }
}

答案 1 :(得分:2)

您可以尝试将PendingIntent.FLAG_UPDATE_CURRENT中的PendingIntent.FLAG_CANCEL_CURRENT更改为nextButtonPendingIntentprevButtonPendingIntent待处理意图会有所帮助。

答案 2 :(得分:1)

PendingIntents中创建updateAppWidget时,对于每个小部件,您可以创建以下两个小部件:

PendingIntent nextButtonPendingIntent = PendingIntent.getBroadcast(context, widgetId, nextButtonIntent, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent prevButtonPendingIntent = PendingIntent.getBroadcast(context, widgetId, prevButtonIntent, PendingIntent.FLAG_UPDATE_CURRENT);

对于两者,您将第二个参数设置为widgetId。 PendingIntent系统不会查看Intent参数是否不同。 (事实上​​,它肯定不应该这样做 - 否则你无法将现有的PendingIntent更新为新的Intent。)这意味着nextButtonPendingIntentprevButtonPendingIntent最终会相同。

解决方案是在该参数中放入已知的,不同的数字,并将其他有用的信息(如小部件ID)放在intent中:

nextButtonIntent.putExtra("widget_id", widgetId);

并在onReceive():

中检索它
int widgetId = intent.getIntExtra("widget_id");