top | android | coffee | dealing_with_companies | dev_blog | experiments | food | fun | io15 | politics | products | random | security | startups | tech_events | thoughts | wearables |

09 Nov 2015, 23:05

Make your phone talk (Android Intents Part 3)

This is the third post in a series about sharing information between apps. (Part 1 is here, and part 2 is here.) In this post, we’re going to create a public API that allows other apps to use our app to speak something out loud.

Series Table of Contents

Follow the series on the Table of Contents page.

Text to Speech Example

Back to looking at code! Yay!

We want to provide to other apps the ability to fire an intent at us, with some text, that will cause us to speak out the text passed in.

This example uses the text-to-speech API provided by Android. Since we’re discussing intents, and public app APIs, I’m actually going to skip the implementation of this. It doesn’t have much to do with the rest of the discussion, and actually, the ability to skip these sorts of implementation details is exactly what we’re after. That said, all of the code is on GitHub, if you’re interested. There isn’t a whole lot needed to do this.

Here’s what we will look at, providing a public API, and consuming that API.

Provider

On the provider side, it’s very similar to what we have in our BroadcastReceiver example from Part 1. We’ll start with the snip from the AndroidManifest.xml:

<receiver android:name=".say.TtsReceiver" >
    <intent-filter>
        <action android:name="io.ejf.intentexamples.say" >
        </action>
    </intent-filter>
</receiver>

This is our BroadcastReceiver.onReceive implementation:

@Override
public void onReceive(Context context, Intent intent) {
    Intent sIntent = new Intent(context, TtsService.class);

    if (!intent.hasExtra("SAY_TEXT"))
        return;

    sIntent.putExtra("SAY_TEXT", intent.getStringExtra("SAY_TEXT"));
    context.startService(sIntent);
}

Notice that we’re starting a service, as opposed to trying to run the text-to-speech code in the BroadcastReceiver. The reason for that is that there are some asynchronous components of Android’s text-to-speech implementation, and the BroadcastReceiver will die as soon as onReceive is finished executing.

In our Service, we have something like the following:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (!intent.hasExtra("SAY_TEXT"))
        return;
    if (null == textToSpeech)
        return;

    String sayText = intent.getStringExtra("SAY_TEXT");
    textToSpeech.speak(sayText, TextToSpeech.QUEUE_ADD, null, null);

    return super.onStartCommand(intent, flags, startId);
}

The above is a slightly modified version of what’s in the project. I skipped how the textToSpeech object gets instantiated.

Consumer

All we need to do to consume this API is fire off an intent:

Intent intent = new Intent();
intent.setAction("io.ejf.intentexamples.say");
intent.putExtra("SAY_TEXT", "Some string to speak");
sendBroadcast(intent);

The above works from apps other than our demo. This is a public API on the phone. In the example code on GitHub, I actually added the above to a separate app, called “SayLauncher”:

SayLauncher

Check out this tag on GitHub!

(Quick side-note here, if you want to check out the repository at this step, first check out the repo, then run the following command: git checkout -b step5 step5. That will get you a branch at the step1 tag.)

Sharing from any app

What we’re doing is a special case of the public APIs discussion, because there’s already a way of doing this that many apps know about, and use. That is generic text sharing. One note here is that text is generally shared to an Activity, but that’s not a big deal for us, we can simply implement a dummy Activity, forward the Intent, then kill the Activity. Let’s take a look.

First, implement the Activity in the AndroidManifest:

<activity android:name=".say.TtsDummyActivity" >
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
    </intent-filter>
</activity>

Now, in the TtsDummyActivity:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Intent intent = getIntent();
    String action = intent.getAction();
    String type = intent.getType();

    if (Intent.ACTION_SEND.equals(action) &&  "text/plain".equals(type)) {
        Intent sIntent = new Intent(this, TtsService.class);
        sIntent.putExtra(Constants.SAY_TEXT, intent.getStringExtra(Intent.EXTRA_TEXT));
        startService(sIntent);
    } else {
        Log.w(TAG, "received unknown intent");
    }

    finish();
}

share via screen

Whenever possible, it’s a good idea to use the popular way of providing APIs to other apps. That way, you don’t need specific implementations, and you can rely on the fact that lots of apps are going to be using these mechanisms. Sometimes, it might make sense to offer two ways of doing something, like we did in this example. That way, if there is an app that wants to integrate directly, because they want exactly the behavior that you provide, then they can do that.

