Chapter 10

Comparing Android and Windows Phone Performance Problems

In this chapter, you will learn the following:

  • General knowledge and differences between the three platforms and three programming languages used in Smartphone development.
  • How to revise many important aspects of application performance that you learned for iOS to apply to Android and Windows Phone, such as:
    • How to benchmark applications for Android and Windows Phone.
    • How to optimize the scrolling performance.
    • The differences in caching and data storage.
    • A brief lesson in data structure and algorithms for the three platforms.
    • A brief lesson in multithreading on the three platforms. Android is different than the other two platforms.
    • Lessons about memory constraints.
    • The different ways these platforms handle multitasking.
    • How to integrate C/C++ code into your Android application.

This chapter will provide a general vision of the three main important Smartphone platforms in the near future: iPhone, Android, and Windows Phone. They are growing up and making huge innovations to keep a competitive advantage against their competitors. For some basic and trivial applications, you won't care to optimize performance for each platform because it takes so much time and effort; you can write a cross-platform application to save time.

Unsurprisingly, cross platform release has a significant delay of up to several weeks or months after the main SDK is released. It also lacks some of the detailed features compared to the main APIs. Therefore, to succeed in any of these three platform markets, you will need to use the main language and features to optimize performance and take advantage of advanced features and APIs for that platform.

I will provide an overview of the main difficulties regarding Android and Windows Phone performance. The approach is simplified by going through the chapters of this book: instruments, the emulator, list view, caching, storage, data structure and algorithms, multithreading, multitasking, memory management, and native C/C++ programming support. For reasons of space, I can't cover all details of each platform nor conjecture which platform is the best. After reading this chapter, you will be aware of the most important difficulties for each platform so that switching and learning a new platform will be easy.

General Knowledge

iPhone uses Objective-C as a main programming language for iOS development. It has no garbage collector but ARC to help with memory management. Only three devices use iOS: iPod Touch, iPhone, and iPad with two different screen resolutions.

Android uses Java as a main programming language and it provides garbage collection for easy memory management. Android has many screen sizes and device hardware specifications. There are some devices with core-duo chips and there are some really weak (much slower processor and limited memory) devices.

Windows Phone uses C# as a main programming language and Silverlight as a user interface framework. C# has garbage collection. There are many devices that support Windows Phone but all must meet the necessary hardware requirements.

Benchmarking on Emulator and Devices

In iOS, as you learned in Chapter 2, the simulator is far faster than the device so there are cases where you need to use the device to test that things work well. The architectures of the simulator and the devices of iOS, Android, and Windows Phone are quite different so there are different approaches to running benchmark tests on each of the platform.

Emulator and Devices

The Android emulator (Figure 10–1) is really slow. You can use it as the lowest benchmark for performance testing. Android also has so many different devices, so for performance, it is hard to keep all Android users happy. You may need to test on different devices to see the range of performance results.

images

Figure 10–1. Android emulator

The Windows Phone emulator (Figure 10–2) runs at a normal performance, so it's is almost the same as a real device. If you want a fast simulator so you can run a quick test in the same way you develop iOS application, it's possible to improve the performance of the emulator; you can find the information easily on the Internet.

images

Figure 10–2. Windows Phone emulator

The iPhone simulator runs extremely fast compared to the real device, as mentioned in Chapter 2, so it's hard to detect any performance issues in it.

Benchmarking

It is important to know which tools are available to you when you need to run benchmarking. Android provides a limited set of tools while Windows Phone provides a wider range of tools that help you to find the performance problem. Many of these tools cover the same functionality as tools supplied by the iOS; they support benchmarking of memory, CPU usage, and user interface processing.

Android

Eclipse for Android doesn't provide a complete list of instrument tools as Xcode does for iPhone. It provides four main instrument tools that you can use to track your performance: thread, heap, object allocation, and file access. You can combine these tools with logging (using Debug.trace()) to measure the general performance of your application.

Although Android provides garbage collection, it has its disadvantages. When the garbage collection runs, it stops your application. This will make your UI cease responding for a couple of milliseconds, or at least not render enough frames (a good rendering frame rate should be around 16-30ms/frame).

Figure 10–3 and 10–4 shows the heap and allocation tracker for Android. You can use these tools to see in what classes or methods you create the most objects.

images

Figure 10–3. Heap instrument

images

