Three Basic Rules to apply while developing apps for Android

Its 2013 and android has been ruling the market for a while, so a lot of developers are attracted towards android app development. If you know the programming language then you can create a working app. But making an app that just works does not make you a good developer. Apps that just works usually causes ANRs. That is not a very good scenario for the users and they end up giving you one star rating with review “Fuck you asshole“. Well they don’t really say that but lets face it, they will search for better alternative in the play store if your app keeps getting them ANR.

So we have to focus on developing apps with better performance. The better performance of the apps depends on following things.

  1. Screen responsive
  2. Interactive
  3. Handy
  4. Supports stone-age phones(too).
  5. Android look and feel

So those are the things we have to focus while developing for android. Then what are the rules? Well lets discuss them.

1. Always use background threads for processes that takes time

 

blocking-the-main-thread.png

All users gets pissed off when above dialog appears on the screen while using your app. It simply means that the users action has a delayed feedback, and your app will stop responding. This leads to frustration and frustrated user end up giving above reviews.

So whats the problem. The main problem is that you are blocking the main thread with a time consuming process. Some examples of such processes are

  • Loading images from server
  • Reading or writing data to your sdcard
  • Database querying
  • Network calling
  • Bitmap loading

Solution : So remember to push these processes in the background thread. You can use AsyncTask for such activities.

Update : I have written an article on how to use asynctask. Check it out here.

2. Display bitmaps efficiently

A picture is worth a thousand word ” , that’s a very nice saying. But in terms of engineering there is also a saying “Even a small picture is worth thousand fucking kilobytes”. Well there is not such saying, actually I made that up. But its actually is true. Lets break it down. We use bitmap images to make our apps content nice and as per above saying it do speaks a thousand words. But they are memory eaters.

 

meme.jpg

Yeah that’s pretty much the situation. We have some proof for that. Lets take a 1000×1000 size image. Its pretty small right? We have to load this image into memory before displaying it. The total memory needed to display an image is

memoryNeeded = 4 * imgHeight * imgWidth bytes

So the total memory needed to display above image is 4*1000*1000. Which is 4 million bytes or nearly 4MB. So we have to allocate 4MB just for a small single image. So lets take a simple xolo a500s. Its screen resolution is 480 * 800. If we try to show above image in this mobile then we shouldnt allocate more than 4*480*800 = 1.5MB  of memory. So how do we do it?

There are couple of ways to do that. Lets take a look into them.

Load bitmap images in background thread

Bitmapfactory.decode method should not be executed on the main UI thread if the source data is read from disk or a network location (or really any source other than memory). The time this data takes to load is unpredictable and depends on a variety of factors (speed of reading from disk or network, size of image, power of CPU, etc.). If one of these tasks blocks the UI thread, the system flags your application as non-responsive and the user has the option of closing it.

Load a Scaled Down Version into Memory

Sometimes we don’t need all the resolution image is offering us. So we can just scale them down. Scaling an image down will help to cut off a lot of memory. If we scaled down 1000*1000 image to 500*500, we can reduce the memory to be allocated from 4MB to just 1MB. That’s hell lot of relief for the memory.

Caching bitmap while using them on Listview, GridView or Viewpager

In components like ListView, GridView and Viewpager you have to load a larger set of images into memory and most of them are not even displayed in the screen at a time. Memory usage is kept down with components like this by recycling the child views as they move off-screen. The garbage collector also frees up your loaded bitmaps, assuming you don’t keep any long lived references. This is all good and well, but in order to keep a fluid and fast-loading UI you want to avoid continually processing these images each time they come back on-screen. A memory and disk cache can often help here, allowing components to quickly reload processed images.

3. Consider developing for all devices

There are thousands of android devices out there on the market. They differ on the screen size, resolution, memory and storage capacity. If you focus on building your app for a single mobile then the chances are it wont look good on every devices. Here are some tips to consider in this situation

Maintain Density-Independance

Your application achieves “density independence” when it preserves the physical size (from the user’s point of view) of user interface elements when displayed on screens with different densities. Maintaining density independence is important because, without it, a UI element (such as a button) appears physically larger on a low-density screen and smaller on a high-density screen. Such density-related size changes can cause problems in your application layout and usability. Lets see what happens when application when it does not provide density independence.

 

density-test-bad.png

Also lets see happens when application when it provides density independence.

 

density-test-good.png

That is a lot difference. The Android system helps your application achieve density independence in two ways:

  • The system scales dp units as appropriate for the current screen density
  • The system scales drawable resources to the appropriate size, based on the current screen density, if necessary

In figure 2, the text view and bitmap drawable have dimensions specified in pixels (px units), so the views are physically larger on a low-density screen and smaller on a high-density screen. This is because although the actual screen sizes may be the same, the high-density screen has more pixels per inch (the same amount of pixels fit in a smaller area). In figure 3, the layout dimensions are specified in density-independent pixels (dpunits). Because the baseline for density-independent pixels is a medium-density screen, the device with a medium-density screen looks the same as it does in figure 2. For the low-density and high-density screens, however, the system scales the density-independent pixel values down and up, respectively, to fit the screen as appropriate.

In most cases, you can ensure density independence in your application simply by specifying all layout dimension values in density-independent pixels (dp units) or with "wrap_content", as appropriate. The system then scales bitmap drawables as appropriate in order to display at the appropriate size, based on the appropriate scaling factor for the current screen’s density.

However, bitmap scaling can result in blurry or pixelated bitmaps, which you might notice in the above screenshots. To avoid these artifacts, you should provide alternative bitmap resources for different densities. For example, you should provide higher-resolution bitmaps for high-density screens and the system will use those instead of re-sizing the bitmap designed for medium-density screens. That’s the topic of my new tip.

Support Multiple Screens

There are couple of ways to do that,  which are:

Provide different layouts for different screen sizes

By default, Android resizes your application layout to fit the current device screen. In most cases, this works fine. In other cases, your UI might not look as good and might need adjustments for different screen sizes. For example, on a larger screen, you might want to adjust the position and size of some elements to take advantage of the additional screen space, or on a smaller screen, you might need to adjust sizes so that everything can fit on the screen.

The configuration qualifiers you can use to provide size-specific resources are small, normal, large, andxlarge. For example, layouts for an extra-large screen should go in layout-xlarge/.

Beginning with Android 3.2 (API level 13), the above size groups are deprecated and you should instead use the sw<N>dp configuration qualifier to define the smallest available width required by your layout resources. For example, if your multi-pane tablet layout requires at least 600dp of screen width, you should place it inlayout-sw600dp/.

Provide different bitmap drawables for different screen densities

By default, Android scales your bitmap drawables (.png, .jpg, and .gif files) and Nine-Patch drawables (.9.png files) so that they render at the appropriate physical size on each device. For example, if your application provides bitmap drawables only for the baseline, medium screen density (mdpi), then the system scales them up when on a high-density screen, and scales them down when on a low-density screen. This scaling can cause artifacts in the bitmaps. To ensure your bitmaps look their best, you should include alternative versions at different resolutions for different screen densities.

Use 9-patch drawable

The main reason to use 9-patch drawable is for scaling purpose. They can scale up or down smoothly without distorting the pixels. It automatically resize to accommodate the contents of the view and the size of the screen.

nine_patch_demo.png

 

WARPPING UP!

Following these rules might take some extra time but it is totally worth. If the apps performance is better then the user might stick to your application for a long time.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s