Check out this tag on GitHub! ( git checkout -b step6 step6 )

Conclusion

We got a lot done here today. First, we finally got around to discussing why we’re bothering with this whole exercise. We discussed a real-world example of how this sort of thing is helpful to all parties, users, API providers, and API consumers. Then, we went through a concrete example and demonstrated a fun way to both produce and consume a public API on the phone.

Next time, we’ll start thinking of some other applications for APIs on the phone, and we’ll pick out another example to work through.

09 Nov 2015, 22:59

Why do we want public APIs? (Android Intents Part 2)

This is the second post in a series about sharing information between apps. (Part 1 is here.) In this post, we’re going to discuss why it might be nice to have a public API exposed from a third party app. I’ll be providing videos that cover the text contents of these posts (plus insightful things), so if you want to watch instead of read, check out the video below:

If you watched the video, feel free to skip to Part 3, where we’ll look at some code. This post is simply a text version of the video.

Series Table of Contents

Follow the series on the Table of Contents page.

Why do we want a public API on the phone?

There are three perspectives here, the user is one, and then the producing developer, and consuming developer are the other two. This isn’t as complicated as it sounds.

I’m going to put this in terms of a couple of concrete apps, so that we have some apps that we can look at, and think about, as opposed to talking so much in the abstract. We’ll talk about MyFitnessPal as the producing developer, offering the API. Strava and Withings will be the consuming developers, they consume MyFitnessPal’s APIs.

This discussion may seem kind of long, but it is the central idea of this entire series. I promise we’ll get back to code soon. Again, if you watch the video, you can skip straight to Part 3, because all of the long text part is covered in the video.

I’d also like to mention up front that these apps already do integrate with each other, but they do it via the web, not on the phone. I’ll discuss the difference in the ‘user’ section. There’s also Google Fit, which intends to take care of this particular issue, and IIRC provides some useful integrations on the device side. In short, this particular example is almost completely solved already, but it’s an easy one to think about, so we’re going to keep it.

Producing Developer

MyFitnessPal sketch

MyFitnessPal, lot’s of typing!

Imagine that you’re MyFitnessPal, and an app that does calorie counting. MyFitnessPal provides users a way to enter their food and exercise and your app tells them how many calories they’ve consumed and how many they’ve burned. Now, you care about gathering fitness data from users, but your main method of getting that data is asking users to enter it manually. Then, along comes Strava, they do automatic tracking for bicycle riding and running. If your user is using both Strava and MyFitnessPal, you could open up an API for Strava (and any other activity tracking app) to send data to MyFitnessPal, so that users don’t have to manually input something that was already captured automatically for them.

Withings sketch

Withings, works just like an ordinary scale, but it syncs your weight to its service

It’s the same deal with Withings, they provide some passive tracking hardware, like a digital scale that sends your current weight to their app, an activity tracking watch, as well as some other products. You, as MyFitnessPal, could open another API that would allow Withings to sync up the user’s weight with you. Withings could use the same APIs for exercise tracking that you opened up for Strava.

The apparent downside is that users will no longer need to enter your app to manually enter this data. However, by offering an API for other apps to consume, you’re actually making both your app and the other app more powerful. Now the user needs to do less work, and they’re going to appreciate that they get stuff for free (free data entry, which is a pain to do on your phone). When you start offering APIs that other apps can consume, users are going to like you more because make the their life easier.

Consuming Developer

Strava sketch

Strava doesn’t require much typing, it records your session.

Now, imagine you’re Strava, you do a great job tracking users’ runs and bike rides, but your users are asking for food tracking as well. That’s a difficult problem, and not really your core competency. It’s something that you really don’t want to do yourself. Luckily, you know that MyFitnessPal does food tracking really well, and they also do exercise tracking. What’s more, they offer an API that allows apps like Strava to send them activity data. All you need to do is implement an API, and now you can tell users to install MyFitnessPal when they ask about food tracking. The best part is that it’s automatic and in the background, users don’t need to think about it, and you’ve done almost no work. It’s a win-win!

User

Imagine that you’re a user that wants to count calories, track your weight, and goes running. MyFitnessPal, Withings, and Strava all work together to allow you to do most of this tacking passively, cutting down the amount of manual data entry you have to do, and saving you time. If there’s a run tracking app that you like, but doesn’t integrate with MyFitnessPal, is that extra friction worth it, or are you going to switch over to Strava?