Figure 10–4. Allocation instrument

Windows Phone

Windows Phone offers a much better performance profiling tool. Figure 10–5 shows the result of running the Windows Phone profiling tool and getting the data back.

images

Figure 10–5. Allocation instrument

The performance tool supports many different metrics for performance benchmarking: frame rate, CPU usage, memory usage, image loads and garbage collection events. This helps you locate the performance bottleneck so you can solve it more easily.

ListView Performance

All ListViews (or TableViews) in iOS, Android, and Windows Phone share similar performance issues. You always need to return data back to the list as soon as possible; otherwise, user will see a lot of jerkiness when scrolling down. Loading images will need to be asynchronous so user can scroll the list smoothly and see data first. Whenever the image is loaded, it will be displayed in the list later.

There are some common issues with view rendering for all three platforms:

  • You should always use opaque views whenever possible.
  • You should not use a complicated, nested list view structure because it starts to display slowly.

There are specific issues for each platform when it comes to this ListView scrolling issue. To have a customized ListView, Android and Windows Phone use a different approach to displaying data into the ListView. The way Android does it is similar to iPhone where you return data and view only if necessary. Windows Phone uses an automatic binding mechanism to bind data into the view. The Windows Phone way is easier to implement for developers but it causes more performance issues than the Android way.

With Windows Phone, when you have a big array of objects, you will soon have a problem with memory and performance because the operating system can't store more objects into the memory and fetch them out to bind with the ListView. This is the main difference between ListView in iPhone, Android, and Windows Phone. In the first two platforms, you only need to decide the size of the list; while scrolling, you can get data to display. Memory should not be an issue with iOS TableView when you can discard the unused objects in the array and only store necessary objects. I will explain briefly how both platforms are implemented and how to solve the problems with both platforms.

Android

In Android, you can map your data with the default layout without any difficulty.

String [] cities= new String[] {"Melbourne", "Victoria", "Adealide"};
this.setListAdapter(new ArrayAdapter<String>(this, R.layout.list_item, cities);

However, if you need to come up with a more complex layout, you can use your own adapter to map the data with the view.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content" android:layout_height="wrap_content">
        <ImageView android:id="@+id/icon" android:layout_height="wrap_content"
                android:src="@drawable/icon" android:layout_width="22px">
        </ImageView>
        <TextView android:text="@+id/TextView01" android:layout_width="wrap_content"
                android:layout_height="wrap_content" android:id="@+id/label"
                android:textSize="30px"></TextView>
</LinearLayout>

My sample application includes an image view in the left and a text view in the right, as the default cell in UITableView of iOS.

public class MySimpleArrayAdapter extends ArrayAdapter<String> {
   @Override
      public View getView(int position, View convertView, ViewGroup parent) {
       LayoutInflater inflater = context.getLayoutInflater();
        View rowView = inflater.inflate(R.layout.rowlayout, null, true);

        TextView textView = (TextView) rowView.findViewById(R.id.label);
        ImageView imageView = (ImageView) rowView.findViewById(R.id.icon);
        textView.setText(names[position]);

        // Change the icon for Windows and iPhone
       imageView.setImageResource(R.drawable.ok);

     return rowView;
   }
}

Creating Java objects (especially View objects) consumes time and CPU, so Android reuses rows that are not displayed any more. For example, if a row disappears off the top or the bottom of the view, Android gives this view back to the Adapter method as a parameter convertView. To use this in your method, you have to check first if convertView is not null, then you can use it to display the next data item.

Another important optimization to note: since the method findViewByID() is an expensive operation, you should avoid using it whenever possible. Instead, you should use setTag() and getTag() method to retrieve the necessary view.

Taking into account these facts, you can rewrite the previous source code as the following:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
   // ViewHolder will buffer the assess to the individual fields of the row
   // layout

   ViewHolder holder;
   // Recycle existing view if passed as parameter
   // This will save memory and time on Android
   // This only works if the base layout for all classes are the same
   View rowView = convertView;
   if (rowView == null) {
       LayoutInflater inflater = context.getLayoutInflater();
       rowView = inflater.inflate(R.layout.rowlayout, null, true);
       holder = new ViewHolder();

       // Only findViewByID() at the first time, then use setTag()
       holder.textView = (TextView) rowView.findViewById(R.id.label);
       holder.imageView = (ImageView) rowView.findViewById(R.id.icon);

       rowView.setTag(holder);

    } else {
       holder = (ViewHolder) rowView.getTag();
    }

    holder.textView.setText(names[position]);

    // Change the icon for Windows and iPhone
    String s = names[position];
    holder.imageView.setImageResource(R.drawable.ok);

     return rowView;
}

