Creating a Twitter Client for Android: Tweeting, Retweeting, and Replying

In this series we are building a Twitter client for the Android platform using the Twitter4J library. This tutorial will focus on implementing tweeting, retweeting, and replying to tweets. We will create a new Activity for tweeting and replying, with retweet and reply buttons implemented for each tweet in the user's home timeline.

Creating a Twitter Client for Android: Tweeting, Retweeting, and Replying

In the first four tutorials we:

Registered the app with Twitter.

Imported the Twitter4J library.

Handled user authentication.

Built the user interface using XML resources.

Created an SQLite database to store the tweets for the user's home timeline.

Mapped the data to the visible Views using an Adapter.

Fetched new updates periodically using a Service and Broadcast.

Step 1: Create a Tweet Activity

Our app is going to have a second Activity in addition to the main timeline screen. This new Activity is for sending Tweets. Inside it, the user can enter text to send a tweet from their Twitter account. The user may enter the Tweet Activity in two ways - by pressing the Tweet button on the app's main screen or by pressing a reply button within the timeline.

If the user presses the Tweet button, they will be presented with an empty text-field for entering their tweet, with a send button to go ahead and send it.

If the user presses the reply button within a timeline tweet, they will also be presented with the text-field, but the reply-to username will already be populated within the field. The reply must also be sent using the ID of the tweet being replied to, which we will implement as well.

Create a new class in your Android project, naming it "NiceTweet" to match the name you included in your Manifest file in the first tutorial. Alter the class declaration as follows:

We will use the Preferences, Twitter, key and secret variables to access the Twitter4J methods for tweeting from the user account. Alter the key and secret to suit your own. The final two variables are for replies. When the user presses the reply button within a tweet, we are going to pass the ID of the tweet being replied to, together with the Twitter screen-name of the account we are replying to. We will store these in the two instance variables.

Here we create a Twitter object using the user's authentication information together with the developer key and secret for the application. When we take users to this Activity class, we are going to pass in the ID and username if a tweet is being replied to. We get these from the Intent:

//get any data passed to this intent for a reply
Bundle extras = getIntent().getExtras();

If the tweet is an ordinary update rather than a reply, there will be no extras. If there are extras, we know the tweet is a reply:

if(extras !=null)
{
//get the ID of the tweet we are replying to
tweetID = extras.getLong("tweetID");
//get the user screen name for the tweet we are replying to
tweetName = extras.getString("tweetUser");
//use the passed information
}

Here we retrieve the ID and screen-name for the tweet to reply to. Next we use this information to add the username to the text-field, still inside the "if" statement:

//get a reference to the text field for tweeting
EditText theReply = (EditText)findViewById(R.id.tweettext);
//start the tweet text for the reply @username
theReply.setText("@"+tweetName+" ");
//set the cursor to the end of the text for entry
theReply.setSelection(theReply.getText().length());

We set the username as the first part of the tweet text, placing the cursor at the end so that the user can type their reply text straight away.

Here we simply set the text to an empty String, again using the ID we gave the text-field in the layout XML. Now we can finish the "setupTweet" method by adding click listeners for the "send" button and the "home" button for returning to the main timeline screen:

Step 3: Detect Clicks

Remember that the Tweet Activity is going to contain a button to take users back to the home timeline as well as the button to send the tweet. Let's now add the "onClick" method to handle users clicking these buttons:

Here we check whether the tweet is a reply or not. The "if" statement executes if the tweet is a reply, including the text from the text-field and the ID of the status update we are replying to. The "else" statement takes care of sending ordinary tweets, in which only the text is passed as parameter. The try and catch blocks are necessary as we are attempting to connect to Twitter over the network. After sending the tweet, whether a reply or not, we set the text-field back to empty in preparation for the next tweet update.

For the "homebtn" case statement, simply set the text-field to an empty String:

tweetTxt.setText("");

Finally, after the switch statement but still inside the "onClick" method, finish the Activity so that it returns to the home timeline:

finish();

Whether the tweet is a reply or an ordinary update, we immediately take the user back to the main screen when it is sent, which we also do when they press the home button - the finish statement will execute in all three cases.

Step 4: Model Tweet Data for Retweets and Replies

To implement retweeting and replying, we need to store the tweet ID and user screen-name within the retweet and reply buttons for each tweet in the timeline. By storing this data within the button Views for retweet and reply, we will be able to detect which tweet is being retweeted or replied to when the user presses a button.

Because the information we need to store comprises a number and some text, we will create a class to model it. Create a new class in your project and name it "StatusData". Your new class should begin as follows:

