Showing posts with label twitter. Show all posts

Machine Learning with AWS & Scala

Recently, in an attempt to starting learning React, I started building an akka-http backend API as a starting point. I quickly got distracted building the backend and ended up integrating with both the Twitter streaming API and AWS' Comprehend sentiment analysis API - which is what this post will be about.

Similar to an old idea, where I built an app consuming tweets about the 2015 Rugby world cup, this time my app was consuming tweets about the FIFA world cup in Russia - splitting tweets by country and recording sentiment for each one (and so a rolling average sentiment for each team).


Overview

The premise was simple:

  1. Connect to the Twitter streaming API (aka the firehose) filtering on world cup related key words
  2. Pass the body of the tweet to AWS Comprehend to get the sentiment score
  3. Update the in memory store of stats (count and average sentiment) for each country

In terms of technology used:
  1. Scala & Akka-Http
  2. Twitter4s Scala client
  3. AWS Java SDK

As always, all the code is on Github - to run it locally, you will need a Twitter dev API key (add an application.conf as per the readme on the Twitter4s github) and you will also need an AWS key/secret - the code will look for credentials stored locally but you can also just set them in environment variables before starting. The free tier supports up to 50,000 Comprehend API requests in the first 12 months - and as you can imagine, plugging this directly into twitter can result in lots of calls, so make sure you restrict it (or at least monitor it) before you leave it running!


Consuming Tweets

Consuming tweets is really simple with the Twitter4s client - we just define a partial function that will handle the incoming tweet. 

The other functions about parsing countries/teams are excluded for brevity - and you can see its quite simple - each inbound tweet we make a call to the Sentiment Service (we will look at that later) then pass it with the additional data to our update service that will then store it in memory. You will also see it is ridiculously easy to start the Twitter streaming client filtering by key words.


Detecting Sentiment

Because I wanted to be able to stub out the sentiment analysis without being tied to AWS, you will notice I am using the self-type annotation on my twitter class above, which requires a SentimentModule to be passed in at construction - I am using a simple cake pattern to manage all my dependencies here. In the Github repo, there is also a Dummy implementation, that will just pick a random number for the score, so you can still see the rest of the API working - but the interesting part is the AWS integration:
Once again, the SDK makes the integration really painless - in my code I am simplifying the actual results a lot to a much cruder Positive/Neutral/Negative rating (plus a numeric score -100..100).

The AWSCredentials class is the bit that is going to look in the normal places for an AWS key.


Storing and updating our stats

So now we have our inbound tweets and a way to asses their sentiment score - I then setup a very simple akka actor to manage the state and just stored the API data in memory (if you restart the app, the store gets reset and the API stops serving data).

Again, very simple out of the box stuff for akka, but it allows easy and thread safe management of the in-memory data store. I also track a rolling list of the last twenty tweets processed, which is managed by a second, almost identical, actor.


The results

I ran the app during several games, below are some sample outputs from the API. The response from the stats API is fairly boring reading (just numbers) but the example tweets show two examples of a positive and neutral tweet correctly identified (apologies for the expletives in the tweet about Poland - I guess that fan wasn't too happy about being beaten by the Senegalese!) - you will also notice, the app captures the countries being mentioned, which exposes one flaw of the design: in the negative tweet from the Polish fan loosing two goals to Senegal, it correctly identifies the sentiment as negative, but we have no way to determine the subject - as both teams are mentioned, the app naively assigns it as a negative tweet to both of the teams, where as on reading, it is clearly negative with regards to Poland (I wasn't too concerned for my experiment, of course, just an observation worth noting).

Sample tweet from the latest API:

Sample response from the stats API:

