2012-01-12 36 views
7

Qualcuno può dirmi come controllare che il mio widget sia stato posizionato sulla schermata iniziale?Check Widget è posizionato su schermo Android

Ho un codice nella mia app che dovrebbe essere eseguito solo se il widget è posizionato sulla schermata iniziale.

+0

Ciao, hai fatto dato un'occhiata alla mia risposta? Penso che potrebbe aiutare .. ;-) –

risposta

6

È necessario memorizzare tali informazioni da soli. Di solito uso le preferenze dell'applicazione, ma potresti usare qualsiasi cosa. Generalmente i widget usano i servizi per comunicare, quindi il codice che fa roba è probabile in un servizio, ma l'utilizzo della preferenza consente a qualsiasi parte della tua app di accedervi.

Nella classe del widget che estende AppWidgetProvider, onEnabled viene chiamato quando il widget viene inserito in una schermata iniziale e l'onDeleted viene (di solito) chiamato quando viene rimosso. onDisabled viene chiamato quando tutte le copie vengono rimosse.

Così nel codice del provider di widget di:

@Override 
public void onEnabled(Context context) { 
    super.onEnabled(context); 
    setWidgetActive(true); 
    context.startService(new Intent(appContext, WidgetUpdateService.class)); 
} 

@Override 
public void onDisabled(Context context) { 
    Context appContext = context.getApplicationContext(); 
    setWidgetActive(false); 
    context.stopService(new Intent(appContext, WidgetUpdateService.class)); 
    super.onDisabled(context); 
} 

private void setWidgetActive(boolean active){ 
    Context appContext = context.getApplicationContext(); 
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(appContext); 
    SharedPreferences.Editor edit = prefs.edit(); 
    edit.putBoolean(Constants.WIDGET_ACTIVE, active); 
    edit.commit(); 
} 

Altrove nel codice, si dovrebbe verificare se il widget è attivo da:

public boolean isWidgetActive(Context context){ 
    Context appContext = context.getApplicationContext(); 
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 
    return prefs.getBoolean(Constants.WIDGET_ACTIVE, false); 
} 
+0

Aargh bello! Grazie, non avevo pensato a onDisabled(), Verrà eseguito solo quando avrai rimosso tutto il widget dalla schermata iniziale della tua app esattamente ciò di cui ho bisogno. Stavo usando: onDeleted(), witch viene eseguito ogni volta che elimini un widget. – Jeff

+0

Ci sono alcuni casi sopra non coprono, e sto cercando soluzioni: (1) utente cancellato preferenze condivise - c'è widget, ma non si sa su di esso (2) rimpiangere utente tra "Aggiungi widget" e premendo "ok" - ma abilitato è stato chiamato, nessun widget – auval

+2

Si prega di dare un'occhiata alla risposta di seguito ;-) –

5

Lo so che è una vecchia questione, ma guardando questo oggi ho visto che ci sono un paio di problemi con la risposta accettata da @ larsona1:

  1. se l'utente ha cancellato t ha condiviso le preferenze: c'è ancora un widget, ma l'app non lo saprà.
  2. se l'utente rimpiange tra "aggiungi widget" e prima di premere "ok" - onEnabled verrà chiamato in ogni caso e un widget verrà registrato nella schermata iniziale anche se non è presente alcun widget e non è possibile rimuoverlo in un secondo momento. (Potrebbe trattarsi di un bug in Home Launcher ADT).

Ho trovato una soluzione al primo problema. Nessuna preferenza condivisa è necessaria, poiché è inaffidabile comunque. Deve essere controllato in runtime.

// in some class you define a static variable, say in S.java 
static boolean sWidgetMayExist = true; 

In widget di vostro provider:

// MyAppWidgetProvider.java 
// to respond to runtime changes, when widgets are added and removed 
@Override 
public void onEnabled(Context context) { 
    super.onEnabled(context); 
    S.sWidgetMayExist = true; 
} 

@Override 
public void onDisabled(Context context) { 
    super.onDisabled(context); 
    S.sWidgetMayExist = true; 
} 

E, nel codice di servizio aggiungere questo:

