The Vital Guide to Android Interviewing - 2
Posted On:
As with any technology, theres knowing Android and then theres really knowing Android. This guide offers a sampling of questions that are key to evaluating the breadth and depth of a candidates mastery of the Android mobile framework.
The Challenge
Finding them requires a highly-effective recruiting process. Such a process can then be augmented with questionssuch as those presented hereinto identify those sparsely distributed candidates across the globe who are true Android experts.
Android is a smartphone operating system built on top of Linux based on Java and XML. Since its not just a language, but a complete, rich and growing software framework, it has alotto master. As of this writing, Android is in its 7th year, now at version 4.4 (KitKat) and has undergone 19 SDK releases.
Google introduced Android as an open source project in 2007 (seeAOSP) so it could get a foothold in the emerging smartphone market. Numerous hardware vendors have used Android for their handsets (Samsung, HTC, Sony, Motorola, and LG just to name a few), often adding their own custom features and code. This sometimes creates additional headaches for developers when incompatibilities or vendor-specific bugs arise (read: workarounds). Android itself isnt perfect either, of course with its sometimes lacking documentation and some quirky-behaving code but it is still certainly a force to be reckoned with.
The Android development platform offers a plethora of features and support classes:
- User Interface, animation, graphics, varying screen size support and orientations
- Touch screen keyboards and gesture recognition
- Databases, content providers, content resolvers, adapters
- Location detection, sensors, services
- Threading options
- Accelerated computation
- Inter-app communication
- Media playback and recording
- Networking and connectivity
- Google Play store and in-app billing
- Localization
- Debugging tools
- And much more
TheUser Interface(UI) is the face of your app. An applications UI is critical as it forms the basis of how users interact with and perceive your app. Android offers numerous classes that developers leverage and customize while also providing a general framework that users come to rely on.
For example, Android provides a general purpose solution for a top navigation system called theActionBar. It also provides support for aNavigationDrawerthat users can slide open and close by tapping an ActionBar menu button or swiping the left edge of the screen. Android provides an abundance of UI classes and widgets to lay out views, create animations, perform custom drawing, displaydrawables(icons, bitmaps, shapes, etc.), and more.
Much of an Android UI can be specified with XML, but one can also write custom subclasses that extend Android UI classes to create custom views and behaviors. The scope of the UI is quite broad (it even includes media playback, video, audio, phone vibration, for example), so we cant cover everything here, but well highlight some key areas that solid Android developers should be well versed in.
Q: What are Activities and Fragments? When and why should you use one over the other?
AnActivityis a user interface component that represents the main focus of attention on a screen. In contrast,Fragments, introduced as tablets emerged with larger screens, are reusable components that are attached to and displayed within activities. Multiple fragments can be shown at once within an activity. While its possible to develop a UI only using Activities, this is generally a bad idea since their code cannot later be reused within other Activities. Elite developers know this and write fragments (sometimes used within trivial activities) tofuture prooftheir app. With this approach, the activity supports its attached fragments, letting the fragments, their layouts and views handle the lions share of the user interface.
For example, lets say you want the user to be able to horizontally scroll through a set of pages where each may show a list, photo, photo gallery, dashboard, or form. Here you might use aViewPagerin your Activity whose items are fragments that handle each of those unique user interface functions separately. If the developer had written these pages as Activities, they would have had to refactor them as fragments.
Also note that, while you can use an Activity without a Fragment, the reverse isnt true.
Q: What are Adapters and when and how are they used?
Its tough to develop an Android app without using an adapter somewhere because they are so important.
Where do adapters fit in? They bridge the Model and View (e.g.AdapterViewssuch asListViews,GridViews,Spinners, andViewPagers) with underlying data. They provide access to data items and are responsible for creating a view for each item in the data set.
Android doesnt adopt the MVC pattern per se. You define the Model that works for you. Android helps you layout and render views, and you customize Androids Activities and Fragments that typically act as Controllers.
Novice developers might try to get away with using simplehelperadapters like,
ArrayAdapter,
SimpleAdapter
and when possible,SimpleCursorAdapter.
But these are usually too limiting for some of the more complex views typically required by todays apps. Master developers will write adapters that extendBaseAdapter
directly because it is more powerful and flexible than the subclass helpers mentioned above.The following snippet shows a custom ContactAdapter that displays contacts in a ListView.(Note: Only the more important methods required are shown.)
// A basic data model for illustrative purposes
class Contact {
publicint id;
public String name;
public String phone;
}
publicclassContactAdapterextendsBaseAdapterimplementsListAdapter {
Context mContext;
List mContacts;
publicContactAdapter(Context context) {
mContext = context;
}
// Call this method to attach data to this adapter, and call when the data changes.
publicvoidnewData(List data) {
mContacts = data;
// Inform AdapterView that data has change and to redraw if necessary.
notifyDataSetChanged();
}
// The crux of the adapter -- bind data to the view layout.
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Contact contact = mContacts.get(position);
LinearLayout view = (LinearLayout) convertView;
if (view == null) {
// "Inflate" our contact.xml view into existence.
LayoutInflater inflater = (LayoutInflater)
mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = (LinearLayout) inflater.inflate(R.layout.contact, null);
}
// Bind the data to their appropriate TextViews in the layout.
((TextView)view.findViewById(R.id.name)).setText(contact.name);
((TextView)view.findViewById(R.id.phone)).setText(contact.phone);
// ... etc. ...
return view;
}
}
Performance and Responsiveness
Users are so demanding. Your app must perform and be responsive or people will become frustrated and simply stop using it.While requirements for an app should clearly define acceptable response times (although shorter is always better), developers should themselves have a general sense for what is reasonable and take measures to optimize performance accordingly. For example, when fetching a lot data from a server, steps should be taken to avoid locking up the user interface (i.e., by loading the data on a background thread).
Seasoned Android developers can be expected to have a variety of performance optimization tricks up their sleeves. The questions that follow aim to evaluate their acumen in this regard.
Q: What are some ways to optimize View usage?
If not careful, the unwitting Android developer can easily get carried away with creating more views in their layouts than necessary. The more views you can remove from your layouts, the more responsive your app becomes. Fewer views mean less memory consumed and reduced garbage collection, as well as less work initializing, laying out, drawing, and traversing views.
Poor design becomes quickly apparent, for example, when trying to scroll rapidly through unoptimized layouts, which can appear sluggish and jerky. If particularly bad, the scrolling experience might become unusable, especially on lower-end devices with slower CPUs. Here are some view optimization techniques an experienced Android developer should be expected to be familiar with.
Technique #1: Optimize views in layouts.Layouts are XML resource files that define views for activities and fragments. Because their design is so important to application performance, Google has written an entire training guide on the subject ofOptimizing Layout Hierarchies.
Lets take the following layout as an example:
This layout consists of four views: a root level horizontal
LinearLayout
that encapsulates anImageView
and a verticalLinearLayout
that contains twoTextViews
. This results in a three level hierarchy.This layout can be optimized by flattening its hierarchy to two levels by using a single root
RelativeLayout
and dropping the secondLinearLayout
altogether. TheImageView
can be positioned to hug the left side of the parentRelativeLayout
and theTextViews
can hug theImageView
or the right side of the parent. The savings in speed and memory may not seem like much individually, but when applied to numerousListView
elements (for example), it can add up quickly and dramatically affect performance.Technique #2: Use the
tag in your layout files.
Its smart to use the
tag if possible when defining a view that is intended to be inflated and added to an existingViewGroup
, such as aGridView
orListView
. This avoids creating an unnecessarymiddlemanViewGroup
such asRelativeLayout
orLinearLayout
just to encapsulate child views. The
tag is simply a placeholder for the parent view that its children will be attached to. In the following example, only theImageView
will be added to the parent, thereby eliminating the need for one of the encapsulating views.Consider the following layout:
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
RelativeLayout>
The above use ofRelativeLayout
, though standard practice, can be eliminated by using a
tag as follows, thereby optimizing this layout:
<mergexmlns:android="http://schemas.android.com/apk/res/android">
<ImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
merge>
Now were using one less view!Technique #3: Consider using a ViewHolder pattern, but do so judiciously.Use of the ViewHolder pattern can improve performance, but it is not a perfect solution. In fact, some would argue that it is really ananti-pattern. In the next question, we discuss the advantages and disadvantages of the ViewHolder approach. These issues should all be carefully weighed and considered before deciding if, where, and when to employ this technique.
Q: What is the ViewHolder pattern and how is it employed? What are some reasons for, and against, using it? What are some alternatives?
One of the first patterns novice Android developers are introduced to is the ViewHolder patternwhich, as previously noted, and as will be further discussed, some might refer to as an anti-pattern.
When we wish to display lists of items in Android UI, we typically use:
- A concrete
AdapterView
subclass such asListView
,GridView
, etc. - An underlying data set, typically an array ofPOJOsor aCursor(a set of database rows)
- An
Adapter
class responsible for creating and populating Views with specified data elements
AdapterView
attempts to recycle Views that are no longer displayed on-screen. This simple but effective technique allows applications to avoid:- Incurring the cost of garbage collection
- Incurring the cost of layout inflation
View.findViewById()
repeatedly to locate child views within a layout. Calls toView.findViewById()
are expensive because sizable chunks of the layout (a hierarchical structure) must be traversed on each call to find a desired child View within a potentially complex layout. There can be noticeable lag when rapidly scrolling through a list with nested layouts, leaving most developers with an ugly problem in search of a solution.Enter theViewHoldercaching pattern. But first, lets put this into historical perspective. Before Android 2.2 (Froyo), the performance of the Dalvik VM and its Garbage Collector were dismal, so it was in this context and to help address this issue that the ViewHolder pattern came into being.
However, with the inclusion of a JIT compiler and vast improvements in the Garbage Collector, the cost of not caching
View.findViewById()
has decreased dramatically (although its still worthwhile and not expensive in terms of developer effort). ViewHolder has therefore become a less necessary approach, which is particularly problematic given some of its negative side effects, such as:- Code clutter
- Breaking theSeparation of Concerns Principle
- Breaking theSingle Responsibility Principle
View.findViewById()
:
staticclassViewHolder {
TextView text;
TextView timestamp;
ImageView icon;
ProgressBar progress;
int position;
}
And then ingetView()
of your Adapter class, cache its results:ViewHolder holder = new ViewHolder();
holder.icon = (ImageView) convertView.findViewById(R.id.listitem_image);
holder.text = (TextView) convertView.findViewById(R.id.listitem_text);
holder.timestamp = (TextView) convertView.findViewById(R.id.listitem_timestamp);
holder.progress = (ProgressBar) convertView.findViewById(R.id.progress_spinner);
convertView.setTag(holder);
Savvy developers recognize that ViewHolder is a struct that is populated via calls toView.findViewById()
. The ViewHolder struct is stored in the parent View viaView.setTag()
. When recycling a View, we can tap the ViewHolder cache:ViewHolder holder = (ViewHolder) convertView.getTag();
Now this technique is great for writing tutorials. However, for example, when you need to addOnClickListeners
, change drawables according to state changes, etc, you wind up with your Adapter class doing a huge amount of work that it should not be doing.What can we do differently? Referencing the
ContactAdapter
code from a previous question, well modify the inflated View (in this caseLinearLayout
) to cache child views in aseparate concern, the parent View itself:@Override
public View getView(int position, View convertView, ViewGroup parent) {
Contact contact = mContacts.get(position);
ContactView view = (ContactView) convertView;
if (view == null) {
// "Inflate" our contact.xml view into existence.
LayoutInflater inflater = (LayoutInflater)
mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = (LinearLayout) inflater.inflate(R.layout.contact, null);
}
// Bind contact data to appropriate child Views in the layout.
view.setModel(contact);
return view;
}
All we need to do now is edit our Contact layout and replace its root element withContactView
(shown below) instead ofLinearLayout
, say. Thats it! We now have proper separation of concerns, single purpose (less cluttered) classes, and we avoid usingView.setTag()
andView.getTag()
methods without overhead while caching child Views.publicclassContactViewextendsLinearLayout {
private Contact model;
private TextView name;
private TextView phone;
@Override
protectedvoidonFinishInflate() {
this.name = (TextView)view.findViewById(R.id.name);
this.phone = (TextView)view.findViewById(R.id.phone);
}
publicvoidsetModel(Contact model) {
this.model = model;
bindModel();
}
privatevoidbindModel() {
this.name.setText(model.name);
this.phone.setText(model.phone);
}
}
Q: What is an ANR? What causes them and how can they be avoided?ANRrefers to Androids infamousApplication Not Respondingdialog that apps can trigger when they spend too much time computing on the main thread. The main thread handles the Android UI, so doing more work there slows downresponsiveness. An ANR is therefore often a kick-in-the-pants when you arent backgrounding longer running tasks.
Examples of tasks that can cause ANRs include:
- Uploading/loading data to/from the cloud
- Saving/loading cached data to/from disk
- Sorting, filtering and searching data
With that in mind, any work to be performed that is not UI-related, especially the above types of resource-bound tasks, should be done on a background thread. Android has several ways to accomplish background work and has spawned some good 3rd party open source libraries for this as well.
Several threading options exist, each with its own advantages and disadvantages. Asynchronous computation is inherently complex and these classes and interfaces attempt to simplify the effort. Check out GooglesProcesses and Threadsguide for more detailed info.
Lets explore some of the more useful threading options in Android:
AsyncTask
AsyncTask
is a helper class that lets you spawn a short background operation. Its most commonly used to display results on the UI thread. This is usually the first class novice developers learn how to use when dealing with asychronicity, since it avoids having to setup and use threads directly.Unfortunately,
AsyncTask
has some serious gotchas. It has become somewhat of a crutch when other, more advanced, threading options ought to be used. Google has flip-flopped over the years on the runtime behavior ofAsyncTask
, from first being run serially (with otherAsyncTasks
on a single background thread), to being run in parallel, and then back to serial! This means that, if the type of concurrency (i.e., serial vs. parallel) is important to your app, you must check the running SDK version of Android before using anAsyncTask
. Developers may be better off using aHandlerThread
orExecutor
as a result.Thread
The
Thread
class is Androids most basic execution environment with its own call stack, arguments, and local variables. Every app has one main thread (for user interface) and other threads in a system thread group. You can either (a) subclassThread
and execute code within itsrun()
method or (b) pass aRunnable
to its constructor which then starts its execution by calling itsstart()
method. Once started, the thread can yield to other threads or can sleep. You cant externally stop a thread though; your only options are to interrupt it, wait for it to complete on its own, orjoin()
it.HandlerThread
Whereas Threads dont have Loopers by default, a
HandlerThread
is a Thread that has aLooperattached. The Looper provides aHandlerthat allows message passing between threads. A Handler also allows for executingRunnabletasks on its attached thread, either immediately or at a later point in time.Here is how you might instantiate a
HandlerThread
on which to post tasks to be executed:class VotingActivity {
private Runnable processVotes = new Runnable() {
publicvoidrun() {
}
};
publicvoidonCreate (Bundle savedInstanceState) {
HandlerThread handlerThread = new HandlerThread("Voting Tasks");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
// Now let's execute a Runnable task ASAP on the new thread we just created:
handler.post(new Runnable() {
publicvoidrun() {
// Accept a vote, say.
}
});
// Let's also schedule a task to execute 10 seconds in the future on the new thread:
handler.postDelayed(processVotes, 10000);
}
}
And heres how we might set up a HandlerThread to process messages sequentially:classDownloadThreadextendsHandlerThread {
publicstaticfinalint START_MSG = 0;
publicstaticfinalint STOP_MSG = 1;
DownloadThread(String name) {
super(name);
}
@Override
publicvoid handleMessage(Message msg) {
switch (msg.what) {
case START_MSG:
// Start downloading...
break;
case STOP_MSG:
// Stop downloading...
break;
default:
break;
}
}
}
And then we could spawn and use this thread as follows:classMainActivityextendsActivity {
publicvoid onCreate (Bundle savedInstanceState) {
// Set up our DownloadThread for receiving messages.
DownloadThread downloadThread = new DownloadThread("Image Downloader");
downloadThread.start();
Handler downloadHandler = new Handler(downloadThread.getLooper());
}
publicvoid startDownloading() {
downloadHandler.sendEmptyMessage(DownloadThread.START_MSG);
}
publicvoid stopDownloading() {
downloadHandler.sendEmptyMessage(DownloadThread.STOP_MSG);
}
}
ExecutorServiceandThreadPoolExecutorThreadPoolExecutor
implements theExecutorService
interface that executes submitted tasks on one of several pooled threads. Thread pooling usually improves performance when executing many tasks due to the reduced overhead of per-task invocation. If you need to execute numerous tasks asynchronously, you can spawn workers fairly easily with this mechanism. Google notes thatThreadPoolExecutor
is somewhat of a configurable kitchen sink, and developers are encouraged to use preconfigured versions such asnewCachedThreadPool()
,newFixedThreadPool()
andnewSingleThreadExecutor()
.Q: What are Loaders? When and why are they used?
In the incessant quest to offload work from the main thread, Android introduced Loaders (see
LoaderManager
andLoader
classes). Loaders simplify asynchronous loading of data in activities and fragments that usually feed adapters. They monitor their data source and deliver new results when content changes. So, instead of blocking and waiting for data to arrive (from your cloud or disk, for example), use a Loader. See GooglesLoaders Guidefor more details.Q: What is RxJava and why is it so cool?
Not every Android developer knows about this gem, so it scores major brownie points in our book when they do. Its a big innovation and perhaps the most exciting part of our post.RxJavais Netflixs open source port of MicrosoftsReactive Extensionslibrary.Reactive programmingis a programming paradigm concerned with data flow and change. Reactive programming has been around for a while, but RxJava hasnt. RxJava is super useful for writing synchronous/asynchronous, event-based observable sequences. It was designed for efficiently querying and consuming data (in motion).
RxJava is not an Android-specific library, but can make ahugeimpact on Android apps, depending on how its used. Its useful with concurrent and/or asynchronous apps that require low latency. For example, a prime use case for it would be to load data asynchronously without having to think too much about threads, handlers, or executors. You might use RxJava to load data for adapters; e.g., subscribe to data of interest on the UI thread, schedule the work to be performed on a background thread, then observe the results back on the UI thread for display.
RxJava allows you to chain data and events, and create sequences that select, filter, transpose, compose, and combine data before a final observer is notified with results. We cant possibly cover RxJava here in the depth it deserves, but we wanted to mention it because elite developers should be aware of it. You can read more about ithere.
Q: How would you cache numerous large images from the net?
If you are developing an image gallery app like Instagram or Pinterest, caching many (large) images from your server becomes critical. In the quest for optimal performance, you want to present images rapidly, so caching them to avoid reloading them from the network is essential. Since you cant cache too many large multi-megabyte images in RAM (since Android memory is volatile and is a limited resource), you really have no alternative but to cache images on disk (flash).
Rather than writing your own cache class(es), you could instead leverage and wrap
DiskLruCache
. Its an indispensable open source solution that experienced Android developers should be aware of. It can be used to cache any kind of data to a file system directory, bounded by a size that you specify.Beyond Android Proper
While Googles Android team employs many great engineers, it cant supply or anticipate every solution imaginable for new problems developers face. Thats where 3rd party open source, and even other Google teams, come in.Savvy Android developers will therefore be familiar with a number of the more valuable libraries that have emerged in recent years. Theses can be used to retrofit new Android features to older handsets, augment existing features, or introduce new functionality.
Those that extend new Android features to older handsets, however, are becoming less crucial as users have been upgrading tonewer Android versions and devices. But that said, Android developers do have alarge fragmentation of Android devices, versions and brandsto contend with, unlike iOS.
Q: What are some of the more useful Android open source libraries and how can you leverage them?
There are numerous open source libraries and add-ons available, from Google and elsewhere, that seasoned Android developers will commonly leverage. Some of the more useful ones include:
- ActionBarSherlock ActionBarSherlock is an extension of Androidssupport librarydesigned to facilitate the use of the action bar design pattern across all versions of Android with a single API. It allows you to easily develop an application with an action bar for every version of Android from 2.x and up.
- DiskLruCache As mentioned above, DiskLruCache is a powerful, yet simple, least-recently-used (LRU) caching implementation for storing dataon disk, with bounded pool size.
- EspressoAnnounced by Google in October 2013and still in developer preview, Espresso is a new UI testing framework whose goal is to make it easy for developers to write reliable UI tests. Most importantly, Espresso removes the need to think about the complexity of multi-threaded testing. Espresso is already being used by a number of Google applications (Drive, Maps, Google+, and more).
- Guava Googles Guava project contains several core libraries actively used by Google internally: collections, caching, primitives support, concurrency libraries, common annotations, string processing, I/O, and somewhat of a mishmash of very useful classes. SeeGuavas wikifor more information. Its purpose is to make Java more pleasant, improvedefensive programming, add optimizations and improve efficiency. It fills out and improves upon common classes like Collections, Math, Reflection, strings, Ranges, Hashing, I/O and more.
- NineOldAndroids NineOldAndroids makes the dramatically new and improved Android Honeycomb (3.0) animation API available to older versions back to 1.0 and forward compatible to the latest release of Android. Animation prior to Honeycomb was pretty darn limited. The new API offers much more power and flexibility to animate objects and actually reposition views with rotation, translation, alpha and scale primitives, for example. The library provides a wrapper that works across all Android versions.
- Protocol Buffers Googles Protocol Buffers is a language-neutral, platform-neutral, extensible mechanism for serializing structured data, that provides a viable alternative to JSON or XML. Its an efficient way to transport object data, for instance in its original binary format without needing to (un)marshal. Data transported is smaller, faster, simplerin Googles words.
- RxJava As mentioned above, RxJava is a Reactive Extension that lets you create asynchronous, event-based code using observable sequences, which can be invaluable in many circumstances.
- Volley Volley is a relatively recent Google libraryintroduced at Google I/O May 2013that makes networking for Android apps faster and easier. Oddly, Google hasnt yet published its own tutorial or documentation other than the source, making some developers skeptical or wary of it, but several have written tutorials such asthisandthis. Highlights include a view that automatically loads images, HTTP request queuing with prioritization, and automatic Android-version-specific selection of the best HTTP library.
Debugging and Tuning
Experienced developers rely on great tools to help them build great software, especially for testing and optimization purposes. Android was a bit slow at first to offer them, but its tool chest has finally filled out. Android offers runtime detection of problems, attached classes that can help detect problems. There are also external tools likeDDMSto view memory usage, find leaks, view thread usage, observe view hierarchies and more.Q: What is the Dont Keep Activities developer option and why is it useful?
Google offers a wide array of runtimedebugging optionsfor devices that can be activated under Settings > Developer options. One of the more useful ones isDont keep activitieswhich immediately destroys an activity when the user leaves it. Its useful for testing activity save and restore (i.e., the
onSaveInstanceState(Bundle)
andonCreate(android.os.Bundle)
code path), which would otherwise be difficult to trigger. It can also uncover other symmetry problems with your activitys life cycle, such as properly opening and closing resources betweenonResume()
andonPause()
callbacks, for instance.Q: What is StrictMode and why is it useful?
In the never-ending quest to improve app responsiveness and keep the UI running smoothly,StrictModeis a valuable Android tool to help detect accidental disk and network access on the main thread (or any thread for that matter).
In the development version of your app (never leave StrictMode enabled in a released app!), you tell Android what problems youre interested in finding and define the penalties to be applied (i.e., what to do) if theyre detected. While not every problem that it finds necessarily needs to be fixed, nor can you be certain that it will find every problem, it provides a highly useful window into your apps imperfections (if any).
Heres how you might enable StrictMode in your Applications onCreate method:
public void onCreate() {
// Only enable when developing your app!
if (DEVELOPER_MODE) {
// Tell Android what thread issues you want to detect and what to do when found.
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork() // or use .detectAll() for all detectable problems
.penaltyLog()
.build());
// Tell Android what VM issues you want to detect and what to do when found.
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects()
.penaltyLog() // Log the problem
.penaltyDeath() // Then kill the app
.build());
}
super.onCreate();
}
Q: What is the lint tool? What does it do and how would you use it?Lintis an Android tool that scans your project and generates a detailed report containing errors and warnings in your code and resource files that you might consider fixing. Its not perfect, and sometimes it report false positives (that top developers know to take with a grain of salt), but its still a useful tool. For example, it can:
- Detect unused files and resources to reduce app bloat
- Tell you where you should be recycling
TypedArrays
after use - Identify where you might be overdrawing backgrounds of overlaying views
- plus many other issues
Wrap Up
Weve only just scratched the surface of Android app development, highlighting some of the more important aspects and nuances of the platform, as well as tools to leverage.Given Androids complexity, it can take a developer years to become truly proficient. Android offers enormous potential given its massive market penetration today and its rich framework. Finding Android Jedi masters is a challenge given their demand and the time it takes to become one. We hope you find the questions presented in this post to be helpful toward that goal as you search for elite, cream-of-the-crop developers.