When I finally did get around to starting to learn React, I just plugged in the APIs and paid no attention to styling, which is a round about way of apologising for the horrible appearence of the screenshot below (I'm really sorry about the css gradient)!





Sentiment analysis of stock tweets

Having previously wired up a simple spring app with Twitter to consume their tweet stream relating to last year's Rugby World Cup - mostly just to experiment with the event-driven programming model in Spring and Reactor - I thought on a whim, why not see if I can find some nice sentiment analysis tools to analyse the tweets, so rather than just consuming the number of tweets about a given topic, I could also analyse if they were positive or not.


Now, that probably sounded like a fairly glib comment. And to be honest, it was: sentiment analysis is very hard, and the last time I looked most efforts were not up to much. Added to that, to make it actually effective, you need some pretty specific training data - for example, if you had a model trained using this blog and then tried to apply that to another sort of text - say tweets - then it's most likely not going to perform well.  Tweets are particularly different as people use different language, grammar and colloquialisms on twitter (in part due to the 140 chars limit) compared to normal writing.

But still, I had my laptop on my commute home on the train, so I figured why not see if there are any simple sentiment analysis libraries that I could just drop in and run the tweets through.  Sure the resulting scores would likely be way off, but it would be an interesting experiment to see how easy it was (and if done, could we then find a decent training set to re-train our model so it was more accurate at analysing tweets).


A quick google later and I came across Stanford's Core NLP (Natural Language Processing) library, via the snappily titled "Twitter Sentiment Analysis in less than 100 lines of code!" (which seemed just as flippant as my original suggestion, so seemed like a good fit!).  Surprisingly, it was actually just as easy as I had hoped that it might of been! The libraries are nicely available in the maven repo, coming with a pre-trained model (albeit trained on film reviews) and are written in Java.  A lot of the code is taken from the approach outline in the above article and the Stanford Core NLP sample class, but its pretty simple and I managed to process a few thousand tweets last night having set it all up on my commute and analyse the sentiment (producing wildly in-accurate sentiment scores - but who's to know, right?!)

(I switched to streaming stock related tweets - mostly just so I could include references to Eddie Murphy in Trading Places)

Updating our dependencies