As you can see, convertView is reused so if it's not null, you can use it as-is. You can also see that I created a wrapper to contain the text view and the image view. You can contain as many views inside the view holder as you want and name the parameter to be anything. You can imagine the view holder as a map that has the attributes as the keys and put other views as values.

Windows Phone

Windows Phones use data binding in a different way, which creates a huge performance and memory problem. In Windows Phone, the UI is still reused, just as in Android and iOS; however, the data is bound directly. This means that if you need to display 1,000 items into the ListView (called ListBox in Windows Phone), all 1,000 items need to be created and loaded into the memory. This works fine for a Silverlight desktop application. But in Windows Phone the memory is more limited, so the phone can't afford to load all 1,000 items.

The main issue with the current Windows Phone binding is that it binds to IEnumerables. This can be solved using another data bind that implements IList, which already supports Count and IndexOf method.

  public class MyDataSource : IList
  {
    const int MAX_ITEMS = 1000;

    public int Count
    {
      get { return MAX_ITEMS; }
    }

    public int IndexOf(object value)
    {
      if (value == null)
      {
        Debug.WriteLine("IndexOf(null)");
        return -1;
      }

      DataItem item = (DataItem)value;
      return item.Index;
    }

    public object this[int index]
    {
      get
      {
        DataItem itemToReturn = new DataItem { Index = index, Text = "NEW ITEM" };
        return itemToReturn;
      }
      set
      {
        throw new NotImplementedException();
      }
    }


    // None of the other IList stuff is necessary for data virtualization
    #region Unimplemented stuff
    // Fill in non-implemented methods here
    #endregion
  }

  public class DataItem
  {
    public int Index { get; internal set; }
    public string Text { get; set; }
    public override string ToString()
    {
      return Text + " [" + Index + "]";
    }
  }

As an exercise, you should integrate this code with the main ListBox code that you use on the UI.

Data Caching

All algorithms and terms that you learned in Chapter 3 for iOS programming can be applied for Android and Windows Phone without any problems. What you should learn are techniques related directly to Windows Phone and Android, such as where to store your cache, how often you should cache, and in what format you should cache your data.

The memory caching part should be no different from iOS either because the hardware specifications for the three platforms are not different. You can have the same memory caching algorithms as the iOS approach. I will focus on how to utilize the file storage to get the best performance.

Android

There are many places where you can store the cache data.

  • Shared preferences: This is exactly the same as NSUserDefaults. You can store primitive data here. It is usually used for settings storage or lightweight storage.
  • Internal storage: You can store private data in device's storage. It's actually a file area inside the internal storage. Other applications can't access this storage.
  • External storage: In most Android phones, users can have more storage by having a removable storage media (such as an SD card). Files saved here are public to the world and can be modified even by the user. The user can enable USB mass storage to transfer files to their computers.
  • SQLite: This is a database, and you access it using Java and SQL as normal without any much difference. That's why if you choose to store your data in SQLite Database in iPhone, you can actually reuse it here.
Shared Preferences

The SharedPreferences class is stored into two layers of structure. The first layer allows you to store the name of the preferences that you want to store, such as “Network Preferences” or “Setting Preferences.” The second layer is the key-value storage layer where you actually store your primitive data.

SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
boolean silent = settings.getBoolean("silentMode", false);
Internal Storage

Files are stored here for longer term and are private to only your application. You can store a file in this storage area by using the following code:

String FILENAME = "hello_file";
String string = "hello world!";

FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(string.getBytes());
fos.close();

This code writes the string into the file and then saves that file.

To save data in a cache folder that can be deleted usually by the operating system without letting you know, use the path inside getCacheDir().

NOTE: To save your files into the application, similar to the way the application bundle does in iOS, you can save into the project directory res/raw/. You can read the file by using openRawResource() but you can't write into these files.

External Storage

This is removable storage so you will need to check if that storage media is attached to the current device or not.

String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
  // YOU CAN READ AND WRITE DATA
} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
  // YOU CAN ONLY READ
} else {
  // YOU CAN NEITHER READ OR WRITE
}