As I mentioned before, these apps already do integrate with one another, and it’s not exclusive to the listed apps, most of the worthwhile fitness apps I’ve come across integrate with each other. The one big downside is that they integrate in the backend, not on the phone. What this means is that users need to sign into different services multiple times on their phones, or set up those integrations on their computers. This is friction. Why not just do it seamlessly on the phone? Is there a reason to even ask the user to log in, when they’re already logged in on the phone in the other app?

Instead of integrating on the backend, it seems possible to integrate on the frontend. The apps just fire intents at each other, and allow the providing app to do the auth in their app. This could be as simple as popping a dialog and asking the user if it’s OK if the other app send it data. What’s more, it means that you don’t need an internet connection for the apps to sync with each other (either via intents, or maybe a combination of intents and content providers). Currently, these services sync up on their own schedule, and it can cause users to manually enter information that will be automatically synced later. Friction.

Integration sketch

The above is a sketch of Withings and Strava talking to MyFitnessPal, if you couldn’t tell. =)

Conclusion

In this post I explained why we’re bothering with this whole exercise. We discussed a real-world example of how this sort of thing is helpful to all parties, users, API providers, and API consumers. Hopefully this has given you some perspective on what this series is all about, and where we might want to go from here. Incidentally, if you have ideas for this series, please feel free to reach out.

Next time, we’ll look at an example that demonstrates a fun way to both produce and consume a public API on the phone.

07 Nov 2015, 09:37

How to launch an Activity (Android Intents Part 1)

This is the first post in a series about sharing information between apps. It will start with the basics, and move on to discuss how we might leverage this to do some interesting things. Additionally, I’ll be providing videos that cover the text contents of these posts (plus insightful things), so if you want to watch instead of read, check out the video below:

Apologies for the quality of the video. I’m just starting out, and hoping that I’ll be able to get better at this. However, I don’t want to let my lack of skill and inexperience prevent me from moving forward.

Series Table of Contents

Follow the series on the Table of Contents page.

Sharing in Android

In Android, information is shared between apps in few different ways, there’s local files stored in the shared storage area of the device, then there are Content Providers, and Intents. Using local files as information sharing seems pretty hacky, and is wide open for attack, so I’m not going to discuss that. Content Providers are interesting, but this series is going to be discussing Intents. If this goes well, maybe I’ll circle back and cover Content Providers.

I’m going to note the official documentation on sharing right here:

Great, now that that’s out of the way, we can get started.

Prerequisites

You’ll need to have your Android development environment all set up. Here’s a post from Google on setting up your environment. Or, in video form below:

Launch an Activity

Let’s say that you want to open one Activity from another Activity, you’d use an intent like the following:

startActivity(new Intent(this, ActivityTwo.class));

In this example, the ‘information’ that you’re sharing is simply that you’d like ActivityTwo to appear on top of ActivityOne. If you’d like to see a fully working example of this, check this tag on GitHub.

(Quick side-note here, if you want to check out the repository at this step, first check out the repo, then run the following command: git checkout -b step1 step1. That will get you a branch at the step1 tag.)

That’s really it for the first example. You can run it on your device, and should see something like the following:

screen 1 screen 2

In the above example, the ‘LAUNCH INTENT’ button runs the startActivity code described above to launch the second activity.

Launch an Activity with Extras

Next, let’s extend the first example, and add a button to ActivityTwo that points back at ActivityOne. However, instead of just launching ActivityOne, we’ll send back some data along with it, that ActivityOne will display. Here’s the tag on GitHub for this state. ( git checkout -b step2 step2 )

This time, we’ll set an extra on the intent:

Intent intent = new Intent(this, ActivityOne.class);
intent.putExtra("EXTRA_CONTENT", "saw ActivityTwo");
startActivity(intent);

ActivityOne will need to check for the intent extra and then do something with it. Here’s how it looks now:

screen 1 screen 2b screen 1b

Start a Service

First, let’s add a button to the Activity:

screen 1

Next, in the OnClickListener for the button, we’ll add some code to launch the intent:

startService(new Intent(this, MainService.class));

Simple, right?

Now, let’s say that we want to kill the service. What should we do? Well, we can actually kill the service using another intent with startService. Here’s what we’ll add to the Service:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (intent.hasExtra("KILL"))
        stopSelf();
    return super.onStartCommand(intent, flags, startId);
}

