Friday, 13 January 2017

Java For Android

While a number of languages can be used to build Android apps, Java is the language Google
encourages developers to use. However, it’s not precisely the same as the Java you may have encountered on other platforms. There are some subtle differences and peculiarities and it’s important for you as an Android developer to get your head around them.
In this tutorial, you’ll take a quick tour of Java in the Android world and find out more about the features it offers. Along the way you’ll also learn:
  • How an app on Android differs from a Java program on a PC
  • How to make use of Object Oriented Programming for Android
  • What a Java Interface is and how you might use it to communicate with other parts of your app
  • What Java Annotations are and how they provide extra information about parts of your app
This tutorial assumes you are familiar with at least one Object Oriented Programming language. It isn’t absolutely essential if you’re not, but the concepts discussed in this article will make more sense if you do.
Note: This article is somewhat different to a standard raywenderlich.com tutorial, in that it describes lots of high-level topics rather than having a follow-along sample app. You’re encouraged to give this a read before embarking on building Android apps as it gives you a great grounding in the quirks of Java for Android.
Grab a cup of your favourite “Java” and strap yourself in for a magical tour of the language — Android style!

Java and Android

Fun fact: Android doesn’t use “pure” Java! This may sound strange, because when you compare code from a traditional Java program to similar code from an Android app, you’d struggle to see the difference.
No Java, What?
Although writing and developing an Android app will feel somewhat familiar to experienced Java developers, the familiarity ends abruptly when you compile and run. The reason you’ll find yourself in uncharted territory is the way Android handles its apps during the compilation process.
Java’s major appeal is its ability to “Write once, run everywhere”. This language is sold as the silver bullet to the expensive process of porting software from one platform to another.
This veritable marvel of software engineering is made possible thanks to what happens when a Java program compiles.
During the compilation process for most other languages, the compiler links and optimizes the program, and then it translates it into Machine Code, which is a set of instructions a computer can understand and execute when you run the program.
Although execution of machine code is fast, it’s limited because it targets the platform on which it runs. If you ever wondered why a program written for iOS platform doesn’t just work on Windows, this is one of the reasons.
Java, in contrast, does something different; instead of translating a program into machine code, the Java compiler translates it an intermediate form called Bytecode. It creates a set of instructions that are similar to machine code, but are targeted to run on a Virtual Machine (VM) instead of some specified architecture.
Using a VM means that as long as it can read and interpret the Bytecode’s instructions, the program will happily run on its host platform, ensuring cross-platform compatibility.
And now you can see why most Java programs prompt you to download the Java Runtime Environment (JRE) when you don’t have it – it’s the default VM for the majority of platforms.

Java for Android is…Different

Compiling an app for Android follows the same path as converting Java files into Bytecode. Except that it doesn’t. When the app (composed of Bytecode) installs on a device, a second step occurs during installation. The app’s Bytecode is converted into machine code that’s optimized for that Android device, improving the app’s runtime performance. This process is known as Ahead of Time compilation (AoT) and is made possible by the Android Runtime (ART) virtual machine.
Note: Ahead of Time Compilation (AoT) is a concept used across many programming languages. You can read more about it on Wikipedia.
AoT compilation only occurs in Android KitKat (4.4) and above, but it also provides backwards compatibility. Prior versions of Android relied on another virtual machine known as Dalvik. Like ART, Dalvik made changes to the Java Bytecode, converting it into a specific form that made various efficiency changes to optimize the app for the kinds of low-powered devices Android was originally designed for.
However, unlike ART, Dalvik didn’t compile the Bytecode into machine code until runtime — using an approach known as Just in Time compilation (JIT). This process is much closer to that used in Java Virtual Environments on a PC.
Android Froyo (2.2) saw an improvement when Dalvik gained the ability to profile the app during runtime for commonly used portions of Dalvik Bytecode. These instructions were then permanently translated into machine code by Dalvik to boost the app’s speed.
Note: Trace Based Just in Time Compilation (JIT) is not unique to Java, and once again, Wikipedia does a nice job of explaining it.
In either case of Android app compilation, it’s the conversion of Bytecode that makes the Java written for Android less “pure”.
The changes to the Bytecode constrain the app’s portability, thereby negating one of the promises of Java language: “Write once, run everywhere”.
Another way Android diverges from Java is with the availability of standard libraries. Java is so portable is because it relies on a standardized collection of libraries it can use across various platforms, such as networking and UI libraries.
Android offers a subset of what Java provides, and what it does provide is only for Android.

Walking Through Java on Android