This media has a much bigger storage capacity so you can save more data in it. However, user can mistakenly delete data, or not attach the media to the device. These files will also be deleted when your application is uninstalled. If you don't want that to happen or you want to share the data with other applications, you can save them into directories at the root by calling getExternalStoragePublicDirectory(). You also have a specific cache directory in the external media where you should save unimportant cache data: getExternalCacheDir().

SQLite Database

Storing in a database can lead to complex problems but it can also help solve many performance issues. There are many techniques to help you improve the performance of database access, such as better indexing, partitioning database, and unique key. I won't cover database optimization in depth, as it is a very large and specialized topic. Suffice it to say that SQLite is broadly similar to any other SQL database.

Windows Phone

Microsoft released a new update to Windows Phone that includes a local database. If you start building a new application and want to use a database, you can now do so. Otherwise, if your application is using some other storage mechanism intensively, you may choose to optimize it rather than rebuilding the whole database.

In Windows Phone, there are also four main approaches to storing files.

  • IsolatedStorageSettings: Key value storage, exactly the same as NSUserDefaults.
    IsolatedStorageSettings appSettings = IsolatedStorageSettings.ApplicationSettings;
    appSettings.Add("email", "[email protected]");
    var myEmail = (string)appSettings["email"];
  • IsolatedStorageFile: Used in Windows Phone to store files into the file system. It doesn't have a default directory for specific purpose like Cache or Public. You need to create your own directory to handle the storage process.
  • XML storage: For the old applications, you may need to choose the XML as your main storage mechanism if you don't have database support.
  • Local database: The new release with Mango will have local database support for Windows Phone. Many problems with local storage performance will be solved with this new release.
IsolatedStorageFile

File storage in Windows Phone is simple; you have the whole application directory to do whatever you want. The operating system will not take care of anything like automatically deleting or restricting the storage limit on this directory.

IsolatedStorageFile myStore = IsolatedStorageFile.GetUserStoreForApplication();
myStore.CreateDirectory("Cache");

// Specify the file path and options.
using (var isoFileStream = new IsolatedStorageFileStream("Text1.txt", FileMode.OpenOrCreate, myStore))
{
  //Write the data
  using (var isoFileWriter = new StreamWriter(isoFileStream))
  {
    isoFileWriter.WriteLine(txtWrite.Text);
  }
}

To read the file, use this code:

using (var isoFileStream = new IsolatedStorageFileStream("Cache\Text1.txt ", FileMode.Open, myStore))
{
  // Read the data.
  using (var isoFileReader = new StreamReader(isoFileStream))
  {
    txtRead.Text = isoFileReader.ReadLine();
  }
}

You need to specify the read/write permission that you want to read, write, or append data in.

XML Storage

Using XML to store and then LINQ XML to read/write to the XML format is a painful process and can significantly hurt the performance of your Windows Phone application.

The main performance issue with storage using LINQ for XML is that you need to load or save the whole XML every time you need to modify or read your data. This is because LINQ uses DOM to access the data. It also causes memory issues when you store the whole big XML file into the memory to access it. If you have a small XML file, it's not any trouble.

There are two ways developers work around this XML issue.

  • You have a main file containing the main structure of all of your data. Then you have several smaller files to store data about each main data item. For example, to have an RSS reader, you can store all the channel information into the main file, then have a separate file for each channel.
  • You only cache the most recent data. Any data that is older than 10 days may be deleted. This will reduce the amount of data you have in your local XML file and reduce the complexity of your work. The drawback is that you need to redownload the old data if necessary.
Database Support

With the new Mango release, Windows Phone will have support for local database storage. You will soon have all the powers of indexing, partitioning, key, and random access to the database. With this new release, you should use LINQ to SQL to have good code reuse, because LINQ to SQL and LINQ to XML share many codebase items.

Data Structure and Algorithms

C#, Java, and Objective-C have similar built-in data structures to support the three main types of object collections: set, array, and map. Table 10–1 provides a summary of these types of collections, their subtype, and how you can implement one yourself.

images

There are some less important data structures such as stack and queue but you can always implement them yourself based on what you learned in Chapter 5.

