2013-04-05 5 views
9

Ho creato un widget dell'app utilizzando la raccolta per la mia app. Il widget mostra la data e l'elenco di elementi in quella specifica data. Tutto funziona correttamente e il widget si aggiorna come richiesto, ma a volte cosa succede cambiando la data nel widget facendo clic su pulsante successivo e precedente, l'elenco non viene aggiornato significa che gli elementi non vengono aggiornati in quella particolare data. Questo comportamento è casuale e si verifica solo a volte. Quindi, perché questo accade, qualcosa di sbagliato nel mio codice.Problema di aggiornamento di un widget dell'app utilizzando la raccolta

codice che ho utilizzo è:

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

Qualcuno sa l'indizio per questa risposta – AndroidDev

+0

Dopo molta ricerca, finalmente ho avuto la mia risposta. In realtà devo chiamare appWidgetManager.notifyAppWidgetViewDataChanged (appWidgetIds, R.id.widget_list); metodo onReceive(). Ho pubblicato il mio codice aggiornato come risposta a questa domanda per un utilizzo futuro. – AndroidDev

risposta

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

Cosa hai cambiato ??? –

+0

Ottima risposta alla tua stessa domanda, kuddos! Mi hai risparmiato un sacco di tempo per la ricerca;) – 2Dee

2

si può provare se cambiare PendingIntent.FLAG_UPDATE_CURRENT a PendingIntent.FLAG_CANCEL_CURRENT nelle vostre nextButtonPendingIntent e prevButtonPendingIntent intenti in attesa sarà di aiuto.

+0

È già impostato come PendingIntent.FLAG_UPDATE_CURRENT in nextButtonPendingIntent e prevButtonPendingIntent. – AndroidDev

+0

Ho sbagliato nella mia risposta originale (ho cambiato l'ordine delle bandiere mentre le inserisco). Modifica ora. –

+0

A volte non funziona a volte aggiorna l'elenco ma a volte non lo fa, ma la data cambia, significa al clic del pulsante, dal metodo onReceive() è andato a updateAppWidget(), ma da lì non è riuscito a chiamare la classe WidgetService. Di conseguenza non sarà in grado di chiamare la classe WidgetDisplay ei dati non verranno aggiornati, ma a volte funziona come un incantesimo. – AndroidDev

1

Quando si crea il PendingIntents in updateAppWidget, per ogni widget, è creare queste due:

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

Per entrambi, si imposta il secondo argomento di widgetId. Il sistema PendingIntent non sembra vedere se l'argomento Intent è diverso. (In realtà, non dovrebbe assolutamente farlo, altrimenti non è possibile aggiornare un PendingIntent esistente in un nuovo Intento.) Ciò significa che lo nextButtonPendingIntent e lo prevButtonPendingIntent finiscono lo stesso.

La soluzione è quella di mettere noto, distinto, numeri in tale argomento e di mettere altre informazioni utili (come il widget di Id) all'interno della intento:

nextButtonIntent.putExtra("widget_id", widgetId); 

e di recuperarli in onReceive():

int widgetId = intent.getIntExtra("widget_id"); 
+0

Sto avendo problemi simili se hai un secondo per guardare la mia domanda over: im a un po 'di perdita http://stackoverflow.com/questions/25944639/appwidget-refresh-uri-for-remoteviews –

+0

Ho risposto, spero che aiuti. –