Android makes extensive use of Java’s adoption of the Object Oriented Programming paradigm, and it’s designed to work around the concepts of encapsulation, inheritance and polymorphism. You utilize all of these when you build apps.
All objects in Android inherit from the Object class in some form, building upon its functions to provide specialized behaviour and features. Take a look at some of the objects available through the Android API; you can see the hierarchy that each object inherits, and all of them eventually inherit Object.

Not-So-Paranormal Activity

The Activity class is an object dedicated to a specific screen of an app. Think of it as something that handles and displays all the associated work that drives the functionality for that screen.
Since your app will have at least have one or two functions, it would make sense to spread them across a few screens so your interface isn’t cluttery. To create a screen, you create a new Java class and have it extend Activity like so:
public class MainMenuActivity extends Activity {
 
}
Just like that, you stub out an area of your app for a specific purpose. Your Activity doesn’t yet know its purpose because you haven’t told it what to do or how to appear.
You can create your activity’s appearance, aka Layout, one of two ways:
  • Declare it in an XML file
  • Programatically create it in a Java class
The more common approach is creating the layout in an XML file. You’d take the programmatic approach if you need to tailor some aspect of your layout.
This article won’t take you take through either process for creating layouts, but understanding how to do it is helpful if you intend to write apps for Android, because it’s a regular task. Learn more about layouts from Android’s documentation.
The following code snippet demonstrates how you would specify that an activity should determine its appearance using the XML layout in res/layout/activity_main_menu.xml.
public class MainMenuActivity extends Activity {
  // 1
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); // 2
 
    setContentView(R.layout.activity_main_menu); // 3
  }
}
Take a look at it bit-by-bit:
  1. First, you override onCreate(), one of the methods available to you in an Activity. It runs when your Activity is created, giving you ample time to set up anything you need. This is often the first method you create for an Activity.
  2. You then call the superclass implementation of onCreate() to ensure any set up required for the Activity is performed. This is a required step. If you don’t do it, your app will crash with an exception warning.
  3. Finally, you tell your Activity to show a screen by using setContentView(), passing in a layout that’s referenced from R.
Note: R is a special class generated by Android for your app’s various assets. These could be a screen layout like you see above, or it could be something like a localized string, image or animation. Android generates R while building, so you shouldn’t modify it at all. More information about it is available from developer.android.com.
The XML layout will most likely include elements which make up the UI. You access these elements though R in an Activity, like this:
public class MainMenuActivity extends Activity {
 
  TextView mTextView;
  Button mButton;
 
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
 
    setContentView(R.layout.activity_main_menu); 
 
    mTextView = (TextView) findViewById(R.id.textview_main_menu);
    mButton = (Button) findViewById(R.id.button_main_menu);
  }
}
The key aspect is findViewById(), which searches the XML layout for view objects specified by their ID, allowing you to manipulate them from Java. Note that you have to typecast each call into an appropriate View subclass, since findViewById() only returns a View object—the root object from which all UI components inherit.
Once you have access to the individual view elements within the Java code, you would be able to interact with them and make them perform actions as you see fit. The following code segment demonstrates adding an action for when the user clicks a button:
public class MainMenuActivity extends Activity {
 
  TextView mTextView;
  Button mButton;
 
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
 
    setContentView(R.layout.activity_main_menu); 
 
    mTextView = (TextView) findViewById(R.id.textview_main_menu);
    mButton = (Button) findViewById(R.id.button_main_menu);
 
    mButton.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        mTextView.setText("Hello World");
      }
    });
  }
}
The code above runs onClick() every time your button is clicked. In onClick(), you tell your TextView, initially empty, to show the text “Hello World”.
Using this simple approach to link views to your class and provide actions to perform on a certain event, you can build highly complex activities. Remember these basic steps, and you’ll be on your way to grasping how Java and Android come together.

Lets Go Modeling

Models are integral to writing an Android app. Not to be confused with the kind of model that struts down the catwalk, they allow you to create objects that consist of data structures and functionality that you can utilize to great effect.
Models exist in separate classes from your UI classes. This separation not only helps keep your app organized, but it conforms to the idea of encapsulation in Object Oriented Programming.
A typical model looks something like this:
public class ReminderList {
 
  private ArrayList mReminderArrayList;
 
  public ReminderList() {
    mReminderArrayList = new ArrayList<>();
  }
 
  public void setReminderArrayList(ArrayList reminderArrayList) {
    this.mReminderArrayList = reminderArrayList;
  }
 
  public ArrayList getReminderArrayList() {
    return mReminderArrayList;
  }
 