For XML parser, Android supports both SAX and DOM XML parser by default so you won't need to add another library just to support it. For C# on Windows Phone, you will need to use LINQ over XML to handle the work in most cases because it provides much better code maintenance and is actually faster than DOM. In case of a really big XML files, consider using XmlReader.

Multithreading

C# and Java are powerful programming languages when it comes to managing multithreading. Similar to iOS multithreading, the jobs for updating the UI will need to be done on the UI thread; other long running operations need to be done in the background thread.

The thread locking mechanisms for the three platforms are similar, based on the notification mechanism. There are, though, some important differences in the way each platform implements and sets specific rules for its multithreading mechanism.

Android

Java has a multithreading mechanism but Android prefers to use its own multithreading management mechanism. In Android, there is a really strict rule for the UI thread. If the UI thread is blocked for more than a few seconds (5 seconds currently), the user is presented with the well-known pop up saying “Application not responding”. After that, your application is forced to close.

In Java, you can create a thread simply by subclassing the Thread class or implementing the Runnable interface. One of the simplest ways is to use an anonymous method.

 new Thread(new Runnable() {
   public void run() {
     // Your background code.
   }
 }).start();

If you create new class, which extends the Thread class, you can simply call newThread().start. If class B implements the Runnable interface, then you can have newThread(B).start.

There are several ways that you can update the UI in the UI thread, similar to the way the following iOS method is called:

[obj performSelectorOnMainThread:mySelector withObject:nil waitUntilDone:YES];

Android offers this list of ways you can update the UI thread:

  • Activity.runOnUiThread(Runnable)
  • View.post(Runnable)
  • View.postDelayed(Runnable, long)
  • Handler

For example, you can use the following code to get the image in the background thread and then update the UI thread:

public void loadImage() {
 new Thread(new Runnable() {
   public void run() {
     final Bitmap bitmapImage = loadBitmapImage();
     myImageView.post(new Runnable() {
       public void run() {
         myImageView.setImageBitmap(bitmapImage);
       }
     });
   }
 }).start();
}

The code can become more complex if inside your thread and inside the UI update code you do a lot of processing. You can also create a class that implements the Runnable interface and calls the run method of this class. Android also offers a simpler way to handle a complex thread processing logic: the AsyncTask class. It's a better thread management structure to handle your threading issues.

private class myAsyncTask extends AsyncTask<X, Y, Z>
  protected void onPreExecute(){
  }

  protected Z doInBackground(X...x){
  }

  protected void onProgressUpdate(Y y){
  }

  protected void onPostExecute(Z z){
  }
}
  • onPreExecute: This method is called before your background thread is executed.
  • doInBackground: The main method runs in background thread.
  • onProgressUpdate: When you need to update the view in the main thread with the current progress of the background thread.
  • onPostExecute: When your background thread finishes, this method is called on the UI thread, and you can update your UI with the result of the background thread.

As you can see from the class structure, you can define three generic type parameters: X, Y and Z.

  • X: The parameter type that you pass into the background thread. You can pass an array of objects with type X into the background task.
  • Y: The parameter type you are going to enter in the onProgressUpdate method. This method is called when you call publishProgress(Y) inside the doInBackground method. For example, you want to show the progress of the operation by a progress bar.
  • Z: The parameter type of the result from the operations you have done in the background process.

The image download sample source code shown previously can be rewritten as

public void loadImage() {
 new DownloadImageTask().execute("http://example.com/image.png");
}

private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
    protected void onPreExecute(){
    }


    protected Bitmap doInBackground(String... urls) {
        return loadImageFromNetwork(urls[0]);
    }

    protected void onPostExecute(Bitmap result) {
        mImageView.setImageBitmap(result);
    }
}

For a locking thread to avoid thread race condition and avoid deadlock, you can use a similar mechanism as iOS programming with the wait, notify and notifyAll methods. Here are similarities between these methods and NSCondition methods you learned in Chapter 6:

  • wait: Similar to [condition lock], it locks the method or block of code.
  • notify and notifyAll: Similar to [condition signal] and [condition unlock], it unlocks the method and tells the other threads to come in. The difference between notify and notifyAll is the first one will randomly pick a thread to let it run while notifyAll will let all threads run.

Windows Phone

You start a new thread in Windows Phone with

public void loadImageFromNetwork()
{
}
Thread t = new Thread (loadImageFromNetwork);
t.Start();

As normal, you will need to update your user interface in the UI thread. This can be done by calling

