2013-04-05 37 views
9

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

的代码,我有使用方法是:

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(){ 
    } 
} 
+0

任何人都知道这个答案的线索 – AndroidDev 2013-04-09 09:39:49

+0

经过大量的搜索,最后我得到了我的答案。其实我必须调用appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds,R.id.widget_list); onReceive()方法。我已经发布了我的更新代码作为此问题的答案以供将来使用。 – AndroidDev 2013-05-03 10:36:57

回答

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); 
     }     
    } 
} 
+7

你变了什么? – 2013-09-21 17:57:39

+0

对自己的问题很好的回答,kuddos!你为我节省了大量的研究时间;) – 2Dee 2013-12-01 15:18:52

2

你可以尝试,如果在你的nextButtonPendingIntentprevButtonPendingIntent未决的意图改变PendingIntent.FLAG_UPDATE_CURRENTPendingIntent.FLAG_CANCEL_CURRENT会有所帮助。

+0

它已经在nextButtonPendingIntent和prevButtonPendingIntent中设置为PendingIntent.FLAG_UPDATE_CURRENT。 – AndroidDev 2013-04-05 11:19:25

+0

我在原来的答案中犯了错误(我粘贴它们时切换了标志的顺序)。现在编辑。 – 2013-04-05 11:21:20

+0

Nope不工作有时它更新列表,但有时它不会,但日期更改,意味着点击按钮,从onReceive()方法到updateAppWidget(),但从那里它无法调用WidgetService类。因此它将无法调用WidgetDisplay类并且数据不会更新,但有时它的作用就像一个魅力。 – AndroidDev 2013-04-05 11:26:57

1

当您在updateAppWidgetPendingIntents,对于每个插件,您可以创建两个:

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)的意图内部编号:

nextButtonIntent.putExtra("widget_id", widgetId); 

而在onReceive():

进行检索
int widgetId = intent.getIntExtra("widget_id"); 
+0

我有类似的问题,如果你有第二个看我的问题结束:即时通讯有点损失http://stackoverflow.com/questions/25944639/appwidget-refresh-uri-for-remoteviews – 2014-09-20 05:18:04

+0

我已经回答了它,希望它有帮助。 – 2014-09-21 14:56:36