  public void removeLastItemFromList() {
    if (!mReminderArrayList.isEmpty()) {
        mReminderArrayList.remove(mReminderArrayList.size() - 1);
    }
  }
}
No mentions of a view or activity in sight! Just data structures, raw data types and various functions. In fact this is just a Plain Old Java Object (POJO) — no secret sauce at all. This model is perfectly encapsulated, meaning you could drop it into any Android app and start using it straight away.
When creating objects in other OOP based languages, it’s conventional to create instance variables that are defined globally within the context of the object. In Android, it’s also conventional to prefix these instance variables with an m so it’s easy to tell what is a non-public, non-static instance variable and what isn’t. It feels a bit odd at first but is a good habit to get into, especially since Android source code specifies this convention and you’d need to do it to contribute to Android source code directly.
Getters and setters for member variables are also a staple of Android development. These short methods provide the rest of your app with a way to change a member variable if needed, and they allow you to provide extra behavior when getting and setting member variables.

Access Modifiers

One final piece of the puzzle that helps setters and getters work is access modifiers. Take a look at the following snippet from the model above:
private ArrayList mReminderArrayList;
 
public void setReminderArrayList(ArrayList reminderArrayList) {
  this.mReminderArrayList = reminderArrayList;
}
Notice the private and public keywords? These are access modifiers and they’re responsible for specifying which elements of your model class are accessible to other classes, helping to encapsulate your objects.
  • Public — accessible by all other objects. The public methods and variables form the API of the class.
  • Private — only accessible to this object. Not even available to subclasses.
  • Protected — accessible to this object and its subclasses. Not available to any other objects.
Member variables should always be set to private or protected. Access to them from outside the class should be via public getters and setters, as demonstrated in the above code snippet. This avoids hard-to-trace side-effects and tightly-coupled code.
If you made a subclass of the model above and wanted your subclass to have access to mReminderArrayList, you would change its access modifier to protected. This grants access to that variable in your subclass, while allowing you to further customize or work with that variable.

Fragments

Before tackling the next topic in Java for Android, you need to know a little bit more about how the UI of an Android app is constructed. Activities are great for managing the entire content of the screen, but they don’t like to share. Luckily there’s a great way to break down the UI into smaller component called fragments.
Fragments are like activities, but with the added bonus of being able to be embed in activities as though they were views. They have lifecycle methods similar to an activity’s onCreate() and can receive input just like an activity.
A layout for a fragment looks exactly the same as a layout for an activity; it contains a few view declarations. You even hook them up to the code in the same way, by declaring the view as a variable and finding the view through the identifier you provide in the layout.
The following code creates a fragment from a layout file at res/layout/fragment_embedded.xml:
public class EmbeddedFragment extends Fragment {
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    return inflater.inflate(R.layout.fragment_embedded, container, false);
  }
}
You first extend your class to inherit the behavior of a fragment and then use one of its lifecycle methods, namely onCreateView(), to set up the fragment. Then you return a layout to show for that particular fragment.
This is all simple enough when your activity and embedded fragment work in isolation, but what if you need them to communicate? Here’s an example method inside an activity that is trying to communicate with a fragment:
private void updateFragment() {
  EmbeddedFragment fragment = (EmbeddedFragment) getFragmentManager().findFragmentById(R.id.fragment_embedded);
  fragment.setTextViewText("Hello Little Fragment");
}
Because the fragment exists within the activity, you access it with findFragmentById and an identifier defined in XML. Then, you can easily invoke a fragment’s public methods, as shown in the above example, setTextViewText().
Conversely, a fragment can access its associated activity by calling getActivity(). This works in many simple situations, but it’s more fun to discuss in terms of an intricate scenario.

Interfaces

What if your activity was home to three lively fragments, each doing its own job, but needing to inform other fragments of what it’s doing at specific times?
In theory, fragments should only concern themselves with their own purpose and needn’t know they exist next to others; the activity is the mastermind in a sense. It’s the only one that has access to all the fragments and knows what they do.
This calls for a Java feature known as Interfaces.
An interface is like a class, but without the implementation. Instead it defines the public API. Classes can then implement these interfaces and your code no longer relies on concrete class implementations, instead knowing only that “this is an unknown object upon which I can call these interface methods”.
Interfaces allow your objects to work indirectly with other objects without exposing their inner workings. Think of something that is extremely complicated to build but quite simple to use: a car, a television set or even the device you’re using to read this tutorial.
You probably don’t know all of the inner workings of these things, but you certainly know how to operate them. Interfaces do the same thing.
In Android, interfaces are useful for facilitating communication fragment to activity, or fragment to fragment. It works like this:
public class EmbeddedFragment extends Fragment {
  // 1
  OnItemInListSelectedListener mCallback;
 
  // 2
  public interface OnItemInListSelectedListener {
    public void onItemInListSelected(int position);
  }
 
