Creazione di un client Twitter per Android recupero degli aggiornamenti tramite un servizio

In questa serie stiamo costruendo un client Twitter per la piattaforma Android utilizzando la libreria Twitter4J. Questo tutorial si concentrerà sull'implementazione di un servizio per recuperare continuamente nuovi tweet per la timeline home dell'utente. Useremo anche un ricevitore Broadcast per aggiornare l'interfaccia dell'app quando nuovi tweet saranno disponibili per la visualizzazione.


Disponibile anche in questa serie:

  1. Creazione di un client Twitter per Android: installazione e panoramica
  2. Creazione di un client Twitter per Android: creazione dell'interfaccia
  3. Creazione di un client Twitter per Android: creazione di un database cronologico
  4. Creazione di un client Twitter per Android: recupero degli aggiornamenti tramite un servizio
  5. Creazione di un client Twitter per Android: Tweeting, Retweeting e Replying

Passaggio 1: creare una classe di servizio

In modo che i tweet della timeline home dell'utente vengano automaticamente visualizzati quando diventano disponibili, utilizzeremo un servizio per recuperarli a intervalli prestabiliti. Questo servizio verrà eseguito a una frequenza di tua scelta, scrivendo nel database e inviando trasmissioni quando i nuovi tweet sono stati recuperati e archiviati. La principale classe di attività dell'app riceverà le trasmissioni e requery il database, aggiornando l'interfaccia della timeline per visualizzare i nuovi dati.

Crea una nuova classe nel tuo progetto, nominandola "TimelineService" e modificando la riga di dichiarazione della classe di apertura come segue:

 public class TimelineService estende il servizio 

Avrai bisogno della seguente importazione:

 importare android.app.Service;

Aggiungi le seguenti variabili di istanza alla tua classe, per interagire con Twitter:

 / ** chiave di autenticazione twitter * / stringa statica finale pubblica TWIT_KEY = "your key"; / ** twitter secret * / public static static String TWIT_SECRET = "il tuo segreto"; / ** oggetto twitter * / timeline Twitter privataTwitter;

Modifica le variabili chiave e segreta per adattarle alle tue, come utilizzato nelle esercitazioni precedenti. Aggiungere le seguenti variabili per la gestione del database:

 / ** oggetto helper del database * / private NiceDataHelper niceHelper; / ** database timeline * / privato SQLiteDatabase niceDB;

Infine, aggiungi quanto segue per l'uso generico all'interno della classe:

 / ** preferenze condivise per i dettagli utente * / private SharedPreferences nicePrefs; / ** gestore per l'aggiornamento * / gestore privato niceHandler; / ** ritardo tra il recupero di nuovi tweet * / int statico int mins = 5; // modifica per soddisfare la finale statica privata lunga FETCH_DELAY = min * (60 * 1000); // debugging tag private String LOG_TAG = "TimelineService";

L'oggetto Handler è per la pianificazione degli aggiornamenti a frequenze fisse. La variabile "min" e la costante "FETCH_DELAY" ti consentono di impostare la frequenza con cui l'app recupererà i nuovi aggiornamenti dalla timeline home dell'utente. Modifica la variabile "min" per riflettere i molti minuti che vuoi che l'app attenda tra gli aggiornamenti. Gli aggiornamenti verranno recuperati solo a questa frequenza mentre l'app è in esecuzione. Quando l'utente esce dall'app e viene distrutto, interromperà il servizio dall'esecuzione continua. La volta successiva che l'utente esegue l'app, recupererà nuovi aggiornamenti riavviando il servizio.

Nella parte superiore del file di classe, aggiungi le seguenti importazioni per la libreria Twitter4J:

 import twitter4j.Status; import twitter4j.Twitter; import twitter4j.TwitterFactory; import twitter4j.conf.Configuration; import twitter4j.conf.ConfigurationBuilder;

Con il seguente elenco per le risorse Android:

 importare android.app.Service; importare android.content.ContentValues; import android.content.Intent; importare android.content.SharedPreferences; import android.database.sqlite.SQLiteDatabase; importa android.os.Handler; importa android.os.IBinder; import android.util.Log;

