Custom Android Navigation Drawers — Part 1
Files created in this tutorial:
I suggest that you follow the tutorial and refer to the commits at the end of each step in order to make sense of the code.
Basic setup on Android Studio using navigation drawer template:
- Click on File → New Project
- Enter Application Name as whatever you wish. Here, I shall use “Navigation_Drawers”
- Click next and select “Phone and Tablet” target API as 21(Lollipop).
- In Add an Activity to Mobile, select the Navigation Drawer Activity.
- Proceed with Next and then Finish
- In the manifest, add the following permissions:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
Creating a JSON data source:
We need some data source from which we will fetch our menu entries.
In order to make this tutorial more useful, lets create a web hosted JSON File and use that as the data source.
We assume that we have the top level menu entries fixed and the sub options as variable.
For simplicity, lets say we have the menu as:
1. Books → Book Names
2. Characters -> Characters.
Here Books and Characters are the top level menu entries.
Book names and characters will be populated using the JSON such that only on selecting a book, will the characters sub menu be populated.
You can either create your own, or use ours: https://dakshil.github.io/android_custom_drawers/books.json
To host your file, create a GitHub Project. Go to settings and create a Page for the project.
Now add the file to your project as done at https://github.com/dakshil/android_custom_drawers/blob/master/books.json
Visit the Page of your project and traverse to the JSON file, just as seen in the above links.
Fetching the JSON data:
Now that we have the data, we need to somehow fetch that onto the device and parse it, i.e. store the values for later use.
We could directly read the data from the URL, but in the future in case one has a static file that is updated once a month, a timestamp can be used on this downloaded file, rather than downloading it each time the app is opened.
We first fetch the JSON file on app open:
- Create a new Java file called “fetchJSONFile” under app → java → whatever the folder where your MainActivity resides in.
- The class must extend AsyncTask as we wish to download in background to avoid hanging the main thread activity.
public class fetchJSONFile extends AsyncTask<Void, Void, String> {
...
}
3. Create a constructor as:
public fetchJSONFile(Context gotContext, String gotFileName) {
context=gotContext;
fileName=gotFileName;
}
4. Create the following methods:
protected String doInBackground(Void... voids) {
}@Override
protected void onPostExecute(String path) {
returnFilePath(path);
}
private String returnFilePath(String result) {
return result;
}
5. In the doInBackground method, we shall download the JSON file as:
try {
String fileURL = "https://dakshil.github.io/android_custom_drawers/" + fileName;
URL url = new URL(fileURL);
InputStream in = new BufferedInputStream(url.openStream());
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int n = in.read(buf);
while (n!=-1)
{
out.write(buf, 0, n);
n=in.read(buf);
}
out.close();
in.close();
byte[] response = out.toByteArray();
String filePath = context.getFilesDir().getPath() + File.separator + fileName;
FileOutputStream fos = new FileOutputStream(filePath);
fos.write(response);
fos.close();
path = context.getFilesDir().getAbsolutePath() + "/" + fileName;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return path;
6. In MainActivity, we call the file downloader of step 5 as:
String JSONFilePath;
String JSONFileName = "books.json";
fetchJSONFile jFile = new fetchJSONFile(this, JSONFileName);
try {
JSONFilePath = jFile.execute().get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
Commits for above steps:
Parsing the JSON data
Now that we have the data, we need to extract the data from it.
Create a new java class called “parseJSONFile” in same directory as “fetchJSONFile”.
- Create classes to represent the JSON data:
static class Characters {
String name;
}
static class Books {
int bookID;
String bookName;
List<Characters> characters;
}
static class JsonData {
List<Books> books;
}
2. Create a method to verify storage permissions:
//above api 23, require user to grant explicit permission to app to access external storage
public static void verifyStoragePermissions(Activity activity) {
// Check if we have write permission
int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
3. Create a method to read the JSON file into a string:
private String readFile(String jFilePath, Context context) throws IOException {
FileInputStream fileIN = new FileInputStream (new File(jFilePath));
StringBuffer data = new StringBuffer("");
byte[] buffer = new byte[1024];
int n;
while ((n = fileIN.read(buffer)) != -1)
{
data.append(new String(buffer, 0, n));
}
fileIN.close();
return data.toString();
}
4. Create a method to map this JSON data to the classes we created with respect to the data:
public JsonData bookDataParse(String jFilePath,Activity activity, Context context) throws IOException {
verifyStoragePermissions(activity);
String json = readFile(jFilePath, context);
Gson gson = new Gson();
JsonData data = gson.fromJson(json, JsonData.class);
return data;
}
5. In your MainActivity, after view is initialized, fetch the data by passing the location of where we downloaded the JSONFile.
parseJSONFile parser = new parseJSONFile();
if(!JSONFileName.equals("")) {
try {
parseJSONFile.JsonData data = parser.bookDataParse(JSONFilePath, this, MainActivity.this);
} catch (IOException e) {
e.printStackTrace();
}
}
Commit for above steps:
To check if everything works, place breakpoints and inspect the values at each step.
In Part 2, we shall see how to utilize this data for the navigation drawer.
Custom Android Navigation Drawers:
https://medium.com/@Dakshil/custom-android-navigation-drawers-8167fead188a
Feel free to leave any comments, suggestions for improvement or other thoughts.
If you used the code above, please do star/fork the repository and give the correct attribution.