  @Override
  public void onAttach(Activity activity) {
    super.onAttach(activity);
    // 3      
    try {
      mCallback = (OnItemInListSelectedListener) activity;
    } 
    catch (ClassCastException e) {
      throw new ClassCastException(activity.toString()  + " must implement OnItemInListSelectedListener");
    }
  }
 
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment_embedded, container, false);
  }
}
Look at this in detail:
  1. In the fragment, you declare a member variable to store a custom object that implements OnItemInListSelectedListener and you name it mCallback.
  2. Next, you create the interface and declare the required methods — your interface can have many methods.
  3. In onAttach(), a fragment lifecycle method, you check if the activity your fragment is attached to conforms to OnItemInListSelectedListener. If not, then it can’t serve your purposes and you have a problem. The ClassCastException describes this during runtime. It’s best to signal this to yourself and other programmers so you can catch the problem early.
The next thing is to make your activity use the interface:
public class MainMenuActivity extends Activity implements EmbeddedFragment.OnItemInListSelectedListener {
 
  ...
 
  public void onItemInListSelected(int position) {
      // Received a message from the Fragment, you'll do something neat here
  }
}
The implements keyword in the class definition states that this class will implement the specified interface. You then need to provide implementations for all the methods specified on the interface. On this custom interface there is only one method, and you can see that it has a skeleton implementation in the above code snippet.
That’s the hard part, but you’re still not communicating fragment to fragment. Say you have defined a second fragment, ListDetailFragment, with identifier fragment_list_detail and a method named showListItemDetails(int). To get them talking, you simply do what you did earlier to establish activity to fragment communications with one of the fragment’s public methods:
public void onItemInListSelected(int position) {
  ListDetailFragment listDetailFragment = (ListDetailFragment) getFragmentManager.findFragmentById(R.id.fragment_list_detail);
  listDetailFragment.showListItemDetails(position);   
}
Just like that, you’ve built a way to communicate between fragments and activities. Interfaces are useful for establishing communication while keeping components separate. Learning how components work with fragments and activities is a vital part of keeping your app architecture flexible.

Annotations

Have you noticed those peculiar lines of code above some of the method names in this article?
@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
}
Those words prefixed with an @ are Annotations. They provide extra information at a variety of stages of an app. Annotations provide extra information to the compiler at runtime or even to generate extra code.
The most common annotation in Android is @Override, which exists to inform the compiler that a specific method should override one from the super class. If your method doesn’t actually override anything, then the compiler will fail and tell you, providing a nice safety net from any oddities you might have encountered.
Another well-known annotation is @TargetApi. It exists to allow your methods to indicate they are for use on a specific or newer version of Android. Using a method with @TargetApi set to a version higher than the current target of your app will cause the compiler to complain that you’re using functionality that isn’t available for your version of Android.
It’s a complaint, but it’s also a polite warning. You can still run your app despite the warning, but you can pretty much count on an ensuing crash.
When you’re building an Android app, you can almost count on needing these two annotations. There are others, and you can learn about the form the Android API documentation. It’s also possible to create your own annotations to automate specific tasks, generate code and other helpful functions.
A shining example of this is the third party library AndroidAnnotations. It provides a variety of custom annotations that simplify multi-line functions into single-line annotations and other useful features. Take a look at what annotations are available and what they offer to your apps.

Where To Go From Here?

Building an Android app requires time, patience and compiling multiple subjects under one roof. Hopefully this article has shed some light on the inner workings and the tricky relationship between Android and Java.
You’ve had a brief intro into these topics:
  • The Android VM. One of the key ways that Java for Android differs from standard Java is in its compilation process, and its virtual machines.
  • Use of POJOs. Plain old java objects are extensively used within Android to form the basis of model objects.
  • Access Modifiers. These are key to making your code readable and easy to reason about.
  • Interfaces. A hugely important topic in Android, as they are in the wider world of Java. Referring to objects via interfaces rather than concrete class implementations will really help to decouple code and create nicely reusable components.
  • Annotations. The Android-specific Java annotations that you’ll be using right from day 1.
There is no substitute for actually making an app; creating an app and experimenting with some of the concepts demonstrated here, and see what works and what fails.
If you’re new to Java, or want to refresh your memory, you can download a free PDF cheat sheet and quick reference that’ll make writing your first Java much smoother.
The forums, found below, are open to you to discuss this tutorial, ask questions, share ideas and muse on the larger theme of developing with Java for Android. There certainly is a lot to talk about!
The Android robot is reproduced or modified from work created and shared by Google and used according to terms described in the Creative Commons 3.0 Attribution License.

Harry

Author & Editor

A technology enthusiast and addictive blogger who likes to hacking tricks and wish to be the best White Hacket Hacker of the World.

0 comments:

Post a Comment

Note: only a member of this blog may post a comment.