Dispatcher.BeginInvoke(() => UpdateUI());

I used a normal lambda expression. If you don't understand it, just leave it like the sample source code and put your method call in.

To avoid race condition and deadlock, you will need to use locking mechanism, the same way as in Java:

obj.notify() => Monitor.Pulse(obj)
obj.notifyAll() => Monitor.PulseAll(obj)
obj.wait() =>  Monitor.Wait(obj)
Asynchronous Download

In Windows Phone, because of the API restriction, you can only use an asynchronous request to download the data from the Internet. You will need to use WebClient or HttpWebRequest to make the request to the server. The following is code to initiate a new web request and receive back data:

WebClient webClient = new WebClient();
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(wc_OpenReadCompleted);
webClient.OpenReadAsync(new Uri(arbitraryImageUriThatKeepsChanging), webClient);

void wc_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
  if (e.Error == null && !e.Cancelled)
 {
     try
     {
        BitmapImage image = new BitmapImage();
        image.SetSource(e.Result);
        imgContent.Source = image;
     }
     catch (Exception ex)
     {
         //Exception handle appropriately for your app
     }
 }
}

Memory Management

Android and Windows Phone have their own garbage collectors, so in many cases, you won't need to worry too much about memory management. Because the general approach to garbage collection of Android and Windows Phone look similar to each other, I will illustrate the general point of garbage collection and then I will go into some specific details and cases for Android.

For limited environments like Smartphones (especially the Android phones that only have 32MB of memory), it's your job to make sure that you use the least memory every time. If you don't need to cache an image in memory, release that image. You can release an image by setting the object to null, and the garbage collector will do its job.

You will only have memory leak if you set a reference to an object for the whole application lifecycle without setting it to null at the appropriate time. Unless your view has a long lifecycle and contains too many objects when it's running, you shouldn't worry.

There are specific issues related to each platform that I will discuss in detail in the following sections.

Android

Android has specific platform features that iOS and Windows Phone don't really have: multitasking and TabView. Multitasking in Android is different than multitasking in iOS. Android applications can start services, and these services run in background forever until some of them get destroyed.

Context Activity Leak

In Android, you have a context that is shared between different activities, and this context stores data and the whole view hierarchy inside. The problem is that this context is passed around objects and methods that need to have it, like when you initiated a text view.

TextView myTextView = new TextView(myContext);

So, if the myTextView leaks, the whole context activity is leaky. Now, consider a case where you need to maintain your background image when the phone changes orientation. When your application changes orientation, it destroys the activity and all the data inside that activity, including your background image. So, the best practice is to keep the image static.

private static Drawable sBackground;

@Override
protected void onCreate(Bundle state) {
  super.onCreate(state);

  TextView label = new TextView(myContext);
  label.setText("Leaks are bad");

  if (sBackground == null) {
    sBackground = getDrawable(R.drawable.large_bitmap);
  }
  label.setBackgroundDrawable(sBackground);

  setContentView(label);
}

Now you can see that the background has a reference to the label, and the label has a reference to the context myContext. And because the background image is static, it will never be released, so you will simply leak the whole context and the old view hierarchy.

Memory in Multitasking

In Android, because all applications can run in background at any time, memory becomes even more restricted. If your application uses too much memory, it will force the operating system to kill other applications to get back memory. This is why good memory management and usage can become significant for you to handle properly.

TabView

There is a similarity between Android and iPhone when it comes to TabView. If you're using a TabView, all of your views in all tabs are loaded into memory, even if they don't get displayed. This usually causes a huge memory issue for all kinds of applications when views are the most memory consuming elements. Think twice before you go for a TabView.

Windows Phone

Windows Phone doesn't have a multitasking feature so your application can utilize all possible memory and run with high performance. There are, however, some view hierarchy issues that can affect your memory if you don't use them properly.

Panorama and Pivot

There are two main important view hierarchies in Windows Phone: Pivot and Panorama. You can use other ways to create a Windows Phone application with a normal view. Pivot and Panorama are similar to each other although the UI concepts are different. Pivot is used more for applications with similar views but for different purpose, for example, weather in different places (London, Paris, New York, California); see Figure 10–6. Panorama is used more for applications that need to display a large picture of the same thing, as shown in Figure 10–7.

images

Figure 10–6. Pivot application

images

Figure 10–7. Panorama application