Then we just put an Extra in the intent in the Activity:

Intent intent = new Intent(this, MainService.class);
intent.putExtra("KILL","");
startService(intent);

If you run that, you’ll see the service getting started then stopped. I added logs to the onStartCommand and onDestroy methods of the service, and here’s what I saw when I clicked the button:

11-04 07:58:23.257 27985-27985/io.ejf.intentexamples I/MainService: starting service
11-04 07:58:23.266 27985-27985/io.ejf.intentexamples I/MainService: stopping service

Check out the code at this point. (git checkout -b step3 step3)

Send a Broadcast

Now, let’s take a look at how to send an intent to a BroadcastReceiver. It’s fairly straightforward, but one little note is that we should add an entry to the AndroidManifest.xml with our intent filter:

<receiver android:name=".MainReceiver" >
    <intent-filter>
        <action android:name="io.ejf.intentexamples" >
        </action>
    </intent-filter>
</receiver>

We need entries for our Services and Activities as well, but when we add an intent-filter it lets the system know what this receiver can handle. (This is our first public API!) Now, we can send a broadcast:

Intent intent = new Intent();
intent.setAction("io.ejf.intentexamples");
sendBroadcast(intent);

I’ve added a log to my receiver, and it seems to work:

11-04 08:28:03.303 25479-25479/io.ejf.intentexamples I/MainReceiver: received broadcast

Check out the code at this point. ( git checkout -b step4 step4 )

Conclusion

That’s it for right now, but you saw a couple of basic things here. We’re now launching an Activity as well as passing some data along. We also now have our first public API! What’s more, our API runs something in the background, and doesn’t bring up another screen. This is an important point that we’ll get into later on. Next, we’ll extend that to start offering something useful.

06 Nov 2015, 20:14

Android Intents Series Table of Contents

This is the Table of Contents for a series of blog posts and videos about sharing information between apps. It will start with the basics, and move on to discuss how we might leverage this to do some interesting things.

The following is the table of contents for the series:

The code for the series is here.

Here’s the YouTube playlist for the videos in the series:

26 Nov 2013, 16:40

An Android app to slow your test device down.

An Android app to slow your test device down.

I’ve got a bunch of Android devices at my desk, most of which are several years old. I need them for testing the apps that I work on, both to make sure that they work consistently across OEMs, but also to see how the app performs on older devices. The problem that I kept running into was that the old devices would feel faster than my newer phone, simply because there wasn’t as much running on them.

The Solution

Add some load to those test devices! I decided to create this app to make the phone do some sort of constant and predictable work in the background. It can do three things, load up the CPU, eat up about 130-140MB of memory (limited by the system here), and make network requests.

Screenshot

I also tried to architect and design the thing in a sane way, hopefully it’s not too difficult to understand.

API

In addition to launching and configuring manually, there is an API that allows you to broadcast an intent, with all the configuration options that you get in the UI! Here’s how you would launch it:

