In this chapter, you will learn the following:
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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:
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.
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 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.
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.
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.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.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);
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.
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().
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.
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.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.
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.
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.
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.
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.
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.
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.
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.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.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)
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
}
}
}
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 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.
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.
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.
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 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.
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.
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 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.
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.
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");
}
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.