E infine quanto segue per la classe Elenco Java:

 import java.util.List;

Per implementare la nostra classe di servizio forniremo i metodi "onCreate" e "onStartCommand" per quando la classe viene istanziata e il servizio avviato, il metodo "onDestroy" per quando termina e il metodo "onBind", che è richiesto anche se non lo useremo. Creeremo anche una classe interiore, in cui recupereremo gli aggiornamenti da Twitter a intervalli prestabiliti.

Innanzitutto, implementiamo il metodo "onCreate":

 @Override public void onCreate () super.onCreate (); // imposta la classe

All'interno del metodo, verranno istanziate alcune delle nostre variabili di istanza:

 // get prefs nicePrefs = getSharedPreferences ("TwitNicePrefs", 0); // get database helper niceHelper = new NiceDataHelper (this); // recupera il database niceDB = niceHelper.getWritableDatabase ();

Creiamo anche un'istanza dell'oggetto Twitter4J in modo che possiamo recuperare i tweet:

 // ottiene le preferenze dell'utente String userToken = nicePrefs.getString ("user_token", null); String userSecret = nicePrefs.getString ("user_secret", null); // crea una nuova configurazione Configuration twitConf = new ConfigurationBuilder () .setOAuthConsumerKey (TWIT_KEY) .setOAuthConsumerSecret (TWIT_SECRET) .setOAuthAccessToken (userToken) .setOAuthAccessTokenSecret (userSecret) .build (); // istanziare new twitter timelineTwitter = new TwitterFactory (twitConf) .getInstance ();

Dobbiamo implementare il metodo "onBind" anche se non lo usiamo realmente, quindi aggiungilo come segue:

 @Override public IBinder onBind (Intent intent) return null; 

Passaggio 2: creare una classe eseguibile

All'avvio del servizio, verrà eseguito il metodo "onStartCommand" e, quando viene distrutto, verrà attivato il metodo "onDestroy". Implementeremo presto entrambi questi metodi, ma prima creeremo una classe interna per gestire il recupero degli aggiornamenti a periodi fissi. All'interno della dichiarazione della classe "TimelineService", aggiungi il seguente schema di classe:

 / ** * La classe TimelineUpdater implementa l'interfaccia runnable * / class TimelineUpdater implementa Runnable // fetch updates

All'interno di questa classe recupereremo la timeline della home dell'utente, la scriverò nel database e invieremo una trasmissione all'attività principale quando ci saranno nuovi tweet da visualizzare. Tutto questo succederà nel metodo "run", quindi aggiungilo alla tua nuova classe interna come segue:

 // run metodo public void run () 

Trasmetteremo la trasmissione all'attività principale solo quando ci sono nuovi tweet, quindi per tenere traccia creiamo una variabile booleana nel metodo "run":

 // controlla gli aggiornamenti - si suppone che nessuno stato booleanoChanges = false;

Ora tenteremo di recuperare i dati da Internet, quindi dobbiamo provare a catturare i blocchi:

 prova // recupera timeline catch (Exception te) Log.e (LOG_TAG, "Exception:" + te); 

All'interno del blocco try, recupera la timeline dell'utente come oggetto List:

 // recupera i nuovi tweet della timeline della home list come elenco homeTimeline = timelineTwitter.getHomeTimeline ();

La cronologia recuperata è un elenco di oggetti Status. Ogni oggetto Status contiene i dati per un singolo aggiornamento dei tweet. Ora dobbiamo scorrere i nuovi tweet e inserirli nel database:

 // itera attraverso i nuovi aggiornamenti di stato per (Stato statusUpdate: homeTimeline) // chiama il metodo getValues ​​della classe helper di dati, passando i nuovi aggiornamenti ContentValues ​​timelineValues ​​= NiceDataHelper.getValues ​​(statusUpdate); // se il database contiene già gli aggiornamenti, non verranno inseriti niceDB.insertOrThrow ("home", null, timelineValues); // conferma che abbiamo nuovi aggiornamenti statusChanges = true; 

Si noti che stiamo chiamando il metodo "getValues" della classe NiceDataHelper, che è statico. Il metodo "getValues" prende gli oggetti dello stato di Twitter e recupera i dati rilevanti per il nostro database, ovvero l'ID tweet, il testo, lo screen-name, l'ora e l'URL dell'immagine del profilo, i quali sono contenuti in ciascuna istanza di Stato. Il metodo restituisce questi come set di valori che possono essere inseriti nel database, cosa che facciamo qui. Dato che ci sono nuovi tweet, impostiamo il flag "statusChanges" su true.

Dopo il blocco catch, inviamo una trasmissione all'attività principale solo se ci sono nuovi tweet da visualizzare:

 // se abbiamo nuovi aggiornamenti, invia un Broadcast if (statusChanges) // questo dovrebbe essere ricevuto nella classe timeline principale sendBroadcast (new Intent ("TWITTER_UPDATES")); 

Gestiremo la ricezione di questo nella classe di attività principale in seguito. Infine, dopo questa istruzione if e ancora all'interno del metodo "run", istruisci Android a chiamare di nuovo il metodo "run" dopo il tuo ritardo selezionato:

 // ritardare il recupero di nuovi aggiornamenti niceHandler.postDelayed (questo, FETCH_DELAY);

Nella parte superiore della classe TimelineService, aggiungi un'altra variabile di istanza per questa nuova classe:

 / ** oggetto thread di aggiornamento * / private TimelineUpdater niceUpdater;

Passaggio 3: avviare l'oggetto eseguibile

Ora possiamo gestire il metodo "TimelineService" per quando viene avviato il servizio. Tornando nella classe Service (al di fuori della nuova classe Runnable), aggiungi il metodo "onStartCommand":

 @Override public int onStartCommand (Intent intent, int flags, int startId) super.onStart (intent, startId); // get handler niceHandler = new Handler (); // crea un'istanza della classe updater niceUpdater = new TimelineUpdater (); // aggiungi alla coda di esecuzione niceHandler.post (niceUpdater); // return sticky return START_STICKY; 

Qui chiamiamo il metodo della superclasse e restituiamo un valore intero standard. Istanziamo anche il Gestore e la nuova classe Runnable. Il Gestore aggiunge il Runnable alla coda del processo in modo che venga eseguito il suo metodo "run".

Ora tutto ciò di cui abbiamo bisogno per finire la classe Service è implementare il metodo destroy:

 @Override public void onDestroy () super.onDestroy (); // interrompe l'aggiornamento di niceHandler.removeCallbacks (niceUpdater); niceDB.close (); 

Passaggio 4: ricevere le trasmissioni

Di nuovo nella principale classe di attività dell'app, ora possiamo avviare il servizio e ricevere le trasmissioni risultanti. Aggiungi la seguente variabile di istanza nella parte superiore della tua classe "TwitNiceActivity":

 / ** Ricevitore broadcast per quando sono disponibili nuovi aggiornamenti * / private BroadcastReceiver niceStatusReceiver;

Avrai bisogno della seguente dichiarazione di importazione:

 importare android.content.BroadcastReceiver;

Aggiungi una nuova classe interna alla tua classe di attività principale per ricevere le trasmissioni, assicurandoti di aggiungerla al di fuori di uno qualsiasi dei metodi ma ancora all'interno della dichiarazione della classe Attività:

 / ** * Classe per implementare la ricevuta di trasmissione per i nuovi aggiornamenti * / classe TwitterUpdateReceiver estende BroadcastReceiver 

Questa classe sta per fare una cosa: ricevere le trasmissioni - quindi implementare il metodo "onReceive" al suo interno:

 @Override public void onReceive (Context context, Intent intent) 

All'interno del metodo, ridurremo le dimensioni del database eliminando alcuni record ogni volta che nuovi tweet diventano disponibili:

 int rowLimit = 100; if (DatabaseUtils.queryNumEntries (timelineDB, "home")> rowLimit) String deleteQuery = "DELETE FROM home WHERE" + BaseColumns._ID + "NOT IN" + "(SELEZIONA" + BaseColumns._ID + "DA CASA ORDINA DA" + " update_time DESC "+" limit "+ rowLimit +") "; timelineDB.execSQL (deleteQuery); 

In questo caso limitiamo la tabella a 100 righe, ma puoi ovviamente cambiarla in un numero a tua scelta. La query elimina tutti tranne i 100 record più recenti nella tabella.

Aggiungi la seguente importazione alla classe:

 importare android.provider.BaseColumns; import android.database.DatabaseUtils; importare android.content.Context;

Ora dobbiamo interrogare il database e aggiornare le viste dell'interfaccia utente usando l'adattatore:

 timelineCursor = timelineDB.query ("home", null, null, null, null, null, "update_time DESC"); startManagingCursor (timelineCursor); timelineAdapter = new UpdateAdapter (context, timelineCursor); homeTimeline.setAdapter (timelineAdapter);

Si noti che usiamo un processo simile a quello che succede nel metodo "setupTimeline". Quando l'utente ha già eseguito l'app almeno una volta, all'avvio, vedrà i dati esistenti mentre vengono recuperati nuovi dati. Non appena i nuovi dati saranno disponibili, le visualizzazioni verranno aggiornate per visualizzarle. Naturalmente la velocità con cui ciò accade dipende dalla connettività di rete dell'utente.


Passaggio 5: avviare il servizio

Completiamo il metodo "setupTimeline". Dopo la riga in cui è stata creata l'istanza della classe UpdateAdapter l'ultima volta, prima che il blocco try termini, aggiungere quanto segue per impostare l'adapter sulla timeline:

 // questo renderà l'app popolare i nuovi dati di aggiornamento nella vista timeline homeTimeline.setAdapter (timelineAdapter);

Quindi creare un'istanza della classe Broadcast Receiver e registrarla per ricevere gli aggiornamenti dalla classe Service:

 // istanza ricevitore classe per scoprire quando sono disponibili nuovi aggiornamenti niceStatusReceiver = new TwitterUpdateReceiver (); // registrati per gli aggiornamenti registerReceiver (niceStatusReceiver, new IntentFilter ("TWITTER_UPDATES"));

Si noti che la stringa che forniamo al costruttore IntentFilter corrisponde alla stringa che usiamo quando si invia la trasmissione all'interno della classe Runnable di TimelineService.

Avrai bisogno della seguente importazione:

 import android.content.IntentFilter;

Infine, avvia il servizio, passando il nome della classe:

 // avvia il servizio per gli aggiornamenti ora this.getApplicationContext (). startService (new Intent (this.getApplicationContext (), TimelineService.class));

Prima di terminare, implementiamo il metodo destroy per la principale classe Activity poiché riguarda gli oggetti che abbiamo usato qui:

 @Override public void onDestroy () super.onDestroy (); prova // interrompi il servizio di aggiornamento stopService (new Intent (this, TimelineService.class)); // remove receiver register unregisterReceiver (niceStatusReceiver); // chiude il database timelineDB.close ();  catch (Exception se) Log.e (LOG_TAG, "impossibile arrestare il servizio o il destinatario"); 

Ogni volta che gestisci database e servizi, è importante non sprecare risorse lasciandoli in esecuzione quando l'app non viene effettivamente eseguita. Qui stiamo fermando il servizio, annullando la registrazione del ricevitore che abbiamo ascoltato e chiuso il database. Quando l'app verrà riavviata, verranno riavviati.


Il prossimo

Ora abbiamo implementato la visualizzazione dei tweet della timeline della home dell'utente, recuperandoli a intervalli fissi attraverso un Servizio e rilevandone il recupero tramite Broadcasts. Nel tutorial finale implementeremo tweeting, retweeting e replying. Ciò comporterà l'implementazione di una nuova attività Tweet e i pulsanti di retweet / risposta all'interno di ciascun aggiornamento nella timeline principale.