Intent launchLoadTest = new Intent();
launchLoadTest.setAction("com.feigdev.loadtester.api");
// Time in miliseconds
long keepAlive = 20 * 1000;
launchLoadTest.putExtra("KEEP_ALIVE", keepAlive);
launchLoadTest.putExtra("CPU_ENABLED", true);
launchLoadTest.putExtra("RAM_ENABLED", true);
launchLoadTest.putExtra("NET_ENABLED", true);
// Valid modes are "LOW", "MEDIUM" and "HIGH"
launchLoadTest.putExtra("MODE", LOW");
sendBroadcast(launchLoadTest);

And, when you’re done, you can kill it too:

Intent launchLoadTest = new Intent();
launchLoadTest.setAction("com.feigdev.loadtester.api");
launchLoadTest.putExtra("KILL_NOW", "KILL_NOW");
sendBroadcast(launchLoadTest);

Here is a project that launches and kills the LoadTester.

Notes

The configurations for load might need to be tweaked. It’s all just guess work at this point, and while I was able to put enough load on my Nexus 5 to freeze it up completely, I haven’t figured out what the best parameters are for a consistent load on each setting. Feel free to make pull requests with different values.

As far as walking through the code, I might break that out into several posts that look at the different components. I’m thinking that there are at least a few good topics in there that would be worth a short discussion.

If you’re looking for an apk, here’s one to download.

Source on GitHub

05 Nov 2013, 19:24

Intel HAXM on OS X 10.9 Mavericks is broken

Intel HAXM on OS X 10.9 Mavericks is broken

HAXM is an Intel driver for running a hardware accelerated version of the Android emulator. It works really, really, really well. When it works. However, there appears to be a bug in the latest version of OS X where trying to load a HAXM accelerated Android emulator will cause a kernel panic, and you’ll need to kill your Mac.

Here’s the link to the thread on Intel’s forums: http://software.intel.com/en-us/comment/1761988

I’ll be keeping a close eye, because, again, the accelerated Android emulator experience is really that good. It’s actually seems to be as fast as the iOS emulator, which is impressive.

Update

The same thread says they’ve pushed a hotfix, and that it should work now!

Installing HAXM

For those of you not on OS X 10.9, HAXM is available for Linux, and Windows as well. Here are some instructions:

You’ll need to download and install the Intel x86 image in the SDK manager, preferably for 4.3, then you will need to install the driver from Intel:

Then, set up an emulator in the AVD Manager using the x86 image, and match the RAM to whatever you set in the intel driver setup. Also, make sure to use the ‘use host gpu’ option in the virtual device settings.

05 Sep 2013, 03:42

Very simple example of a Loader and LoaderManager in Android

Very simple example of a Loader and LoaderManager in Android

Loaders in Android are great, they allow you to asynchronously load data to be used in Adapters. I have found CursorLoaders very useful for getting data from a database to the UI in a way that minimizes blocking calls on the UI thread.

Alex Lockwood has posted a great, and detailed four part discussion of the Loader pattern on his blog. If you don’t know much about Loaders, or the LoaderManager, or why you might want to use them, go read that series. This is the nickle tour. My goal here is to show you just what you need to get you up and running with this.

Loaders are simple

All you really need to do is move your query into the loadInBackground method, and the rest is boilerplate.

Something to call back to

You’ll need to put the LoaderCallbacks somewhere, you can put it where you like, in an Activity or Fragment, or in a separate class. They just need to go somewhere.

Call it!

Now that you’ve got the Loader and the LoaderCallbacks defined, you can call it, and start benefiting from painless asynchronous loading of your data.

Sample

I added a Loader to the same sample project that I blogged about in my previous post. Here’s the source.

04 Sep 2013, 16:26

AndroidSerialSQL - solving some problems with SQLite in Android

AndroidSerialSQL - solving some problems with SQLite in Android

I created an Android project library that intends to solve the problem of concurrent write attempts from different threads to an Android SQLite database. Get the project here.

Quick Edit

This solution is intended to solve a specific problem, not to be used in the general case. In a larger, more complex application, you might have data coming in from different sources asynchronously (on different threads), being written to different tables, at random times. In such an application, there is the possibility for two simultaneous writes, where one may silently fail due to a database lock. This solution aims to prevent that from happening. This is not intended for the small application with infrequent database writes, or in cases where you think that being locked out on writes is extremely unlikely, in those cases, it would be better to bundle your writes in batches and transactions, which you should try to do within this framework as well.

The Problem

Here’s a blog post explaining the issue, along with a choice quote:

If you try to write to the database from actual distinct connections at the same time, one will fail. It will not wait till the first is done and then write. It will simply not write your change. Worse, if you don’t call the right version of insert/update on the SQLiteDatabase, you won’t get an exception. You’ll just get a message in your LogCat, and that will be it.

This goes farther than the singleton pattern of only getting one database object (or one writable database object) and implements a blocking queue with a thread pool executor, where the thread pool has a max size of one. This means that there will be a single thread that handles database write operations, and it will work through the backlog of requests that exists in the queue.

In order to accomplish this, we cut off access to a writable version of the database outside of a couple abstract runnables, which are intended to be added to the queue. WriterTask and UpgradeRunnable are those specialized runnables, both of them hold a reference to a database, and have ways of grabbing a reference to the writable db. There are a couple of data structures dedicated to handling the database (or databases), and these special runnables.

Using this lib

This is a standard Android library project, so if you’re using Eclipse, or are familiar with using Android library projects, just do what you normally do. I should probably turn this into a jar at some point, but I’m lazy, and may not get around to it. Plus, if I did that, I’d want to make sure that it was polished enough to submit to Maven Central and all that jazz, but that’s not where things are right now.

Use at your own risk! Right now, this is more of a good starting point, and something to look at as a reference. Don’t pull it into your project unless you plan on forking it and fixing problems as they appear.

If you’re using Gradle, you can do the following in the parent directory, or wherever you want to put your libraries:

git submodule add git@github.com:emil10001/AndroidSerialSQL.git

In your project parent’s settings.gradle:

include ':YourApp', ':AndroidSerialSQL'

In your app’s build.gradle:

dependencies {
    compile project(':AndroidSerialSQL')
}

Usage

There are a few steps to get this up and running. It should all be fairly straght-forward.

1

Create a defenition of your database.

DefineDB myDB = new DefineDB("myDB", 1);
myDB.setTableDefenition("items", 
  "create table items "
  + "( _id integer primary key autoincrement, "
  + "item text);");

2

Use the defenition to open/create the database, and store it in a data structure for use.

AccessDB.addDB(context, myDB);

3

Insert an item into your database.

AccessDB.addWriteTask(new WriterTask("myDB", callback) {
@Override
    public void run() {
        db.beginTransaction();
        try {
            ContentValues values = new ContentValues();
            values.put("item", "five");
            db.insert(ITEMS, null, values);
            db.setTransactionSuccessful();
        } catch (Exception ex) {
            Log.e(TAG, "failed to insert", ex);
        } finally {
            db.endTransaction();
        }
        callback.run();
    }
});

4

Retrieve things from the database.

AccessDB.getReadableDB("myDB").query("items", null, 
  null, null, null, null, null);

5

Handle upgrades by adding to the database defenition.

myDB.setVersionUpgrade(2, new UpgradeRunnable() {
    @Override
    public void run() {
        db.execSQL("create table two"
        + "( _id integer primary key autoincrement, "
        + "different_thing text);");
    }
});

Sample implementation

Check out the sample branch for a working app that implements this library.

Get the project

Here’s the repo on GitHub.

04 Sep 2013, 16:03

Android Sqlite Locking

Android Sqlite Locking

touchlabblog:

Recently I’ve been doing quite a bit of work with the Android Sqlite database.  Mostly with the android piece of ormlite.

The Android examples cover some basic Sqlite usage, but they really don’t go into depth with regards to proper usage patters, and more importantly, improper usage patters.  Most examples and documentation is slated towards using very basic database queries, and beyond that, creating a ContentProvider.  What never really seems to be covered is stuff like:

  • Where do you create and store your SQLiteOpenHelper instances?
  • How many should you have?
  • Are there any concerns when accessing the database from multiple threads?

If you look around for information you’ll find a lot of partial or incorrect info.  A great example was forwarded to me by Gray yesterday (he runs the ormlite project).  It was on stackexchange…

http://stackoverflow.com/questions/2493331/what-is-best-practice-with-sqlite-and-android/2493839

Read More

This is a great post on Android SQLite, and definitely worth taking the time to read. I first found it a year ago on a different blog, the post seems to move around once in a while, so grab an offline copy for safe-keeping.

29 Aug 2013, 02:17

Trying SlidingPaneLayout with Fragments (in Android)

Trying SlidingPaneLayout with Fragments (in Android)

Building on my last few posts, I wanted to try out the new SlidingPaneLayout that’s being offered in the support library. For the uninitiated, here’s a Google I/O presentation that presents SlidingPaneLayout along with a few other new UI concepts for Android:

This was super simple to do, so I’m going to go fairly quickly again.

Instructions

0

My last few posts, are prerequisites for this one. So, make sure that you’re up to speed on those.

1

Add a SlidingPaneLayout section to your activity, it should contain a couple views that you can attach things to later. Since we’re attaching fragments, these needed to be some sort of ViewGroup, and FrameLayout implements that.

2

In the MainActivity, we want to grab a reference to the SlidingPane, start it as open by default, and attach our content to it. Our content happens to be fragments, but you can attach whatever views you feel like here.

3

The fragments are pretty simple, we simply inflate the layout. I also decided to put some text and a color in there.

4

This is the layout file used by the fragments.

Conclusion

This whole thing took less time than it did to install the 0.2.6 upgrade for Android Studio, so if you’re thinking about using a SlidingPaneLayout, it’s incredibly simple, so just go for it!

Github repo here.