I will skip the normal app setup and Twitter connection stuff, as I was just building this on top of the app I had previously done for the RWC (which already connected to the Twitter streaming API and persisted info to Redis.

All we need to do here is add the two Stanford dependencies - you can see I also added a dependency for Twitter's open-source library - this provides tweet cleanup/processing stuff, and really just used to extract "cashtags" (like a hashtag, but starting with a $ used on Twitter to indicate stock symbols, e.g. $GOOGL etc).


Spring configuration

Next up, as we are using Spring its super easy to just add the configuration so we can let Spring manage our Stanford NLP objects and inject them into our service class that will have the code to analyse the sentiment

Now we have told Spring to manage the main Stanford class we need and the simple Twitter Extractor class. For the StanfordCoreNLP class we are passing in some properties for what text analysis we want to use (this can usually be done with a properties file, but I was feeling lazy so did it programatically - you can see details of which Annotators are available here: http://stanfordnlp.github.io/CoreNLP/annotators.html )


Next up, based on the code examples we have seen, we need a little bit of code to analyse a piece of text and return a score - So I created a simple Spring service called SentimentService that I later wire into my event listener.

That's mostly it really, in my event listener instead of just persisting the tweet along with its labels I also run the analysis and also save the score.


 (Analysis of a couple thousand tweets - an average score plus number of tweets for each symbol)

As always, all the code is available on GitHub, so feel free to fork it and play yourself (and if you manage to find a training set to accurately analyse tweets then let me know!)

Twitter API & Smartphone as your identity

At Twitter's Flight conference this week, they announced a couple of new toys for developers: Fabric and Digits.

Fabric is a new platform for building mobile apps

The Fabric platform is made of three modular kits that address some of the most common and pervasive challenges that all app developers face: stability, distribution, revenue and identity.


It seems everyone has to be building a platform these days, but really it sounds like Twitter, having previously shut down developers on their API/platform a while ago, realised that actually letting devs on their platform (now that it includes advertising APIs - thanks to their MoPub acquisiting a while ago) is going to be profitable for them.

Maybe it will be well received, and the way the market changes maybe people will go for it - but I wouldn't be building an app based around a Twitter platform given their track record.  The company are a lot older, and maturer now (and they probably released their API too early last time around), but it still seems like quite a risk to have something as central as login/revenue tied to Twitter (I dont like third party logins anyway..).



Anyway, the much more interesting product they released was Digits - which allows sign-in with your mobile number - which as I have ranted before, is an idea that I love, and seems like a really smart move by Twitter. Both in as much that it will move twitter to that space of smartphone is your social-identity/network and also offers a lot more value than just another platform that serves ads and supports login etc.

Building a Twitter style autocomplete for Android

I have recently been working on an android app and found myself needing a Twitter style input box that allowed certain words to be looked up using an API driven autocomplete but also supporting freetext (if you have used the compose tweet input on android, like this - free text, but if you type @ then you get a user name autocomplete).



I google'd for a while, and stumbled through a few StackOverflow answers but none of there were 100% clear, and further more, just copy-pasting the code into a dummy project I was working in didn't work. So here is a break down of the what and how this works.

There are four main components:

The XML Layout: MultiAutoCompleteTextView


This is simple - just add the MultiAutoCompleteTextView just like you would any input. The only point of interest here is the "completionThreshold" - this is just the number of characters that have to be typed before auto-complete kicks in. We have set this to one char so it kicks in early.


We then just setup the auto-complete in our Activity onCreate

SetTokeniser: UsernameTokenizer

This is a custom class that implements the Tokenizer interface. This will be used by our autocomplete imput box to work out whether or not it should be displaying a dropdown menu. If you are using a static list for lookups (countries, fixed codes from your app, etc) then this is the only thing you really need to do - then you can just set the fields ArrayAdapter as the list of Strings etc and it will automatically kick in.

In our case, we are using the @ character to identify the start of pieces of text that should be lookedup and spaces to determine the end of the look up token.


The three methods are relatively straight forward - and will drive when your app presents the drop down:
  • terminateToken(CharSequence text) - this basically just provides a presentable version of our token with a proper terminator at the end (e.g. makes sure a trailing single space in this case)
  • findTokenStart(CharSequence text, int cursor) - Just finds the position of the start of the token. It does this by iterating backwards through the provided CharSequence (the text input in the input box) starting from the position of the cursor, which is just the position of the last character edited (this means if you go back and edit text in the middle of a block it still finds the correct token).  If no valid token start is found (e.g. we go backwards and we can't find a @ character) then the current position is returned - no dropdown is displayed.
  • findTokenEnd(CharSequence text, int cursor) - As above, but finds the end position. Iterates forward until a token terminator (in our case a space) or the end of the text is found

As long as you implement these to support your token identification pattern then you will get a dropdown appearing appropriately.


Adding a text changed listener

For ease of use on this one, I have just set the activity to implement the TextWatcher interface - the reason for this is just convenience - the implementation is going to handle calling our API asyncronously, so it is easier if it has the activity context.

There are three methods that need to be implemented - four our case there will be two no-op methods and just one implementation:


The method onTextChanged is implemented - unfortunately the tokenizer will only indicate to the application when to display the dropdown - it doesn't actually call the API, so we have to slightly repeat ourselves here in handling the API invocation.  In this method we need to again check for and find the relevant valid token in the input, and if a valid token found, then pass it to our API to lookup the dataset.

To help with that, I also added some additional methods to help check for the existence of a valid token (reading them should be self explanatory, but comments included inline)


In this case, as it was just an experiment, and I didn't actually have a user lookup API I have just used the LinkedIn skills API (this code also taken in part from a StackOverflow answer).

The Async task should also be straight forward, and can be implemented in whatever pattern you are using for Async calls - but the key point to note is how we are updating our dropdown list.


The API driven, multi-autocomplete/free text field should then be working as expected



Spring Social Integration

So, you may notice that I am something of a Spring fan, and generally like to try out different Spring projects where I get the chance. I have been aware of the Spring Social project for a little while (was looking at integrating LinkedIn with flutterby but decided against it), so recently, when a competition was announced in work to create a Java web app in the cloud for a chance to win a new Android tablet I thought this would be a good chance to put together something of a showcase of technology.

As always, the web app is a straight forward Spring MVC project built with the current latest Spring libraries (3.1 - also making use of declarative caching with ehcache, which was nice) and also includes the Spring Data MongoDB integration (again - primarily because it seems to be the most commonly supported NoSQL db in the cloud.. well CloudFoundry and OpenShift anyways). I also took the opportunity to integrate some Spring Social stuff, so I will go through that, as its pretty easy (will post again on some thoughts about Redhat's OpenShift platform and further SpringSocial stuff).



Maven Configuration

First of all, there is obviously some Maven configuration needed in the pom. It took me a little while to find the correct repositories to get all the different Spring Social libraries from (some implementations are less mature than others so not all have full proper releases yet)


	 spring-snapshot
	 Spring Maven Snapshot Repository
	 http://maven.springframework.org/snapshot



	 spring-milestone
	 Spring Maven Milestone Repository
	 http://maven.springframework.org/milestone




 Next we need to add the libraries we need:


	org.springframework.social
	spring-social-web
	${spring-social.version}
	
		
			spring-core
			org.springframework
		
		
			spring-web
			org.springframework
		
		
			spring-webmvc
			org.springframework
		
	



	org.springframework.social
	spring-social-github
	${spring-social-github.version}



	org.springframework.social
	spring-social-twitter
	${spring-social-twitter.version}


As you can see, we take the core Spring Social library, and for my project I also used Twitter and GitHub integration (I also had LinkedIn early on, but removed that as the LinkedIn terms of use on the API are pretty limiting). I added the exclusions to ensure that the latest Spring libraries were being used, as these were declared elsewhere in the Pom.



Storing User Connection Details

Spring Social supports both OAuth1 and OAuth2, and provides the underlying mechanisms to perform the "OAuth Dance" which enables your application (once approived by a user) to capture the access token required to enable your application to access the third party API. Usually your application would capture the user details including access token and store them (encrypted of course!) so the user does not need to approve the application every time they use it. There are examples in the Spring Social showcase on GitHub of doing this with a standard JDBC connection implementation, but as I was capturing my user details in Hibernate I decided to implement a Hibernate version.

To implement your own storage mechanism you need two classes, a ConnectionRepository and a UsersConnectionRepository and must implement the same interfaces:

public class HibernateUsersConnectionRepository implements UsersConnectionRepository { 

public class HibernateConnectionRepository implements ConnectionRepository {


You can see my hibernate implementations here. Obviously I also needed a Hibernate entity to represent this connection details, but that was a straight forward entity as follows:

@Entity
@Table(name = "CV_CONNECTION")
public class SocialConnection {

       @Id
       private Long id;
       private String providerId;
       private String providerUserId;
       private String displayName;
       private String profileUrl;
       private String imageUrl;
       private String accessToken;
       private String secret;
       private String refreshToken;
       private Long expireTime;
       private Integer rank;


Configuring the Beans

The next step is to define the  Spring Social beans to use (such as Twitter, GitHub etc) so they can be used throughout the application.

For this I used a Configuration class rather than adding the config directly to my application context xml (this just involves creating a POJO and annotating it with the @Configuration annotation - this then allows you to create code equivalents of xml config that would normally exist in app context xml - we will see more in the details below).

@Configuration
public class SocialConfiguration {


The beans we need to define are the ConnectionRepository, UsersConnectionRepository, ConnectionFactoryLocator and then any Social interface that we are using, in our case Twitter and GitHub.

ConnectionFactoryLocator:


@Bean
public ConnectionFactoryLocator connectionFactoryLocator() {
	  ConnectionFactoryRegistry registry = new ConnectionFactoryRegistry();
	  registry.addConnectionFactory(new GitHubConnectionFactory(gitHubKey, gitHubSecret));
	  registry.addConnectionFactory(new TwitterConnectionFactory(twitterKey, twitterSecret));
	  return registry;
}

The ConnectionFactoryLocator is simply used to initialise the UsersConnectionRepository, for every SpringSocial third party you want to use, you need to add a ConnectionFactory instance as per above - all Spring Social implementations will provide a ConnectionFactory implementation.

The @Bean annotation is like defining a <bean> in the application context xml.

UsersConnectionRepository:


@Bean
@Scope(value = "singleton", proxyMode = ScopedProxyMode.INTERFACES)
public UsersConnectionRepository usersConnectionRepository() {
	  HibernateUsersConnectionRepository repository = new HibernateUsersConnectionRepository(connectionFactoryLocator(), Encryptors.noOpText());
	  return repository;
}

This is to configure the UsersConnectionRepository - as you can see, in this case we are telling Spring to instantiate a HibernateUsersConnectionRepository.


ConnectionRepository:

This one is straight forward as well - again, using the Hibernate implementation of the interface and

@Bean
@Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
public ConnectionRepository connectionRepository() {
	  Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
	  if (authentication == null) {
			 throw new IllegalStateException("Unable to get a ConnectionRepository: no user signed in");
	  }
	  ApplicationUser user = (ApplicationUser) authentication.getPrincipal();
	  return usersConnectionRepository().createConnectionRepository(String.valueOf(user.getAccountId()));
}

You will note that this method also includes an @Scope annotation the value is set to "request" - this is because for every individual user that accesses the applciation, we want them to have access to their own connection (so the application connects to their twitter/github accounts etc, so this bean is scoped to each individual user request (but for user session life). 

ThirdParty Interfaces:

Finally we need a config method for every third party interface that we want to use - they all take a common form as follows:

@Bean
@Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
public Twitter twitter() {
	if (connectionRepository().findPrimaryConnection(Twitter.class) != null) {
		return connectionRepository().findPrimaryConnection(Twitter.class).getApi();
	}
	return null;
}

You will note once again these are scoped to  a user's request and simply gets the connection from the ConnectionRepository for the given interface.



Using the Interfaces

Every implementation exposes the third party API, so each will have a specific API available to it to allow you to perform common tasks (depending on the maturity of the implementation, it may only offer a limited subset of the overall API) .

Below is an example of using the Twitter interface in the Spring-Social-Twitter library to post an update:

@Autowired
private Twitter twitter;
public void postTweet(String content) {
	  twitter.timelineOperations().updateStatus(content);
}

As you can see, once the Twitter interface has been configured and injected, it becomes very simple to utilise the API.



On the whole, it is a relatively simple set of libraries to use and offers (an ever growing) set of integrations with third party sites so worth having a look at.


As always, the entire code base is on my GitHub account (if this link fails, then check the GitHub link on the right) and for the time being the application is being hosted on the CloudFoundry platform (although this is still in development, so it may come up and down, and data may be cleared out intermittently - it is not intended as a live production site and you should not put any data in there that you want to keep!) - The application is a dynamic online resume/CV application, that allows users to create a CV as well as pull in data from their GitHub accounts to show off actual examples of code and skills etc.

Android & Twitter - OAuth Authentication Tutorial

I’ve seen a lot of questions about connecting Android apps with Twitter using OAuth and thought I would write up a walkthrough of how it can be done. The example will be done using Twitter4J which is a great library for connecting Java apps with Twitter and provides a simple interface to connect to the public Twitter Web Services.

First thing you will need to do is to register your new app (even though you haven’t made it yet!). Do this by heading to https://dev.twitter.com/apps/new (you will need an existing Twitter account sign up). You should complete the form with the relevant details for your app:


You should fill in your details for the application such as name, description, URL – but the only key things to remember to do here are as follows:

1) Make sure you select “Browser” as your application type – even though we are creating an app, we will authenticate using the browser and a callback URL.

2) Tick read & write permissions

Once you have registered you will be provided with a “Consumer Key” and a “Consumer Secret” – make note of these for later – we will need to include these in the app.


Now let’s get started with the app! I will assume for this tutorial that you are familiar with the basics of Android apps so won’t go into details about how to setup the UI and what an Activity or Application is.
The first thing we will do is create an Activity that will prompt the user to login to Twitter and authorize the app to connect to Twitter to make updates. Let’s start with the onCreate method:


@Override
public void onCreate(Bundle savedInstanceState) {
 System.setProperty("http.keepAlive", "false");
 super.onCreate(savedInstanceState);
 setContentView(R.layout.main_oauth);
 
 //check for saved log in details..
 checkForSavedLogin();

 //set consumer and provider on teh Application service
 getConsumerProvider();
 
 //Define login button and listener
 buttonLogin = (Button)findViewById(R.id.ButtonLogin);
 buttonLogin.setOnClickListener(new OnClickListener() {  
  public void onClick(View v) {
   askOAuth();
  }
 });
}

The first line we set the http keepAlive property – this is important so the app manages the connection correctly without reseting. The next important thing is our call to the checkForSavedLogin() method – this is a method that checks whether the user has previously authorised the app to access twitter, in which case we can just proceed as usual to the default twitter timeline activity (we will have a look at that method next). Otherwise we just initialise the Consumer/Provider and store them in our Application class so they are available to all Activities throughout the application. Then finally we inflate the button on the page and set a listener to call the askOAuth() method on click.


Now let’s jump in to the checkForSavedLogin() to see whats going on there:

private void checkForSavedLogin() {
 // Get Access Token and persist it
 AccessToken a = getAccessToken();
 if (a==null) return; //if there are no credentials stored then return to usual activity

 // initialize Twitter4J
 twitter = new TwitterFactory().getInstance();
 twitter.setOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
 twitter.setOAuthAccessToken(a);
 ((TwitterApplication)getApplication()).setTwitter(twitter);
 
 startFirstActivity();
 finish();
}



This method calls a method getAccessToken() – all this does is check in the user SharedPreferences to see whether we have stored the users AccessToken previously – if there is no token found it just returns, so the user is left on the authentication activity waiting input.

However, if a token is found, then we initialise Twitter4J Twitter object and store that in our Application class (again, so we can use it throughout the application).
Finally we call startFirstActivity(), which simply calls the default Twitter timeline activity we have and finishes the authentication activity as it is not needed.

So that is all good, if the user has previously authenticated then no probs – however, if no saved token is found the user still needs to authenticate so we need to handle the user action (remember we are calling the askOAuth() method from within our button listener).



Let’s have a look at that method – this is where the authentication is all done:

private void askOAuth() {
 try {
  consumer = new CommonsHttpOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
  provider = new DefaultOAuthProvider("http://twitter.com/oauth/request_token", "http://twitter.com/oauth/access_token", "http://twitter.com/oauth/authorize");
  String authUrl = provider.retrieveRequestToken(consumer, CALLBACK_URL);
  Toast.makeText(this, "Please authorize this app!", Toast.LENGTH_LONG).show();
  setConsumerProvider();
  startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(authUrl)));
 } catch (Exception e) {
  Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
 }
}

First thing we do here is to initialise the Consumer and Provider objects – we are using the Commons OAuth Consumer/Provider (so you need to make sure you copy the following JARs in to your /assets/ directory and then add them to your build path: “signpost-commonshttp” and “signpost-core”).

You will see that the consumer is initialised using to static Strings CONSUMER_KEY and CONSUMER_SECRET – these need to be set to be the key and secret Twitter provided when you registered the app – you should make sure you keep these secret and not reveal them to people.

The provider is then just initialised using the relevant URLs that Twitter provides to authenticate againse.

Next, we call the retrieveRequestToken() method on the provider object, this takes two arguments: the consumer, and the CALLBACK_URL (another static string) we will come back to what this is later.

We then call startActivity with a new Intent using the authenticate URL – this is what will forward the user to the Twitter authentication service for them to securely login and authorize the app to make updates for them.



So now, we have a simple authentication activity, that if the user has never logged on before will forward them on to the Twitter OAuth service – next we need to handle the response from Twitter and if a successful response received, then store the Access Token for future use. This is all done in the onResume() method:

@Override
protected void onResume() {
 super.onResume();
 if (this.getIntent()!=null && this.getIntent().getData()!=null){
  Uri uri = this.getIntent().getData();
  if (uri != null && uri.toString().startsWith(CALLBACK_URL)) {
   String verifier = uri.getQueryParameter(oauth.signpost.OAuth.OAUTH_VERIFIER);
   try {
    // this will populate token and token_secret in consumer
    provider.retrieveAccessToken(consumer, verifier);

    // Get Access Token and persist it
    AccessToken a = new AccessToken(consumer.getToken(), consumer.getTokenSecret());
    storeAccessToken(a);

    // initialize Twitter4J
    twitter = new TwitterFactory().getInstance();
    twitter.setOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
    twitter.setOAuthAccessToken(a);
    ((TwitterApplication)getApplication()).setTwitter(twitter);
    //Log.e("Login", "Twitter Initialised");
    
    startFirstActivity();

   } catch (Exception e) {
    //Log.e(APP, e.getMessage());
    e.printStackTrace();
    Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
   }
  }
 }
}


First thing, the method checks that the intent that has called the onResume is the expected intent, and then pulls out the verifying string from the callback URI – it then uses this string to retrieve the access token. Once we have called the retrieveAccessToken() method, we can initialise an AccessToken and store it. Next we initialise the Twitter4J object with the CONSUMER_KEY and SECRET again and then set the Access Token – once this has all been setup we just start the first activity as normal.
Once the user has authenticated they will be forwarded to the their friends timeline!

Now, the only thing remaining, is that we need to tell the app that once Twitter has finished authenticating that it needs to return to our Authentication Activity to call the above onResume method, or else it won’t be able to continue. To do this, Twitter will attempt to use the CALLBACK_URL we saw earlier. If you remember, when we requested the token from Twitter we passed in the CALLBACK_URL. I have previously defined this as follows:

private String CALLBACK_URL =           "callback://tweeter";

The name of the callback is up to you (I have named it “tweeter”), what is important is that this matches the callback you define in your Manifest XML. For the welcome activity (our Authentication activity) it needs to be defined as follows:


 
  
  
 
 
  
  
  
  
 



As you can see, we have defined an intent-filter with a scheme called “callback” and we provide the host name as “tweeter” – matching that used to call the Twitter service.

And thats it! The user has been authenticated and returned to our application correctly, so it can now continue to read timelines, post tweets, retweet, etc.



The complete source code of the application is available here (NOW ON GITHUB!), please note that I have removed my own CONSUMER_KEY/SECRET details, so to make this work you will need to register your app and populate with your own details to see it work in your emulator/device.

Android Twitter Reader

Following on from the RSS Reader, some time last year I was investigating using Twitter in some of my apps, so I put together this simple Twitter reader (it only reads tweets from a given user - it doesnt allow posting etc)




For the most it is the same as the RSS Reader in terms of laying out the Android Lists and the layout.xml, so I won't go over that, I will just go through the Twitter integration.

The first step is to retrieve all the tweets, for this I am using the very useful Twitter4J Java library that simply wraps the Twitter API with a Java API

Twitter twitter = new TwitterFactory().getInstance();
  List statuses = new ArrayList();
     try {
   statuses = twitter.getUserTimeline(screenName);
  } catch (TwitterException e) {
   Log.e("Twitter", "Error logging in to Twitter");
   Log.e("Twitter", e.getMessage());
  }


Once you have the list of latest tweets, I convert them in to JSON so my listAdapter can process them more easily:

ArrayList JOBS = new ArrayList();
  try {
   if (statuses.size()>0){
    for (Status s : statuses){
     String avatar = "http://" + s.getUser().getProfileImageURL().getHost() + s.getUser().getProfileImageURL().getPath();
     JSONObject object = new JSONObject();
     object.put("tweet", s.getText());
     String timePosted = Utility.getDateDifference(s.getCreatedAt());
     object.put("tweetDate", timePosted);
     object.put("author", s.getUser().getName());
     object.put("avatar", avatar);
     object.put("userObj", s.getUser());
     object.put("tweetId", s.getId());
     
     JOBS.add(object); 
    }
   }else{
    JSONObject object = new JSONObject();
    object.put("tweet", "You have not logged in yet! Please log on to view latest tweets");
    object.put("author", "");
    JOBS.add(object);
   }

  } catch (JSONException e1) {
   Log.e("JSON", "There was an error creating the JSONObject", e1);
  }


And thats pretty much that! the listAdapter just pulls the information out of the JSON objects as per above and displays as necessary. The only other thing I will show is a little Date util class to make the date posted a little more fun:

public static String getDateDifference(Date thenDate){
        Calendar now = Calendar.getInstance();
        Calendar then = Calendar.getInstance();
        now.setTime(new Date());
        then.setTime(thenDate);

        
        // Get the represented date in milliseconds
        long nowMs = now.getTimeInMillis();
        long thenMs = then.getTimeInMillis();
        
        // Calculate difference in milliseconds
        long diff = nowMs - thenMs;
        
        // Calculate difference in seconds
        long diffMinutes = diff / (60 * 1000);
        long diffHours = diff / (60 * 60 * 1000);
        long diffDays = diff / (24 * 60 * 60 * 1000);

  if (diffMinutes<60){
   if (diffMinutes==1)
    return diffMinutes + " minute ago";
   else
    return diffMinutes + " minutes ago";
  } else if (diffHours<24){
   if (diffHours==1)
    return diffHours + " hour ago";
   else
    return diffHours + " hours ago";
  }else if (diffDays<30){
   if (diffDays==1)
    return diffDays + " day ago";
   else
    return diffDays + " days ago";
  }else {
   return "a long time ago..";
  }
 }

I like this

From the twitter-sphere this week:


In theory there's not much difference between theory and practice. But in practice there is a huge difference


Tweeted by @petrvanblokland

Two new Android Apps..



I have finally published my first two mobile apps to the Android market.


You cannot actually search the market officialy online, as Google only permit it via an Android mobile device, but you can find them here


Its been a long time coming, but there is another one on its way shortly.