-
Notifications
You must be signed in to change notification settings - Fork 1
Insight: ContentPage, BackgroundTask and JSONProcessingTask
In this article, I will explain the way that a ContentPage and the JSONProcessingTask/BackgroundTask accompanying it work.
1. ContentPage:
A ContentPage extends Page and has these following fields:
public abstract class ContentPage extends Page { @InjectView(R.id.appBreadcrumb) protected Button appBreadcrumb; @InjectView (R.id.parentBreadcrumb) protected Button parentBreadcrumb; @InjectView (R.id.homeBreadcrumb) protected Button homeBreadcrumb; @InjectView (R.id.breadcrumbs) protected LinearLayout breadcrumbs; @InjectView (R.id.extraTextView) protected TextView extraTextView; @InjectView (R.id.contentLayout) protected LinearLayout contentLayout; @InjectView (R.id.contentScroll) protected ScrollView contentScroll; protected boolean dialogOnSetup = false; //set this to true if a progress dialog is needed when calling PageSetupTask protected boolean loaded = false; protected boolean jsonDownloaded = false; protected boolean jsonProcessed = false; protected JSONObject jsonContent; ... }
The @InjectView tag is responsible for the injection of the specified views for use later in the Activity. It is part of RoboGuice. These views are all part of the LinearLayout inflated from content_page_template.xml. The next 4 booleans and the JSONObject jsonContent will be used for setting up the content of the page. So this page actually has contents derived from the JSON downloaded from the wanted page, thus its name.
The difference of this kind of page lies in the refresh() and onResume() methods.
@Override
public void onResume() {
super.onResume();
if (!loaded || MyApplication.destroyed)
{
//The page is either not loaded or all its data has been erased
//after sleeping for a while and its cache is claimed
loaded = true;
jsonDownloaded = false;
jsonProcessed = false;
if (MyApplication.destroyed)
{
MyApplication.destroyed = false;
}
new PageSetupTask(this).execute();
}
if (!jsonProcessed)
{
//if manual refresh is true it should always be set back to false upon termination of a task
refresh();
}
}
This method uses 3 out of 4 of the boolean fields:
-
loaded indicates the first run of the page.
-
jsonDownloaded indicates whether the JSON needed has been downloaded for the first time.
-
jsonProcessed indicates whether the JSON data have been processed.
There is another boolean called destroyed. This boolean is a public static value in MyApplication, which means it lives along with the application’s lifecycle. destroyed is initiated to true when MyApplication is created and set to false when any instance of Page is created. That means if the application is killed by the user or the OS to make space and restarted later, this boolean destroyed indicates whether the application data have been claimed or not and force a reload of the whole page.
2. The BackgroundTasks:
There are normally 2 BackgroundTasks in a ContentPage: the compulsory PageSetupTask and another lying in the refresh() method (most likely a JSONProcessingTask). Here is how they work:
-
Depending on the state of the page, PageSetupTask will run (MyApplication.destroyed is set to true or loaded is set to false)
-
PageSetupTask is responsible for 2 things: 1 - download the jsonContent if jsonDownloaded is set to false, and 2 – build the breadcrumbs bar at the top of the page. Notice that the breadcrumbs only work using dev.m.
-
The tricky part is the second BackgroundTask. These 2 tasks are normally triggered almost simultaneously for the first run, and the second BackgroundTask might want to reuse the JSON data downloaded from the PageSetupTask, which means it should wait until the data is fully downloaded and then comes the processing. The JSON downloaded by the PageSetupTask is stored in jsonContent. This task should download the JSON itself if needed (e.g. in case of a manual refresh). After a successful first run, PageSetupTask normally doesn’t need to be called again.
-
A manual refresh is triggered by an option in the menu inflated by pressing the menu hard key on the phone. This makes the boolean MyApplication.manualRefresh true and call refresh() that spawns a new task. This task can check for the manualRefresh boolean to know when to download the new data and when not.
-
Now each BackgroundTask has a progress spinner and will show up if specified (from its constructor) and dismiss when the task is finished. Calling 2 tasks like this will result in 2 spinners, so there is the 4th boolean: dialogOnSetup that controls the progress spinner of the PageSetupTask. In case that 2 tasks may be called (and the manual refresh will call the 2nd BackgroundTask), dialogOnSetup should be false, but if only one is called, i.e. in case only PageSetupTask is present like in UnimplementedPage, dialogOnSetup should be true.
A typical task extending JSONProcessingTask looks like this:
public class WebLearnAnnouncementTask extends JSONProcessingTask {
public WebLearnAnnouncementTask(ContentPage page,
boolean toDestroyPageAfterFailure, boolean dialogEnabled) {
super(page, toDestroyPageAfterFailure, dialogEnabled);
// TODO Auto-generated constructor stub
}
@Override
public void updateView(JSONObject jsonContent) {
try {
JSONObject announcement = jsonContent.getJSONObject("announcement");
LinearLayout announcementLayout = (LinearLayout) page.getLayoutInflater().inflate(R.layout.weblearn_announcement, null);
...
page.getContentLayout().removeAllViews();
page.getContentLayout().addView(announcementLayout);
((ContentPage) page).doneProcessingJSON();
} catch (Exception e) {
e.printStackTrace();
otherException = true;
}
}
@Override
protected JSONObject doInBackground(JSONObject... params) {
if(Page.manualRefresh)
{
return super.doInBackground();
}
while (!((ContentPage) page).downloadedJSON())
{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return ((ContentPage) page).getJSONContent();
}
}
doInBackground() here checks for a manualRefresh, if true, it will download the data from scratch and returns it (the method doInBackground() in JSONProcessingTask class does just that, thus the call super.doInBackground()) otherwise it waits and the rest is self-explanatory.
updateView() will not be called if doInBackground() returns null (see the code of BackgroundTask). All the layouts and other views should only be added to the contentLayout of the page, accessible by using the method ContentPage.getContentLayout(). By the end of the try block, ContentPage.doneProcessingJSON() should be called to set jsonProcessed to true.
Any Exception caught should make the boolean otherException true – this will trigger the Exception handling and error messages in BackgroundTask.onPostExecute(). For more details, you should refer to the code of BackgroundTask and AsyncTask.