Making Buffer for Android more proactive with Reactive-Pusher

Feb 8, 2018 5 min readOverflow
Photo of Joe Birch
Joe Birch

Senior Engineer @ Buffer

When your application content reflects the state of data stored on a server, making sure you’re always displaying the most up-to-date state ensures a better experience for the user. Now, this can be achieved by the user themselves but it involves the manual refreshing of content. For example, the user may be required to pull-to-refresh in order to show the latest content in some form of content feed. In any app, this is probably the simpler method to implement, but it’s not the best experience for our users.

And to build on this even further — in the case of Buffer, another team member within your account may have paused your queue, added a new update or rescheduled a post to go out on a different day — when this happens you may not be aware of it and without repeatedly manually refreshing, you would never know. That’s where Pusher comes in to help us out! Now in Buffer for Android (well, when it’s out of beta!), whenever content changes on the server-side the Android app will refresh the content shown to ensure that you’re always seeing the freshest state of content. The flow for this looks something like this:

As shown above, there are four different refresh events which are now triggered in the app:

  • We refresh the queue of updates whenever any events occur related to updates. For example, this could be a new update being added or an existing on edited edited by any other device.
  • If a Draft contribution post is updated or approved on another device, we refresh the queue of Draft posts.
  • If an update is collected, then this means new analytics are available for us to display which means we need to refresh the analytics queue of content.
  • If the profile queue is paused or un-paused on another device then we reflect this state in the app by toggling the visibility of the pause/un-pause queue button.

The team over at Pusher made the process of implementing this in our app quite delightful by providing us with a helpful Java Client Library – pusher/pusher-websocket-java

Now, this is great work and super useful by itself. But the way in which we wanted to use it in our app, and the places where it would be used, meant that it wasn’t the exact representation which we felt was best for our needs. Because of that, we went ahead to create the Reactive-Pusher library – bufferapp/Reactive-Pusher

But why exactly did we decide to wrap the library in the first place?

  • To begin with, both of the apps we work on within the Android team at Buffer heavily use a reactive approach within their architectures. To keep this architecture in place it’s ideal if everything follows the same approaches to ensure a consistent approach.
  • This in turn makes it easier for us to chain events in our app as part of the same observable stream. So now we can subscribe to events from Pusher we can chain on specific actions to be carried out once those events have taken place.
  • Everything is part of the same stream, the reactive implementation allows us to continue this practice making the application less error-prone and easier to debug.
  • Following on from consistency, it’s easier to understand and maintain these parts off of our project if they’re built with the same approach as other parts of the project. If someone new was to join the team or an existing developer was to jump into that code, there wouldn’t be any increased friction from the need to learn new things.
  • When we subscribe to pusher events, the startup and tear down of these subscriptions now becomes part of the same process for the other reactive components within the corresponding screens. This reduces the need to keep a track of different instance references as the same CompositeDisposable is responsible for all subscriptions in that screen.

So, what can you do with RxPusher?

RxPusher supports most of the functionality found within the Pusher Java Client library, here’s a quick look at what you can do with it and how:

Connecting to Pusher

You can use the observeConnection() method to observe the connection to the Pusher service, this won’t terminate so you will continue to receive connection updates regardless of how the Pusher connection status changes:

reactivePusher.observeConnection().subscribe({
    when (it) {
        ConnectionStatus.CONNECTED -> { }
        ConnectionStatus.CONNECTING -> { }
        ConnectionStatus.DISCONNECTING -> { }
        ConnectionStatus.DISCONNECTED -> { }
        ConnectionStatus.RECONNECTING -> { }
        ConnectionStatus.UNKNOWN -> { }
    }
}))

There is also an observeConnection(varargs filter: String) method available that allows you to pass a collection of ConnectionEvents which you wish to exclude the callback being triggered.

Getting channels

You can retrieve channels using either the getChannel(), getPrivateChannel()or getPresenceChannel() methods.
Calling getChannels() will return you an instance of a Channel, getPrivateChannel() a PrivateChannel instance and getPresenceChannel() a PresenceChannel instance. When calling this you just need to pass in the required channel name.

reactivePusher.getChannel("some channel name")
    .subscribe({ // do something with the channel })

Checking channel subscription state

You can also use the isChannelSubscribed(), isPrivateChannelSubscribed()and isPresenceChannelSubscribed()methods to check the subscription state of a channel.
When calling this method you need to pass in the desired channel name which you wish to check. Upon a successful request you will be returned a boolean value if the channel is subscribed to.

reactivePusher.isChannelSubscribed("some channel name")
    .subscribe({
        // do something with the channel subscription result
    })

Subscribing to channels

Using the subscribeToChannel(), subscribeToPrivateChannel() or bindToPrivateChannelEvent() methods allow you to subscribe to events from a given channel.
When subscribing to a channel you need to pass the channel name along with a collection of events that you wish to subscribe to, when binding you only need to pass a single event that you wish to bind to. When an event is received you will get an instance of a ChannelEvent from the callback.

reactivePusher.subscribeToChannel("some channel name", events...)
    .subscribe({ // do something with the channel event })

Triggering events

You can also trigger events from this library by using the triggerEvent() method. This just requires you to pass in the channel name, the event name and the data you wish to pass with that event.

reactivePusher.triggerEvent("some channel name", "some event name", "some data")
    .subscribe({ // do something with the trigger completion })

Conclusion

Using Pusher in our Android app has allowed us to introduce a more pro-active experience for our users, ensuring their always shown fresh content regardless of where the data was changed or who by. Creating Reactive Pusher has also allowed us to implement it in a way that fits in well with our architecture. Both of these together means not only our users our happier, but also our developers!
Are you using Pusher in your apps, thinking of doing so or even have questions about Reactive Pusher? Feel free to drop us a response or get in touch over on Twitter.

Brought to you by

Try Buffer for free

140,000+ small businesses like yours use Buffer to build their brand on social media every month

Get started now

Related Articles

OverflowJul 12, 2024
How We're Preventing Breaking Changes in GraphQL APIs at Buffer — and Why It's Essential for Our Customers

As part of our commitment to transparency and building in public, Buffer engineer Joe Birch shares how we’re doing this for our own GraphQL API via the use of GitHub Actions.

OverflowDec 13, 2022
Highlighting Text Input with Jetpack Compose

We recently launched a new feature at Buffer, called Ideas. With Ideas, you can store all your best ideas, tweak them until they’re ready, and drop them straight into your Buffer queue. Now that Ideas has launched in our web and mobile apps, we have some time to share some learnings from the development of this feature. In this blog post, we’ll dive into how we added support for URL highlighting to the Ideas Composer on Android, using Jetpack Compose. We started adopting Jetpack Compose into ou

OverflowApr 18, 2022
Secure Access To Opensearch on AWS

With the surprising swap of Elasticsearch with Opensearch on AWS. Learn how the team at Buffer achieved secure access without AWS credentials.

140,000+ people like you use Buffer to build their brand on social media every month