2010-12-14 18 views
5

Ho un widget che deve eseguire un'operazione potenzialmente di lunga durata in onUpdate(). l'esecuzione dell'operazione ha comportato direttamente gli ANR. per risolvere questo, il mio primo tentativo è stato quello di creare un thread in esso. ho notato che il widget non si aggiornava in alcuni casi. la mia ipotesi è che una volta che onUpdate() si chiude, Android potrebbe terminare il processo insieme al thread non finito.operazione Android long-running per aggiornare una appwidget

il mio prossimo tentativo è stato creare un servizio di intenti. il widget suUpdate() avvia il servizio intent, che esegue direttamente il lavoro e aggiorna il widget al termine. questo funziona, ma con mia grande sorpresa sembra che onHandleIntent() sia single threaded. se ho due widget e quindi aggiorno e avvio il servizio intent, essi aggiornano in sequenza ...

il caso dei due widget non è molto importante, ma mi sto solo chiedendo una procedura ottimale per questo tipo di pattern .

per risolvere il caso dei due widget ho finito per aggiornare tutte le istanze del widget con gli stessi dati ogni volta che si fa clic su uno di essi. ad esempio, eseguo una volta il processo a esecuzione lunga e applico i risultati a tutte le istanze del widget. nel mio scenario questo non ha importanza, ma per molti widget potrebbe essere importante non farlo.

pensieri?

risposta

3

ma con mia grande sorpresa sembra che onHandleIntent() è a thread singolo

Sì.

se ho due widget, e poi entrambi aggiornamento e avviare il servizio intenti, essi aggiornare in sequenza ...

Sì.

ma mi sto solo chiedendo una buona pratica per questo tipo di modello.

Il IntentService era una soluzione eccellente, IMHO. Ricorda che Android funziona su CPU lente, con dispositivi con poca RAM. Eseguire molti thread in parallelo non è generalmente una buona idea.

allora io sono entrare in avvio di un thread nel onHandleIntent(), che richiede un blocco scia, e sembra proprio la cosa si fa tutto troppo complicato.

Prova il mio WakefulIntentService.

+0

ok se capisco correttamente. 1) il widget avvia il servizio intent per ottenere i dati e aggiorna il widget quando è terminato 2) il servizio intent ottiene un wake lock e avvia un thread per eseguire il lavoro effettivo e quindi aggiorna il widget quando ha finito 3) al termine del thread, rilascia la serratura. ragazzo che sembra complicato. perché non riesco a prendere un blocco su onHandleIntent() stesso? –

+0

@ farble1670: perché il dispositivo potrebbe addormentarsi prima di arrivare. – CommonsWare

+0

scusate, volevo dire aggrapparmi a suHandleUpdate(), nel app appwidget. che cosa mi ha fatto inviare la richiesta a un servizio di intenti? –

0

make onUpdate chiama la propria funzione per scorrere i widget e aggiornarli. Fai il tuo compito asincrono prima del ciclo. Avrai bisogno di due azioni separate, una che richiede l'avvio dell'aggiornamento e una che verrà trasmessa per il tuo IntentService per far sapere ai widget che sono finiti. Spero che questo ti aiuti.

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

private void updateWidget(Context context){ 
    ComponentName widget = new ComponentName(context, MyWidget.class); 
    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); 
    int[] appWidgetIds = appWidgetManager.getAppWidgetIds(widget); 
    updateWidget(context, appWidgetManager, appWidgetIds); 
} 

private void updateWidget(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { 

    final boolean isEnabled = true; //took out code didn't want you to see 
    // start intent service here 
    for(int i = 0; i< appWidgetIds.length; i++){ 
     int appWidgetId = appWidgetIds[i]; 
     Intent intent = new Intent(isEnabled ? ACTION_TOGGLE_OFF : ACTION_TOGGLE_ON); 
     PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0); 

     RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout); 
     views.setOnClickPendingIntent(R.id.widget , pi); 
     views.setImageViewResource(R.id.widget_image, isEnabled? R.drawable.widget_on : R.drawable.widget_off); 

     appWidgetManager.updateAppWidget(appWidgetId, views); 
    } 
} 
+0

hmmm, non sono sicuro di vedere come questo si applica. iniziare da zero. in onUpdate(), esegui un processo a lunga esecuzione, quindi aggiorna tutti gli ID. il lungo processo in esecuzione non può essere eseguito solo nel thread onUpdate(), ciò causerà un ANR. quindi, usa un servizio di intenti. ma questo è a thread singolo, quindi se più chiamate suUpdate() provengono da più widget, risultanti in chiamate di servizio con più intenzioni, il secondo widget si blocca in attesa che il primo finisca nel servizio intent. –

+0

questo è il motivo per cui lo chiameresti prima di passare in rassegna e aggiornare i tuoi widget, in sostanza prendi in mano il convincere di Google che aggiorna tutti i widget per te. La funzione di aggiornamento dovrebbe gestire solo le modifiche dell'interfaccia utente in modo da avere un'istruzione if/else o switch per determinare quale sia l'azione corrente (avviare la discussione, l'avanzamento del thread, terminare il thread) – schwiz

+0

okay ... la mia prima domanda che immagino è stato mancato riguarda l'avvio del thread. se va bene iniziare una discussione su onUpdate() e ritornare? non ho bisogno di prendere una serratura? Android ucciderà il processo dopo l'uscita di onUpdate()? averlo avviato un servizio di intent invece di un thread sembra impedire l'ANR ma non funziona quando ci sono più widget che si aggiornano mentre si bloccheranno in attesa di onHandleIntent() per uscire. quindi sto iniziando una discussione su onHandleIntent(), che richiede un wake lock, e sembra proprio che si stia complicando troppo. –

Problemi correlati