public class StatusData {

Inside the class, add instance variables for the tweet ID and username:

The method simply instantiates the two variables. Next add a public method so that we can retrieve the tweet ID elsewhere:

/**
* Get the ID of the tweet
* @return tweetID as a long
*/
public long getID() {return tweetID;}

Then add a method to return the screen-name:

/**
* Get the user screen name for the tweet
* @return tweetUser as a String
*/
public String getUser() {return tweetUser;}

These methods will allow us to retrieve this information when users click the retweet or reply button for a particular tweet.

Step 5: Extend Binding for Retweets and Replies

Now we need to extend the code in the Adapter class we created ("UpdateAdapter"). In the "bindView" method, we tailored the mapping of data to the user interface Views. Now we will add further processing to include the tweet data within each retweet and reply button. Before the end of your "bindView" method, begin as follows:

Remember that the "bindView" method is passed a Cursor object for traversing the data. Here we use the Cursor to retrieve the long ID value and String username for the current tweet. You will need the following additional import:

import android.provider.BaseColumns;

Now we will instantiate an object of our new StatusData class, passing the tweet data to the constructor method:

//create a StatusData object to store these
StatusData tweetData = new StatusData(statusID, statusName);

The StatusData object contains everything necessary to send a retweet or reply for the tweet in question. We will now attach a reference to this object within the retweet and reply buttons for the tweet, so that we can access the information following user clicks. We use the "setTag" method:

//set the status data object as tag for both retweet and reply buttons in this view
row.findViewById(R.id.retweet).setTag(tweetData);
row.findViewById(R.id.reply).setTag(tweetData);

The "bindView" method also receives a parameter representing the row View in which the tweet is going to be displayed. If you look back at the update XML layout file, you will see that these two ID values are included for the buttons. We set the tag in each button to reflect the StatusData object holding the ID and username for the tweet displayed. Now we need to setup button clicks for these:

Here we specify a click listener to handle button clicks. Inside the listener method, we will be able to retrieve the StatusData objects of any retweet and reply buttons clicked. We are also going to allow users to click the username for a tweet in order to open the user profile in the Web browser. Add a click listener to that View here as well:

//setup onclick for the user screen name within the tweet
row.findViewById(R.id.userScreen).setOnClickListener(tweetListener);

This will allow us to link into the Twitter Web interface so that users can access functions we have not provided within the app itself.

Step 6: Handle Button and Username Clicks

In your UpdateAdapter class, create an "onClickListener" to handle clicks, using the name "tweetListener" to match what we specified in the "bindView" method:

Inside the reply case statement, we start the Tweet Activity class, passing the reply data so that the reply ID and username can be included when sending the tweet:

//create an intent for sending a new tweet
Intent replyIntent = new Intent(v.getContext(), NiceTweet.class);
//get the data from the tag within the button view
StatusData theData = (StatusData)v.getTag();
//pass the status ID
replyIntent.putExtra("tweetID", theData.getID());
//pass the user name
replyIntent.putExtra("tweetUser", theData.getUser());
//go to the tweet screen
v.getContext().startActivity(replyIntent);

Notice that we retrieve the tag for the pressed View, casting it as a StatusData object. We then call the public methods we provided within the StatusData class to return the tweet ID and user screen-name. We pass these to the Tweet Activity as extras, then start the Activity. At this point the user will be taken to the Tweet screen where the reply data will be used to implement replying to the correct tweet.

In the retweet case statement, we will retweet the relevant tweet directly, using the Twitter4J methods. First instantiate a Twitter object using the Shared Preferences plus your developer key and secret for the app:

This is the same technique we have used to instantiate the Twitter class before. We can now use the Twitter object to send the retweet. First we need to retrieve the StatusData object from the button that has been clicked:

Here we retrieve the user name as a text String from the View itself, which displays the screen-name as a String anyway. We build this into a Twitter profile page address, parsing it as a URI and instructing the browser to open it.

Step 7: Implement Moving from Home to Tweet

Remember that our main app Activity displays a button to take users straight to the Tweet screen. Let's implement that now. In your main Activity class, add the following inside your "setupTimeline" method, anywhere after you set the main content view:

The Tweet button ID matches what we included in the main timeline XML layout file. The main Activity class is going to handle clicks of the Tweet button. If you look at your "onClick" method within the main Activity ("TwitNiceActivity" if you used the name in the first tutorial), you should see a switch statement with one case statement for the "signin" button. Add a second case statement for the Tweet button as follows (before the default statement):

Here we simply start the Tweet Activity. We do not need to pass any information to the Activity as in this case the user is simply launching it to send an ordinary tweet.

That's It!

That's our Twitter app complete! Run the app on an emulator or device to see it function. On first run you will of course have to consent to let the app use your Twitter account. You can optionally create a separate Twitter account to test the app with, rather than using your normal account. After authorization, you should be presented with the home timeline representing the most recent tweets from the accounts you follow. Test tweeting, retweeting and replying, as well as making sure your timeline is automatically updating at your chosen interval.

Advanced Topics

In this tutorial series we have created a basic Twitter client for Android. There are many ways in which you could enhance and improve upon the app, such as including the ability to view direct messages or to view user profiles within the app rather than having to use the Web browser. You could also make mentions of users within tweets clickable (i.e. linking any text String preceded by "@" to the profile page for that user). A similar process would allow you to support hashtags. More advanced Twitter clients also display conversations when selecting an individual tweet, showing replies in chronological order.

In terms of the application implementation, there are also enhancements you could consider. For example, in case the user has low connectivity, you could implement downloading the profile images as a background process. You could also implement some form of image caching to maximize on efficiency. Rather than the app automatically refreshing the ListView with new Tweets, you could implement a button at the top of the timeline, for users to control the display, with the button indicating how many new tweets are available. Finally, you could improve efficiency by running the Service in a separate Thread.

Thanks For Reading

Hope you've enjoyed this series on Creating a Twitter Client for the Android platform! As well as learning how to connect your apps to Twitter, you now have experience of using an external library plus a variety of Android platform resources such as Databases, Adapters, Services and Broadcasts. These are all key skills your future Android projects will benefit from. The downloadable source code contains additional notes you may find helpful.