There is a big performance problem with panorama applications: you need to load the whole view into the memory even without displaying it. The longer the view is, the more you need to load and it will soon put your application out of memory. This is certainly a major consideration. If you use a panorama view, you should only use a short view; don't load too much data or subviews.

Multitasking

Multitasking is always an issue with all Smartphone platforms because the battery can drain quickly. As discussed in Chapter 8, iOS multitasking is not exactly multitasking. It's a combination of fast application switching and some limited background services.

Android offers multitasking via a different approach, allowing more time and freedom for applications to run and do computation in background. Windows Phone doesn't allow your applications to run in background yet; you may need to wait until the Mango release for that.

Android

In Android, to create a background process, you need to use the Service class. To clarify, using Service doesn't mean a separate thread or a separate process. When you call this service, it will tell the system that your application has something to do in the background. You can also expose some other services to other applications.

To start a new Service, you need to extend the Service class and implement the necessary methods.

public class MyService extends Service {
  private static final String TAG = "MyService";

  @Override
    public IBinder onBind(Intent intent) {
    return null;
    }

    @Override
    public void onCreate() {
      Log.d(TAG, "onCreate");
    }

    @Override
    public void onDestroy() {
      Log.d(TAG, "onDestroy");

    }

    @Override
    public void onStart(Intent intent, int startid) {
      Log.d(TAG, "onStart");
    }
  }

  public void onClick(View src) {
    switch (src.getId()) {
      case R.id.buttonStart:
        startService(new Intent(this, MyService.class));
        break;
      case R.id.buttonStop:
        stopService(new Intent(this, MyService.class));
        break;
  }
}

There are four main methods that you need to know, as shown in the sample source code. When the new service is started by method startService(new Intent(this, MyService.class)), the method onCreate() will be called, and then onStart() will be called. When a service is stopped by stopService(new Intent(this, MyService.class));, the method onDestroy() will be called.

You will need to put your main logic code in the onStart() method and let the background process run from here.

Support of C/C++ Programming

You can write C/C++ code inside your Android applications but that requires you to know about JNI (Java Native Interface) and how to interact with NDK (Native Development Kit). The way you interact is similar to the way you use Objective-C code to interact with C/C++ code. You may need to be careful about memory management problems and should not mess things up too much. Using Java will allow you to have garbage collection while using C/C++ requires you to manage memory manually.

Windows Phone, though, doesn't support any programming languages except C#. If you want to develop games, you will need to use XNA with C/C++. Adding and calling C/C++ code from Java using NDK is really easy; just write a little wrapper code. You need to have a wrapper method to convert between C and Java.

#include <jni.h>
#include <string.h>
#include <android/log.h>

void Java_com_packagename_classname_helloLog(JNIEnv * env, jobject this, jstring myLog)
{
    jboolean isCopy;
    const char * szLogThis = (*env)->GetStringUTFChars(env, logThis, &isCopy);
    (*env)->ReleaseStringUTFChars(env, logThis, szLogThis);
}  

There is a reason for the long function name: the first word is “Java”, followed by the package name, the class name, and the method name. When you need to call this method, you can call it with the following format:

helloLog("This will log to LogCat via the native call.");  

You need to define the method interface inside your class so that Android can call it appropriately. This will help Android link this interface with the implementation inside the compiled native code.

private native void helloLog(String logThis);  

Finally, you need to load the library. In fact, you should load the library as soon as you load the class.

static {
    System.loadLibrary("ndk1");
}  

Summary

In this chapter, you learned about differences in performance optimization for three main platforms: iOS, Android, and Windows Phone. There are many similar issues between them because all three platforms are limited by the mobile devices constraint.

Having the same problem with the ListView and how to reuse the view properly, the three platforms solve the problem in a similar way—by trying to reduce loading all data and reusing the view as much as possible.

Caching and data storage in the three platforms is different because they choose different ways to implement the data storage and file structure for the application. iOS has the strongest database storage currently with CoreData while Android can utilize the strength of using external storage. The SQL database release for Windows Phone is expected by any Windows Phone developer in the next fall.

There are also big differences in the way the platforms choose to implement the same functionality, such as multitasking. Multitasking in iOS is more focused on fast app switching, Android focus on real multitasking by allowing process to run in the background, and Windows Phone doesn't support any multitasking in this version.

Exercise

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset