In deze serie bouwen we een Twitter-client voor het Android-platform met behulp van de Twitter4J-bibliotheek. Deze zelfstudie richt zich op het implementeren van een service om voortdurend nieuwe tweets op te halen voor de thuistijdlijn van de gebruiker. We zullen ook een Broadcast-ontvanger gebruiken om de app-interface bij te werken wanneer er nieuwe tweets beschikbaar komen voor weergave.
Om ervoor te zorgen dat de thuistijdlijn tweets automatisch worden weergegeven wanneer ze beschikbaar zijn, gaan we een service gebruiken om ze op gezette tijden op te halen. Deze dienst wordt uitgevoerd met een frequentie naar keuze, schrijft naar de database en verzendt uitzendingen wanneer nieuwe tweets zijn opgehaald en opgeslagen. De hoofdactiviteitsklasse van de app zal de broadcasts ontvangen en de database opvragen, waarbij de tijdlijninterface wordt bijgewerkt om de nieuwe gegevens weer te geven.
Maak een nieuwe klasse in uw project met de naam "TimelineService" en wijzig de openingsklasse-declaratie als volgt:
public class TimelineService verlengt Service
U heeft de volgende import nodig:
import android.app.Service;
Voeg de volgende instantievariabelen toe aan uw klas voor interactie met Twitter:
/ ** twitter authentication key * / public final static static TWIT_KEY = "uw sleutel"; / ** twittergeheim * / openbare definitieve statische reeks TWIT_SECRET = "uw geheim"; / ** twitter-object * / privé Twitter timelineTwitter;
Wijzig de sleutel- en geheime variabelen die bij uw eigen variabelen passen, zoals gebruikt in de vorige zelfstudies. Voeg de volgende variabelen toe voor het afhandelen van de database:
/ ** database-helperobject * / private NiceDataHelper niceHelper; / ** tijdlijndatabase * / private SQLiteDatabase niceDB;
Voeg ten slotte het volgende toe voor algemeen gebruik binnen de klas:
/ ** gedeelde voorkeuren voor gebruikersdetails * / private SharedPreferences nicePrefs; / ** handler voor updater * / private Handler niceHandler; / ** vertraging tussen het ophalen van nieuwe tweets * / private static int mins = 5; // wijzigen om te voldoen aan privé statische laatste lange FETCH_DELAY = mins * (60 * 1000); // debugging tag private String LOG_TAG = "TimelineService";
Het Handler-object dient voor het plannen van updates op ingestelde frequenties. Met de constante "mins" en "FETCH_DELAY" kunt u de frequentie instellen waarmee de app nieuwe updates ophaalt van de starttijdlijn van de gebruiker. Wijzig de "mins" -variabele om rekening te houden met het aantal minuten dat u wilt dat de app tussen updates wacht. De updates worden alleen op deze frequentie opgehaald terwijl de app wordt uitgevoerd. Wanneer de gebruiker de app verlaat en deze wordt vernietigd, stopt de service voortdurend. De volgende keer dat de gebruiker de app uitvoert, worden nieuwe updates opgehaald door de service opnieuw te starten.
Voeg de volgende imports voor de Twitter4J-bibliotheek toe aan de bovenkant van uw klassenbestand:
import twitter4j.Status; import twitter4j.Twitter; import twitter4j.TwitterFactory; import twitter4j.conf.Configuration; import twitter4j.conf.ConfigurationBuilder;
Met de volgende lijst voor Android-bronnen:
import android.app.Service; import android.content.ContentValues; importeer android.content.Intent; importeer android.content.SharedPreferences; importeer android.database.sqlite.SQLiteDatabase; import android.os.Handler; import android.os.IBinder; import android.util.Log;
En tot slot het volgende voor de klasse Java-lijst:
importeer java.util.List;
Om onze serviceklasse te implementeren, bieden we de methoden "onCreate" en "onStartCommand" voor wanneer de klasse wordt gestart en de service wordt gestart, de "onDestroy" -methode voor wanneer deze is voltooid en de "onBind" -methode, die vereist is hoewel we het niet zullen gebruiken. We gaan ook een innerlijke klasse maken, waarin we de updates van Twitter met vaste tussenpozen zullen ophalen.
Laten we eerst de methode "onCreate" implementeren:
@Override public void onCreate () super.onCreate (); // de klas instellen
Binnen de methode zullen we enkele instantievariabelen instantiëren:
// get prefs nicePrefs = getSharedPreferences ("TwitNicePrefs", 0); // krijg database-helper niceHelper = new NiceDataHelper (this); // haal de database op niceDB = niceHelper.getWritableDatabase ();
Laten we ook een instantie van het Twitter4J-object maken, zodat we tweets kunnen ophalen:
// krijg gebruikersvoorkeuren String userToken = nicePrefs.getString ("user_token", null); String userSecret = nicePrefs.getString ("user_secret", null); // nieuwe configuratie maken Configuratie twitConf = nieuwe ConfigurationBuilder () .setOAuthConsumerKey (TWIT_KEY) .setOAuthConsumerSecret (TWIT_SECRET) .setOAuthAccessToken (userToken) .setOAuthAccessTokenSecret (userSecret) .build (); // instantiate nieuwe twitter timelineTwitter = nieuwe TwitterFactory (twitConf) .getInstance ();
We moeten de "onBind" -methode implementeren, hoewel we deze niet echt gebruiken, dus voeg deze als volgt toe:
@Override openbare IBinder onBind (Intent opzet) return null;
Wanneer de service start, wordt de methode "onStartCommand" uitgevoerd en wanneer deze wordt vernietigd, wordt de methode "onDestroy" geactiveerd. We zullen beide methoden binnenkort implementeren, maar eerst zullen we een innerlijke klasse maken om de updates op vaste tijden op te halen. Voeg in uw klassementsdeclaratie "TimelineService" de volgende klasseschema toe:
/ ** * TimelineUpdater-klasse implementeert de uitvoerbare interface * / class TimelineUpdater implementeert Runnable // fetch updates
Binnen deze klasse halen we de thuistijdlijn van de gebruiker op, schrijven deze naar de database en sturen een uitzending naar de hoofdactiviteit wanneer er nieuwe tweets zijn die moeten worden weergegeven. Dit gaat allemaal gebeuren in de "run" -methode, dus voeg het als volgt aan je nieuwe innerlijke klasse toe:
// run-methode public void run ()
We sturen de uitzending alleen naar de hoofdactiviteit als er nieuwe tweets zijn, dus om bij te houden, creëren we een booleaanse variabele binnen de "run" -methode:
// controleer op updates - neem geen boolean statusChanges = false;
Vervolgens gaan we proberen gegevens van internet te halen, dus we moeten blokken proberen vangen en vangen:
probeer // haal tijdlijn op vangst (uitzondering te) Log.e (LOG_TAG, "Uitzondering:" + te);
Zoek in het try-blok de tijdlijn van de gebruiker op als een List-object:
// haal de nieuwe thuistijdlijn tweets op als een lijstlijsthomeTimeline = timelineTwitter.getHomeTimeline ();
De opgehaalde tijdlijn is een lijst met statusobjecten. Elk Status-object bevat de gegevens voor een enkele tweet-update. Nu moeten we de nieuwe tweets doorlopen en ze in de database invoegen:
// itereer door middel van nieuwe statusupdates voor (Status statusUpdate: homeTimeline) // call de getValues-methode van de data helper-klasse, waarbij de nieuwe updates worden doorgegeven ContentValues timelineValues = NiceDataHelper.getValues (statusUpdate); // als de database al de updates bevat, worden deze niet ingevoegd niceDB.insertOrThrow ("home", null, timelineValues); // bevestigen dat we nieuwe updates statusChanges = true hebben;
Merk op dat we de "getValues" -methode van de klasse NiceDataHelper, die statisch is, aanroepen. De "getValues" -methode neemt Twitter-statusobjecten en haalt de relevante gegevens voor onze database op, d.w.z. de tweet-ID, tekst, schermnaam, tijd en profielafbeeldings-URL, die alle zijn opgenomen in elke statusinstantie. De methode retourneert deze als sets waarden die in de database kunnen worden ingevoegd, wat we hier doen. Omdat er nieuwe tweets zijn, zetten we de vlag "statusChanges" op true.
Na het catch-blok sturen we alleen een broadcast naar de hoofdactiviteit als er nieuwe tweets zijn die kunnen worden weergegeven:
// als we nieuwe updates hebben, stuur dan een uitzending als (statuswijzigingen) // dit moet worden ontvangen in de hoofdtijdlijnklasse sendBroadcast (nieuwe intentie ("TWITTER_UPDATES"));
We zullen de ontvangst van dit in de hoofdactiviteitsklasse later verwerken. Eindelijk, na deze if-instructie en nog steeds binnen de "run" -methode, instrueer Android om de "run" -methode opnieuw te bellen na de gekozen vertraging:
// vertraging ophalen van nieuwe updates niceHandler.postDelayed (this, FETCH_DELAY);
Voeg aan de bovenkant van uw klasse TimelineService een andere exemplaarvariabele toe voor deze nieuwe klasse:
/ ** updater thread object * / private TimelineUpdater niceUpdater;
Nu kunnen we omgaan met de "TimelineService" -methode voor wanneer de service start. Terug in de klasse Service (buiten de nieuwe Runnable-klasse), voegt u de methode "onStartCommand" toe:
@Override public int onStartCommand (Intent intent, int flags, int startId) super.onStart (intent, startId); // krijg handler niceHandler = new Handler (); // maak een instantie van de updater-klasse niceUpdater = new TimelineUpdater (); // add to run queue niceHandler.post (niceUpdater); // return sticky return START_STICKY;
Hier noemen we de methode van de superklasse en retourneren een standaard integer-waarde. We geven ook de handler en de nieuwe Runnable-klasse een instantiatie. De handler voegt Runnable toe aan de proceswachtrij, zodat de "run" -methode wordt uitgevoerd.
Nu is alles wat we nodig hebben om de Service-klasse af te maken de uitvoering van de vernietigingsmethode:
@Override public void onDestroy () super.onDestroy (); // stop het updaten van niceHandler.removeCallbacks (niceUpdater); niceDB.close ();
Terug in de hoofdactiviteitsklasse van de app kunnen we nu de service starten en de resulterende uitzendingen ontvangen. Voeg de volgende instantievariabele toe aan de bovenkant van uw klasse "TwitNiceActivity":
/ ** Broadcast-ontvanger voor wanneer nieuwe updates beschikbaar zijn * / private BroadcastReceiver niceStatusReceiver;
U hebt de volgende importverklaring nodig:
import android.content.BroadcastReceiver;
Voeg een nieuwe binnenklasse toe aan uw hoofdactiviteitsklasse om uitzendingen te ontvangen, zorg ervoor dat u deze buiten een van de methoden maar nog steeds in de klasse-declaratie van de klasse toevoegt:
/ ** * Klasse om Broadcast-ontvangst uit te voeren voor nieuwe updates * / class TwitterUpdateReceiver breidt BroadcastReceiver uit
Deze klasse gaat één ding doen: Uitzendingen ontvangen - dus implementeer de "onReceive" -methode erin:
@Override public void onReceive (Context context, Intent intent)
Binnen de methode gaan we de grootte van de database minimaliseren door een aantal records te verwijderen wanneer er nieuwe tweets beschikbaar komen:
int rowLimit = 100; if (DatabaseUtils.queryNumEntries (timelineDB, "home")> rowLimit) String deleteQuery = "DELETE FROM home WHERE" + BaseColumns._ID + "NOT IN" + "(SELECT" + BaseColumns._ID + "FROM home BESTEL BY" + " update_time DESC "+" limit "+ rowLimit +") "; timelineDB.execSQL (deleteQuery);
In dit geval beperken we de tabel tot 100 rijen, maar u kunt dit natuurlijk wijzigen naar een nummer van uw keuze. Met de query worden alle 100 nieuwe records in de tabel verwijderd.
Voeg de volgende import toe aan de klas:
importeer android.provider.BaseColumns; importeer android.database.DatabaseUtils; importeer android.content.Context;
Nu moeten we de database opvragen en de weergave van de gebruikersinterface bijwerken met behulp van de adapter:
timelineCursor = timelineDB.query ("home", null, null, null, null, null, "update_time DESC"); startManagingCursor (timelineCursor); timelineAdapter = nieuwe UpdateAdapter (context, tijdlijnCursor); homeTimeline.setAdapter (timelineAdapter);
Merk op dat we een soortgelijk proces gebruiken als wat er gebeurt in de "setupTimeline" -methode. Wanneer de gebruiker de app al minstens één keer heeft uitgevoerd, zien deze bij het opstarten de bestaande gegevens terwijl nieuwe gegevens worden opgehaald. Zodra de nieuwe gegevens beschikbaar zijn, worden de weergaven bijgewerkt om deze weer te geven. Natuurlijk is de snelheid waarmee dit gebeurt afhankelijk van de netwerkverbinding van de gebruiker.
Laten we de methode "setupTimeline" voltooien. Na de regel waarin u de laatste keer de klasse UpdateAdapter hebt geïnstantieerd, voordat het try-blok wordt beëindigd, voegt u het volgende toe om de adapter op de tijdlijn in te stellen:
// hierdoor zal de app de nieuwe updategegevens vullen in de tijdlijnweergave homeTimeline.setAdapter (timelineAdapter);
Maak vervolgens een instantie van uw Broadcast Receiver-klasse en registreer deze om updates van de serviceklasse te ontvangen:
// instantiate receiver class om uit te vinden wanneer nieuwe updates beschikbaar zijn niceStatusReceiver = new TwitterUpdateReceiver (); // registreer voor updates registerReceiver (niceStatusReceiver, nieuw IntentFilter ("TWITTER_UPDATES"));
Merk op dat de String die we aan de constructor IntentFilter hier geven overeenkomt met de String die we gebruiken bij het verzenden van de Broadcast binnen de klasse TimelineService Runnable.
U heeft de volgende import nodig:
importeer android.content.IntentFilter;
Start ten slotte de service en geef de klassenaam door:
// start de Service voor updates nu this.getApplicationContext (). startService (new Intent (this.getApplicationContext (), TimelineService.class));
Voordat we klaar zijn, laten we de vernietigingsmethode voor de hoofdactiviteitklasse implementeren, omdat het objecten betreft die we hier hebben gebruikt:
@Override public void onDestroy () super.onDestroy (); probeer // stop the updater Service stopservice (nieuwe Intent (this, TimelineService.class)); // verwijder ontvangerregister unregisterReceiver (niceStatusReceiver); // sluit de databasetijd timelineDB.close (); catch (Exception se) Log.e (LOG_TAG, "kan service of ontvanger niet stoppen");
Wanneer u met databases en Services omgaat, is het belangrijk om geen bronnen te verspillen door ze te laten werken wanneer de app niet daadwerkelijk wordt uitgevoerd. Hier stoppen we de Service, verwijderen we de ontvanger waar we naar hebben geluisterd en sluiten we de database. Wanneer de app opnieuw wordt gestart, worden deze allemaal opnieuw gestart.
We hebben nu geïmplementeerd met weergave van de thuistijdlijn tweets van de gebruiker, deze met vaste intervallen ophalen via een service en hun ophalen detecteren met behulp van broadcasts. In de laatste tutorial implementeren we tweeten, retweeten en antwoorden. Dit omvat het implementeren van een nieuwe Tweet Activity en de retweet / reply-knoppen binnen elke update in de hoofdtijdlijn.