AppWidgetManager manager = null; 
RemoteViews views = null; 
ComponentName widgetComponent = null; 

    // ..and in your update thread 

    if (!S.sWidgetMayExist) { return; } 

if (manager == null || widgetComponent == null) { 
    widgetComponent = new ComponentName(c, 
      MyAppWidgetProvider.class); 
    manager = AppWidgetManager.getInstance(c); 
} 

if (manager.getAppWidgetIds(widgetComponent) == null) { 
    S.sWidgetMayExist = false; 
} 
+1

Secondo questa pagina [1] problema 2 sembra essere un bug che è stato risolto con Android 2.1 e versioni successive. L'ho provato con Android 4.1.2 e i metodi onDelete e onDisabled sono stati chiamati correttamente. [1] https://groups.google.com/forum/?fromgroups=#!topic/android-developers/4agiDfaGvDw – friday

+0

Vedere la risposta di Waza_Be, sembra funzionare e richiede molto meno codice. –

+0

@ WilliamT.Mallard La mia risposta è 6 mesi più vecchia di quella di Waza. Quindi non l'ho controllato quando ho risposto. Ma rivedendolo ora, non sono sicuro che copra i casi limite a cui mi riferisco. – auval

37

Solo dicendo, ma ...

int ids[] = AppWidgetManager.getInstance(this).getAppWidgetIds(new ComponentName(this,MyAppWidgetProvider.class)); 

    Toast.makeText(this, "Number of widgets: "+ids.length, Toast.LENGTH_LONG).show(); 
+5

Questa è la risposta corretta: interrogare AppWidgetManager e ottenere gli id ​​è il modo corretto per verificare se e quanti widget sono posizionati nella schermata iniziale. –

+2

Posso anche confermare che questa è la risposta corretta. Non perdere tempo seguendo la risposta di larsona1 e finendo con il codice fragile da mantenere. – Marky

+1

l'unico problema è che a volte restituisce un numero di ID anche se non vengono visualizzati widget – Catalina

1

@ Waza_Be ha ragione quando guarda la lista "AppWidgetIds" per sapere t Il numero di widget attivi (quelli installati sul tuo homescreen) è il modo corretto per conoscere queste informazioni.

Tuttavia, tieni presente che NON DEVI DOVEREI guardare da solo.

Controllare la documentazione ufficiale di Android per le migliori pratiche sui widget: https://developer.android.com/guide/topics/appwidgets/index.html#AppWidgetProvider

L'approccio giusto è quello di sovrascrivere solo il metodo onUpdate() e scorrere l'elenco dei widget "attivi":

public class ExampleAppWidgetProvider extends AppWidgetProvider { 

    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { 
     final int N = appWidgetIds.length; 

     // Perform this loop procedure for each App Widget that belongs to this provider 
     for (int i=0; i<N; i++) { 
      int appWidgetId = appWidgetIds[i]; 

      // Create an Intent to launch ExampleActivity 
      Intent intent = new Intent(context, ExampleActivity.class); 
      PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); 

      // Get the layout for the App Widget and attach an on-click listener 
      // to the button 
      RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider_layout); 
      views.setOnClickPendingIntent(R.id.button, pendingIntent); 

      // Tell the AppWidgetManager to perform an update on the current app widget 
      appWidgetManager.updateAppWidget(appWidgetId, views); 
     } 
    } 
} 

E poiché il proprio fornitore di widget sovrascrive AppWidgetProvider, NON si andrà nel metodo onUpdate() se non ci sono widget attivi nella schermata iniziale!

vedere il codice OnReceive() di Android AppWidgetProvider che controlla già per te, che "appWidgetIds.length> 0":

public void onReceive(Context context, Intent intent) { 
    // Protect against rogue update broadcasts (not really a security issue, 
    // just filter bad broacasts out so subclasses are less likely to crash). 
    String action = intent.getAction(); 
    if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) { 
     Bundle extras = intent.getExtras(); 
     if (extras != null) { 
      int[] appWidgetIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS); 
      if (appWidgetIds != null && appWidgetIds.length > 0) { 
       this.onUpdate(context, AppWidgetManager.getInstance(context), appWidgetIds); 
      } 
     } 
    } 

(...) 
}