The goal of this article is to remove calls to debug log for release builds. Debug logs, which is done using Log.d(tag, msg) often contains more information that you want exposed to the public. It also takes up valuable CPU cycles.
Remove Log.d calls via Proguard
Proguard is a tool on Android that shrinks, optimize, and obfuscate your code. We want to use this on our release builds. In Gradle, we enable this either in the buildType or product flavor closure. The details can be found in the Android Tools User Guide
Example build.gradle:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Note that there are two default rules files. When you first create a project in Android Studio, you usually get a proguard-android.txt file. In order for us to tell Proguard to remove the debug log, we need it to run the optimization phase, so we need to tell it to use the proguard-android-optimization.txt file instead.
The second thing to notice here is the inclusion of a second txt file, the proguard-rules.txt. This text file is how we tell Proguard to remove calls to Log.d, Log.v, Log.i, and whatever else you think is safe to remove.
Example proguard-rules.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The assumenosideaffects flag is an optimization option that tells Proguard to treat the declared method as an empty method and thus is safe to remove. Details can be found in the Proguard Usage Manual.
Please note that if for whatever reason you decide to use the returned integer from Log.d and assign it to a variable, Proguard will think that it maybe a useful method and won't remove it. So make sure that whatever method you decided to use this option with does not return a value that's being used, if your intention is to remove the call.
So now if we compile the release build, we would effectively remove the Log.d. So lets take the following example set of calls
Before Proguard:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
As we can see, it did a decent job of removing the debug logs. But it also left something behind. It created a new class and called some function. This is the obfuscated version of the code. So what we are seeing here is that the UserInfo class is still being created. So while we no longer take up I/O cycles by logging, we are still taking up CPU and memory by creating a class that we otherwise didn't need to create. So how can we change the code such that Proguard can safely remove the creation of the UserInfo class? It turns out that if we wrap it around a final boolean of FALSE, then Proguard will remove the code since there's no way the code can be executed. So we might consider changing our code to something like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This is a working solution. But because it requires that you add these "if (BuildConfig.DEBUG)" statements everywhere, it may not be acceptable, depending on the size of your project.
You need to have a rooted phone. Rooting of a phone is different for every device model, so it's important to find the right tools and procedure for your particular phone. Once your phone is rooted, connect your computer to your phone via USB and enable debugging via the developer options. You can now use the following set of commands in your computer terminal.
What we're doing here is making the system folder read and write-able. Some of the preload apps will be in the system/priv-app and some will be in system/app. Only apks in /system/priv-app can use "system"-level permissions. Prior to Kitkat, all apks on the system partition could use those permissions. Uninstalling the app is just a matter of removing the APK file.
I was cleaning up my laptop today and found an old memo that I thought was worth saving. I wanted to post it here in case anyone thought it was useful.
As a seasoned mobile application developer, I'm regularly approached by recruiters for new exciting opportunities, many of them from startup companies that are ready to jump into the mobile app world with existing web services.
Most companies start breaking into the mobile app development with iPhone/iPad app. This is influenced by reports that iOS users are more willing to pay. CNN reported in 2011 that Apple users buy 61% more apps! What's more, it's my personal experience that Android app simply takes longer to develop. Here are my reasons for that:
Apple's XCode has a wonderful emulator & profiling tool for performance.
Android's emulator is slow; really really slow. So slow that every developer must obtain a physical device.
Apple's Xcode is a mature IDE
Most developer still develop their Android app using the poorly executed Eclipse IDE.
If you're lucky and have some bravery, you've switched to Android Studio, which is based on the rock solid IntelliJ IDEA. Even though it's in beta, it will improve your life dramatically.
Apple's adoption rate is extremely high, so you code against only the latest SDK
In Android, you have to draw a line where your minimum SDK would be.
This version will have consequence in terms of how complicated your code becomes and what open source libraries you maybe able to take advantage of.
As an illustration, the project I'm currently involved in has an iOS and an Android team. We're building roughly the same app. Adjusted for developers dedicated to features specific to a platform, the iOS team has only 2 person, but the Android team has 4. I've been involved in developing a dozen mobile apps, and time and again, the iOS app has less bugs, jank, and requires less people.
How long does it take to make a mobile app? Answer: 18 weeks!
If you've started with an iOS app, you have at least one mobile developer. She is going to understand the challenges presented to her like no other kinds of developer. She understand that you are going to be running code in someone's personal phone, which means the user care about battery life, bandwidth usage, privacy, and most obviously, the user need that phone to be a phone first, and an application second. Because of that your application can be interrupted any time. And because of these limitations, there are apps that simply doesn't belong in the mobile world, or at least not in the same form as you would on a desktop.
So what if your version 1.0 app is going to be an Android app because market research suggest that those are your primary customers? Here's what I would look for in a candidate:
Understanding application life cycle
What type of objects would be appropriate to store in the Application?
How would I handle the app being interrupted by a phone call in an Activity or Fragment?
What special care to take if the app is to support orientation change?
Proper usage of thread
What are Executors and how do you choose which Executor to use?
When is it appropriate to use runOnUiThread and when would you use Handler instead?
In which thread are the method in AsyncTask executed in and how would you make it safe to use if your app handles both portrait and landscape orientation?
What things are appropriate to run in the UI thread?
Understanding Services
What type of task is appropriate to be done in a Service?
How does a Service notify the application UI of progress or result?
and many many more topics, that not everyone is going to know
Adding maps to your app
Writing a widget
Chrome casting
Media playback
Ads integration
Facebook and Twitter integration
Lastly, you need to be able to build and distribute the app, which initially may be very simple, but soon enough you'll need someone who knows how to build, sign, and submit the app. You may want someone who's familiar with Maven, Gradle, and Google Play
I think if you're in a startup and wants to hire just one Android developer, she needs to have a good amount of diverse and deep understanding of Android. In my opinion, it's worthwhile to plan out what features you want to build so that you can ask the right questions. There's no point in hiring someone who has tons of experience in Map related apps if you're not going to be integrating maps. That's not to say you shouldn't hire a good generalist. But since this is your first and only Android developer in your startup, you need someone who is already an expert in Android, so in this case, you need someone who has already done it.
The other part of the hiring process that I find extremely flawed in the software industry is how we interview people. Most typically, we revert to CS 101 questions. While most of those questions are legitimate, many of them are useless. For example, a now popular question is about how to detect infinite loop in a linked list. This is popularized by an interview book that both interviewer and interviewee reads, and thus offer no insight today. If she ace the question right away, I'm pretty sure she just read the book. And honestly, how often do you encounter most of the things we ask in these interviews anyway.
The best interview that I've personally had was when I was asked to bring my own laptop, my own IDE, and pair program together a very simple app. For example, write an app that downloads a JSON file and display it in a ListView. Another type of question would be to design the app that you want to build. What component would we need. what open source library can we utilize. Perhaps most importantly, IMHO, is to make the interviewing process worthwhile for both parties. Both person should walk away learning something.
I realize my opinion doesn't align exact with Joel Spolsky's view on interviewing. I just think his views can be adjusted for different types of developers. And as Google admitted, even their hiring process is flawed. And perhaps the technical interview is dead. One thing is certain, hiring and getting hired as a software developer is hard!
So godspeed to all who look for the right developer! and godspeed to those of us who strive to widen our knowledge and to sharpen our skills everyday. May we encounter good people and produce great product that enriches our society.
I've always liked how nice the StringBuilder API is. But I have not found the perfect opportunity to use it until today when I wanted to create a clean API for a Request object for searching OnDemand videos. The server API has been defined to accept a bunch of parameters. And depending on what you want to search for, you may supply one or more of these parameters.
What I wanted to create was a request object that's immutable once it's created. I have plans to use this request as a key to retrieve cached response, so it would be messy if someone was allowed to modify the attributes of the original request. So I've decided to have no setter methods.
I could create a constructor with all the parameters, but that would mean that most of the time the developer may have to create a SearchRequest object with lots of nulls. It's also very easy to misplace the arguments. If argument 1 is the rating and argument 2 is the offset, and they're both integers, I can imagine someone accidentally putting the value for offset in the ratings position and the value for ratings in the offset position.
The Builder pattern can be helpful in my situation. So I've prototyped the class here. Let's take a look at how I use this class first. Here's an example of a SearchRequest that query for high rating sports TV shows and episodes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Running this code generates the following print: 03-01 20:00:59.849 1321-1321/com.example.app I/System.out﹕ http://my.server.com/search.json?offset=0&max_result=100&rating=4&categories=SPORTS&types=TV_EPISODE,TV_SERIES
I've restricted the creation of the SearchRequest object directly by making the constructor private. Instead the developer need to create a new SearchRequestBuilder. The builder then has small methods that are clearly named to add attributes. Once you have composed the request you want, you call the toSearchRequest method and you get the SearchRequest object.
And here's the source code for SearchRequest. I've seen variations of this pattern, but I've implemented it to satisfy my own requirements. I'd love to hear how you've used this pattern in the course of your career and how it differs from my interpretation.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
It has been a while since I've dealt with SQL. Recently we wanted to see if having an SQLlite database in Android would provide a performance boost. The idea is to prefetch the day's TV guide and load it into an SQL database during the night. And then when the user starts the app, we would first look at the database to see if we already have the data. If so we would load that instead of going through a network request. There may also be a performance boost if the query was written properly. Another benefit over network request is that the REST resource is in JSON format and needs to be parsed, whereas translating from a database row into a POJO potentially is faster. It also takes us later into using CusorAdapter and load data on demand. For those reason it's worth trying it out.
The first thing I need to do is store all my TV Program POJO into the database. And the first step is to create a table. To create a table, I execute an SQL statement such as this:
CREATE TABLE program (id INTEGER PRIMARY KEY, name TEXT NOT NULL, start_time NUMERIC, end_time NUMERIC)
It reads that we're going to be creating a new table with 4 fields: an ID, name, start and stop time. This table will have the name program. Each row in this table must have at least an ID and a display name.
In Android, we do this by creating a class that extends SQLiteOpenHelper and overriding the method
public void onCreate(SQLiteDatabase db);
In that function we can execute the query
db.execSQL(createTableQueryStr);
The SQLiteOpenHelper is a class that manage database creation and help with version control.
When you extends SQLiteOpenHelper, you are also required to implement onUpgrade method. Here, we'll simply delete the table and erase all previous data. The query is:
DROP TABLE IF EXISTS program
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The Program POJO actually has more data than the 4 things, but for simplicity of this blog, we'll pretend there's only 4 fields. But I want to mention that in reality, the POJO also includes a List of Strings that denotes which genre(s) the program belongs to. In order to include this information, I needed to create a 2nd table of genres. I decided to use Foreign key contraint to better insure data integrity. This way I don't accidentally add a Genre that doesn't belong to any program. The query for that table looks like this:
CREATE TABLE genre (program_id INTEGER, genre_name TEXT, FOREIGN KEY (program_id) REFERENCES program(id))
A database query always return a Cursor. It's the mechanism for which you retrieve the result. It doesn't load all the results in memory, only what the cursor is pointing at. This is good if you pass this cursor to your view so that you only need to get the data that is displayed in the UI, but it's not always possible depending on how the app is structured. So for convinence, I've created some method to translate between table row and POJO and vise versa.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Before you can insert, query, or delete anything in the database, you need to open it. This is usually done either than your app is created or when your Service is connected. Here I've created a ProgramsDataSource class that'll help me insert query and remove programs based on the start_time of the TV program.
Note the use of the insertWithOnConflict method where if a row already exist, I'll replace the values instead of throwing an exception.
The other thing to note is that if you need to use the DISTINCT function of SQL to query all unique names for example. Let's say I want to know programs of my entire TV Guide during prime time during the week, but I don't want to see the evening news show up 5 times, I would do a query with DISTINCT. To do that in SQLiteDatabase in Android, you use the overloaded method for query with the boolean as first argument.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
First thing to note is a StringTokenzier is depreciated.
StringTokenizer is a legacy class that is retained for compatibility reasons although its use is discouraged in new code. It is recommended that anyone seeking this functionality use the split method of String or the java.util.regex package instead.
Instead use String.split(String regex), which takes regular expression. So to use the method we have to look at how regular express can split words.
[^abc]Any character except a, b, or c (negation)
\sA whitespace character: [ \t\n\x0B\f\r]
\SA non-whitespace character: [^\s]
So to split words in a String, I use the following:
String line = "Lorem ipsum dolor sit amet, consectetur adipisicing elit...";
String[] words = line.split("\\s*[^a-zA-Z]+\\s*");
I've been tasked to modernize our application's networking layer. We have been writing our own network manager to deal with http 302 redirect and caching responses, but there are many opensource project that already does these things very well. I've looked into RoboSpice and Volley as the more popular choices for doing networking in Android. I found that they're a good candidate as an improved AsyncTask as well as providing caching. However both framework are closely related to the Activity context and doesn't work as well when put into a Service such as ones that I intent to make with a SyncAdapter. We needed a lower level framework. To figure out what fits our bill, we wrote down some of our requirements:
It needs to support Https
We want to translate server JSON into client POJO
The framework needs to allow us to edit the header and post body for authentication
We want the ability to pass arguments to methods and insert them as part of the URL or the query
We want to save bandwidth with Gzip
We want efficient communication with parallel requests
we want Http caching that follows the server's http cache directive
It needs to follow http 302 redirect
It needs to work well with Android
I stumbled across Square's Retrofit and OkHttp. Here's how it fits.
Retrofit
Supports Https
In Retrofit's home page, their example uses https, so clearly it supports it.
RestAdapter restAdapter = new RestAdapter.Builder()
.setServer("https://api.github.com")
.build();
Converts JSON to POJO
Retrofit use GSON by default to convert Http bodies to and from JSON.
Edit request header and body
Retrofit allow header information to be set statically using annotation or at runtime using a RequestIntercepter.
Edit URL and query
Retrofit uses annotated method arguments to replace PATH or query placeholders. You can also change it at runtime using RequestIntercepter.
Working with Android
The generated implementation GET and POST can be made synchronously outside of UI thread, or asynchronously callback on the UI thread, or in background thread via Netflix's RxJava rx.Observable. So it's very flexible in what threading model we need. We can also put RoboSpice on top of Retrofit later if we want.
"it will silently recover from common connection problems"
Local Caching
OkHttp's HttpResponseCache allows you to set aside a specific amount of space in cache directory, very similar to Google's HttpResponseCache.
First create an OkHttpClient and set 10MB of space in the cache director for caching
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Then in order to add some standard PATH and query parameters I create a RequestInterceptor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Then we can build the RestAdapter and set the OkHttpClient as the networking component and set the request interceptor so that every request will be modified to include those Path and query.
Note that for debugging purpose I've turned on debugging so I can see the actual request and response in the log.
Also note that the http scheme is set as part of the most.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Then with the RestAdapter, you call create with the Interface that you want to create. But before we do that, we need to define the Interface.
GET
Notice that synchronous call throws RetrofitError at runtime, so I've declared it in the interface explicitly here. The caller should try/catch the request in case an error occurred.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
So now, we can create POJO data for all the data that our server returns, create Interface files for all the APIs that the server has available, annotate the URL, the header, the post body, and the return type. And then I should have a brand new and robust REST library for my application!
For more information, visit the
Android introduced Loaders in 3.0 to ease asynchronous tasks on Activity and Fragments. It monitor the source of the data and automatically deliver new result when content changes. It's primary usage is to work with a database utilizing the CursorLoader, but it can also be used to do other asynchronous tasks. I want to take a look at how Loaders could be used as a replacement for AsyncTask.
The issue with AsyncTask is well known. If you rotate the device, you have to cancel the AsyncTask or the app will crash. Loaders handles rotation better, it automatically reconnect to the last loader’s cursor when being recreated after a configuration change avoiding the need to re-query their data.
There is an instance of LoaderManager in every Activity and Fragment. You simply call getLoaderManager(). Note that if you're using the support library, you will call getSupportLoaderManager() instead.
To do the actual task, create a class that extends the AsyncTaskLoader and implement the loadInBackground method. The return type will be whatever data you want to send back to the main app. In my example, the work is just to sleep for some time. And my return value is just how many milliseconds I slept.
To trigger the work, the first thing to do is to implement the LoaderCallbacks interface in your Activity or Fragment. You can then call initLoader in the Activity's onCreate method. In my test app, I'm actually going to start the task after clicking a button, so I call initLoader() and forceLoad(). The onCreateLoader method will then be triggered. Notice that it uses an integer ID to identify the Loader. I'm not sure, but my guess is that typically you only have one Loader to handle all the asynchronously tasks for an Activity or Fragment.
Finally, to get feedback on the UI, the onLoadFinished method will be called in the UI thread where you can show the result. In my example, I'm simply making a Toast message, but you could imagine where we can update a table with rows of values or show a text.
Note that while AsyncTask has onProgressUpdate(Integer progress) to show how much data has been fetched, a Loader doesn't have this capability out of the box.
I still have a lot to learn about Loaders after this short prototype. So far, it seems like a lot of work to avoid canceling and restarting tasks. If data fetch performance is a concern, which is always the case to a certain degree, then I would consider using AsyncTaskLoader instead of AsyncTask. But there are alternate solutions, such as RoboSpice, that maybe a better solution. My guess is that Loaders are much more effective when dealing with database, which I intent to try out soon.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
In our Android phone TV application, we need a few server resources before meaningful data can be fetched. For example, we need to know the template for the playback URL so that when user select a channel, we can construct a full URL to play from the channel ID, the device dimension, etc. We also need to fetch another table that tells us which settings to use when the app is connected to a WiFi spot versus when it's on a cellular signal. We need these and a few other essential resources before the app can start.
All of these resources are asynchronous fetches from the server. And we don't want to navigate to the home page until all resources have been retrieved. A handy class to help track that we've got all those resources is the CountDownLatch. It blocks the calling thread until the count reaches zero. You create the latch, fire off your asynchronous tasks in separate threads. Then when each of the task is finished, you decrement the count by calling countDown().
To block the calling thread, you call the await() method. One mistake I made the first time was call wait() instead of await(), so make sure you call the right method. If you call wait, you'll get an IllegalMonitorException.
Warning: NEVER block the UI/main thread!
It's obvious, but still worth noting. You should not use this on the main thread. Instead I would use this to patch several tasks and make it act like a single operation, then notify the UI that all tasks are done via a handler or broadcast receiver.
To see how it all works, I wrote a simple function and run it to see how it looks:
Sample code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
I was trying to publish a JavaDoc for my Android Library. Being an absolute novice in Gradle, I searched the net and found a piece of gem that just worked. The Magic is from line 31 to line 46. It creates 2 Gradle tasks for me:
generatedebugjavadoc &
generatereleasejavadoc
WebRep
currentVote
noRating
noWeight
And then the JavaDoc files can be found in <ProjectDir>/build/docs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
When I ask my colleagues about IntentService as a way to execute asynchronous tasks, most seems to be unaware of it existence. Perhaps it is because it doesn't interact with the UI/main thread like AsyncTask does, so it's use is limited to background processes that doesn't require UI feedback, and so there are less scenarios where it is appropriate. IntentService is just one of many ways Android provide asynchronous operations. Others include
runOnUIThread
Executor
Handler
AsyncTask
Service
Loader
Service vs IntentService
The first question that most developer ask is what's the difference between a normal Android Service and an IntentService. Most folks understand that a Service is an application component that can perform long running tasks in the background without UI feedback. If you read the Class Overview of IntentService, you would read that
"IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand."
The first time I read this quote, I interpreted to mean that Service extends IntentService. But the opposite is true.
public abstract class IntentService extends Service
IntentService does a little bit more than what Service does for you.
While a regular Service runs in the caller's thread, which in most cases is the main thread, IntentService always run on a background thread.
IntentService uses a message queue to process requests, so only one intent is handled at any time.
if you need parallel tasks such as downloading multiple images at the same time, IntentService may not be a good choice.
If one of the tasks is stuck, then all the pending tasks in the queue will not execute.
Calling stopService is optional; The IntentService will stop itself once there's no more work on the queue.
A broadcast receiver is needed if you want to provide UI feedback.
Implementing an IntentSevice
There are only a few things you have to do:
Declare a few constants for communication between application and IntentService.
Create a class that extends IntentService; Implements onHandleIntent method.
Create a BroadcastReciever; Implement onReceive method.
Trigger the IntentService by calling startService, with input arguments wrapped in an Intent.
Example:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
In order to handle configuration change properly, when the device is rotated for example, the broadcast receiver should be bind and unbinded along with the lifecycle of the Activity or Fragment
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Note that the requests are handled serially such that if startService was called by mistake more than once with the same Intent, the work will be done twice, so it's important to either prevent that from happening in the calling side or write the IntentService such that it recognize a duplicate request. This can be accomplished by a runtime cache or input and output. So if the service receive the Intent and it already cached the result, then just broadcast the result again. Finally, if you call stopService all the pending tasks will be lost, which maybe what you want.
To see how others have used IntentService, I went on Github and did a search and found a few examples of open source project that uses IntentService as a background task.
RingerMuteService uses IntentService to change the volume level of the device