Mobile Phone Handheld Hardware Hardware Rick Rogers John Lombardo O'Reilly Media, Inc. O'Reilly Media Android Application Development, 1st Edition5.2. Eclipse Java EditorThe Android SDK takes full advantage of the features built into the
Eclipse IDE, including those in the
Eclipse text editor, which is customized for Java source code development.
Let's use a simple application as an example of some of that editor's
features. If you're already an expert on using Eclipse for Java
development, you can skip this section. If you're new to Eclipse (or new
to Java), there are some hints here that will speed up your development of
Android applications. 5.2.1. Java ErrorsWe've created a new Android project called DebugTest, using
Eclipse and the Android SDK (File New Project Android Project).
When you do that, and open the Java source file the SDK created for you,
you get a central pane that looks like Figure 5-1. This is the Eclipse Java
text editor, and it is already doing its job to point out errors in the
nascent application. 
In this case, the error indication is in the left margin: the
little lightbulb and red X on line 11. Within that line, the editor has
underlined the R in R.layout.main to tell you specifically where
there's a problem. Editors in Eclipse are smart enough to understand the
syntax of the language they are editing, and in this case, the error
flag is telling us there's a problem with this part of the code. If we
use the mouse to hover over the R, we
get a pop up that gives us more information, as shown in Figure 5-2. If you hover your mouse
over the symbols in the left margin, you get the same pop up. 
Notice also that there's a little red indicator in the upper-right
area of the pane, indicating there is an error somewhere in this file,
and a little red open rectangle in the right margin. If this file were
big enough to need the vertical scroll bar, you could easily see the
locations of the errors in the file, and you could scroll to them by
dragging the scroll segment to the red rectangle. Eclipse makes it very
easy to see where it has found errors in your code. A quick check of the Package Explorer pane shows that there's no R.java file. Of course not! It doesn't exist,
because we haven't built the project yet, and that's why resources under
R can't be resolved. After we build
DebugTest (Project Build All), the error goes away (both the red
underline and the symbols in the margin). So let's add some code for a simple application and see some of
Eclipse's debug features. We'll edit DebugTest.java and main.xml to add a label, a text box, a
WebView (we want some Internet action to give us more to look at), and a
button. The application will be a trivial browser, with the box being
the URL and the button being the trigger to go load the URL into the
WebView. We'll throw in some intentional errors to see how Eclipse
handles them. Our altered main.xml file now
looks like this: <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Enter URL:"
/>
<EditText
android:id="@+id/URL"
android:layout_width="fill_parent"
android:layout_height="60.0dip"
android:maxLines="1"
<Button
android:id="@+id/btnGo"
android:layout_width="wrap_content"
android:layout_height="60.0dip"
android:text="Go"
/>
<WebView
android:id="@+id/wvBrowser"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<LinearLayout>
and DebugTest.java looks like
this: package com.oreilly.debug;
import android.app.Activity;
import android.os.Bundle;
public class DebugTest extends Activity {
private EditText txtURL;
private Button btnGo;
private WebView wvBrowser;
// Set up an onClick routine to gather URLs entered by the user
private final Button.OnClickListener btnGoOnClick = new Button.OnClickListener() {
public void onClick(View v) {
try {
wvBrowser.loadURL();
}
catch (Exception e) {}
}
};
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Find the Views in the layout file
txtURL = (EditText) findViewById(R.id.txtURL);
btnGo = (Button) findViewById(R.id.btnGo);
btnGo.setOnClickListener(btnGoOnClick);
wvBrowser = (WebView) findViewById(R.id.wvBrowser);
}
}If you type in these lines (instead of copying and pasting),
you'll see that the editor tries to anticipate what you might type given
the context of where you are in the code. As you type "wvBrowser.", for
example (including the final dot), the editor knows that
wvBrowser is a WebView, so it gives you a list of methods
and variables that WebViews have. This is a great feature that really
helps cut down on mistyped method and variable names. Once you've typed
or selected the method, the editor shows you the parameters for that
method, so you don't have to look those up either. Since we need to access the Internet to get web pages, we ask for
that permission in AndroidManifest.xml: <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.oreilly.debug"
android:versionCode="1"
android:versionName="1.0.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".DebugTest"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
</manifest>Looking at main.xml in the
Eclipse editor pane (now an XML editor, but with many of the same
features we saw in the Java editor), we see some errors (Figure 5-3). 
A quick inspection confirms what the editor is telling us—that
there's no close tag for the EditText. We type /> into line
17, and the red underlines immediately go away. Now that the EditText tag is fixed, we're left with one
more error, shown in Figure 5-4. 
It says we're missing the end tag for LinearLayout, but we're
really missing the slash that should start the end tag
</LinearLayout>. From the editor's syntactical point
of view, it knows only that it expected to find a
</LinearLayout> before the next
<LinearLayout> tag or the end of the file, and it
didn't find one. The error message is enough to cause us to look in the
right place and figure out what is really wrong. Now that we have main.xml
fixed up, let's look at the first part of DebugTest.java as it appears in Eclipse
(Figure 5-5). We can see from the
right scroll margin that there are a total of seven errors, and our
mouse is hovering over the error in the declaration of
btnGo. 
Now for one of my favorite features of Eclipse. The source of the
error displayed in Figure 5-5, it
turns out, is that EditText can't be resolved in the example, because we haven't
imported the package that defines EditTexts. You could go look in the
Android documentation and find the right name for the library, but
Eclipse has a labor-saving feature that will find it for you. Just type
Ctrl-Shift-O (that's the letter O) while the editor has focus, and
Eclipse will attempt to resolve all the unresolved references in the
file by finding appropriate libraries. With that one stroke, the
appropriate packages get imported for EditText, Button, and WebView (you
can't see them in Figure 5-5,
because they're hidden by the pop up), and those errors disappear from
the editing pane as well. That leaves us with five more errors, so we scroll down as shown
in the Eclipse screenshot in Figure 5-6. 
The four errors in lines 29, 32, 33, and 35 have the same source
as the one in Figure 5-2 and
will go away the first time we build the project with the new main.xml. Let's fix the remaining error using
Eclipse's help. We currently have the mouse hovering over the error in line 19,
and the pop up says we're trying to pass an Editable instead of a String
to the loadURL(String)
method. That's easy to fix: Editables have a toString method, like most objects, so we can
change onClick to look like
this: public void onClick(View v) {
try {
wvBrowser.loadUrl(txtURL.getText().toString());
}
catch (Exception e) {}
}Now we try to build and run the project (Run Run Android
Application), but Eclipse tells us we still have errors. It helpfully
lists all the problems found in the Problems tab, located in the pane at
the bottom of the Eclipse window. Figure 5-7 shows that tab. 
Clicking on an error in the Problems tab takes us directly to the
corresponding line of source code in the Editing pane for DebugTest.java. A quick look at main.xml reveals the problem: we referred to
the text box as URL in
main.xml, and tried to find it as txtURL in the Java code. A quick fix to
main.xml, and the compile
completes. Eclipse starts the Android emulator for us and loads our
application so it appears on the screen. The application runs—now to see
whether it produces correct results. If you type in a URL like www.oreilly.com and click the Go button, you
get...an error. Instead of the web page you asked for, you see a page
that says "Web Page not Available." Let's try http://www.oreilly.com...ah, that works. So
let's add code that checks whether the URL starts with http://, and if not, adds it: public void onClick(View v) {
try {
String sURL = txtURL.getText().toString();
if(sURL.substring(0,6).equals("http://")) {
wvBrowser.loadUrl(sURL);
}else{
sURL = "http://" + sURL;
wvBrowser.loadUrl(sURL);
}
}
catch (Exception e) {}
}Now when we run the program using www.oreilly.com as the URL, it works—but
http://www.oreilly.com doesn't! Let's
use the debugger to figure out why. 5.2.2. The DebuggerThe Android SDK makes the use of the Eclipse debugger completely
transparent, so let's use it to see what's going wrong with our program.
We'll put a breakpoint at the line we just entered, so the debugger will
break there when we run the program. Eclipse gives us three ways to
toggle a breakpoint: Use the menus. Select the line you want to toggle and choose
Run Toggle Breakpoint. Use the keyboard. Select the line you want to toggle and key
Ctrl-Shift-B. Double-click in the left margin of the editor window at the
line you want to toggle (my favorite method).
Whatever way you choose, you end up with a breakpoint mark in the
left margin of the editor window, as shown in Figure 5-8. 
To invoke the Debugger, choose Run Debug Android Application
from the Eclipse menu. Eclipse and the Android SDK do what they did before (build the
program if necessary, convert to Dalvik, invoke the emulator, load your
program, and start it running). You may get a window in the Emulator
that says "Waiting for Debugger: Application DebugTest is waiting for
the Debugger to connect." If you do, just wait a few seconds and the
Debugger should finish initializing, the window will disappear, and
you'll see the DebugTest screen. Now enter http://www.oreilly.com and click the Go
button. DebugTest starts executing and breaks at the breakpoint. Eclipse
automatically changes to the Debug Perspective, showing you panes that apply to
debugging your application. Starting from the upper left and moving down
the window, left to right, these are:
Debug The Debug pane has a single tab (Debug) that shows a
trace of recent execution. It should show that you are at a
breakpoint in a Dalvik thread running DebugTest, at Java line 19.
In its toolbar, this pane also contains the buttons for Resume,
Suspend, Terminate, Step Into, Step Over, Step Return, etc.
Variables and Breakpoints This pane has two tabs, the most useful of which is
Variables, where you can see the current value of variables that
are in scope. So far it's showing values for this and v.
Editor This contains a tab for each of the source files that
you had open in the Java Perspective. The currently displayed tab
should show DebugTest.java,
highlighting the current breakpoint (line 19).
Outline This shows the structure of your application. DebugTest
is simple, so it shows only one method, OnCreate.
Console/Tasks/Properties This pane has tabs for each of these views, which don't
contain much that's interesting at the moment. The Console is the
most useful, and in some debug situations can have important
information telling you what is (or isn't) happening.
Logcat This is the subject of the next section: the contents of the
Android logcat log, with buttons to filter the content.
Focusing on the Editor pane, which shows us stopped at line 19,
let's use the Step Over button (in the Debug toolbar in the pane above)
to step the program one line, to line 20. Now sURL appears in the Variables Pane, and it has
the right value, http://www.oreilly.com. Step once more and you
can tell something's wrong: we expected the program to take the first
branch of the if, and it took the second instead.
That's why http:// is appearing twice
in the URL string. If we step once more we can see that, as the value of
sURL changes in the Variables
Pane. To find out why, let's use another debug feature of Eclipse. From
the menu, choose Window Show View Display. A new Display tab is
added to the lower-left pane, and comes to the front. As long as the
Debugger is running, you can type any variable or expression that's in
scope into this window to display the variable's value or execute the
expression. We should be curious about the expression we're comparing
the user's URL to, sURL.substring(0,6). So cut and paste this
method call from the Editor pane into the Display tab, select the
expression, right-click, and choose Display from the pop-up menu.
Eclipse evaluates the expression and displays the result in the pane—and
what do you know, it's http:/, with
the last / missing, as shown in Figure 5-9. This problem may be
typical of errors that programmers encounter with the use of Java's
substring method, because its second
parameter represents the location of the last character, not the count
of characters, as in some other languages. We change the 6 to 7, and the
program works fine. 
5.2.3. LogcatGranted, the errors we debugged in the last section were pretty
straightforward—no different from debugging in any other environment.
But most applications are not as simple as DebugTest, and many problems
are much harder to isolate and solve. Android provides a general-purpose
logging facility that can help with many of those more difficult
problems. As mentioned before, there's a logcat pane on the Debug perspective (it's also in the DDMS perspective, which we'll talk
about in the next section and in Section 5.2.5). The log for DebugTest isn't very
interesting, so instead start MJAndroid in Debug mode and we'll take a
look at its log. After the application comes up in the emulator, Eclipse switches to the Debug Perspective and shows the
logcat pane on the lower right, as it looks in Figure 5-10. 
To make the pane large enough to be useful for reading the
log, click on the "full screen" symbol at the upper right of
the pane, and it will expand to fill the Eclipse window. You will then
see that there are hundreds of log messages in the file, going back to
when Eclipse first started the instantiation of the emulator that you
are using, continuing through the boot process for Android, loading all
the applications, and finally loading and executing MJAndroid. How are
you supposed to find anything useful in all of that? Luckily, Android provides you with some handy filters to apply to
the logfile. See the V, D, I, W, and E symbols in the toolbar? These
filters successively narrow the scope of messages displayed, as
follows:
V (Verbose) Show everything
D (Debug) Show Debug, Information, Warning, and Error messages
(equivalent to V for now)
I (Information) Show Information, Warning, and Error messages
W (Warning) Show Warning and Error messages
E (Error) Show only Error messages
The columns displayed for the log are:
Time The time the log entry was made
Priority (the column is not actually labeled) One of the log entry types from the previous list (D, I, W,
or E)
pid The Linux process ID of the process making the entry
tag A short tag describing the source of the entry
Message The log entry itself
About two-thirds of the way through the log (if you started a new
emulator when you brought up MJAndroid), you'll see a message entry
something like: 11-28 12:10:31.475: INFO/ActivityManager(52): Start proc com.microjobsinc.mjandroid
for activity com.microjobsinc.mjandroid/.MicroJobs:
pid=163 uid=10017 gids={3003}which actually appears all on one line; we've broken it here so it
will fit on a printed page. This is a log message from the Activity Manager telling us that it
started MicroJobs with process ID 163 (it will probably be different as
you run it). If you click on the green cross at the top of the logcat
pane, it will let you define a custom filter. Fill in a random name and
the pid number that you saw in the log. Now the log is filtered to show
only the messages that apply to this instance of MicroJobs. There are
likely still a lot of messages, which you can filter further (using the
D, I, W, and E buttons) or just scan.  | If you ask other people for help debugging an error in your own
program, one of the first things you'll likely be asked for is a copy
of the logcat output. You can easily extract the content of the
logfile to a text file by selecting what you'd like to preserve and
clicking on the little down arrow at the upper right of the logcat
pane, which brings down a pull-down menu. One of the selections on the
menu is "Export Selection as Text...", which takes you to a dialog
where you can name an output file for the log text. |
|
5.2.3.1. Looking at logcat to solve runtime errorsLogcat gives you a lot of information about what happened as Android tried to run your program. It
is very useful when you get a generic error message from Android that
doesn't tell you much. Let's demonstrate one of my (least)
favorites. In Eclipse, go to main.xml
for MJAndroid and remove the apiKey line under the MapView declaration (save it in a text
file or somewhere, so you can restore it; we're doing this just to
generate an error). The apiKey is
needed to access mapping information, so removing it brings the
program to a screeching halt. When you run the program, the emulator
screen looks like Figure 5-11. 
Although it's good to know that the application stopped, the
message tells us very little about why. If you now look at the logcat
output in the Debug perspective (or the DDMS perspective), you'll find
something like this after MicroJobs starts up, all in red type (we've
left off the first few columns so it will fit): java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.microjobsinc.mjandroid/com.microjobsinc.mjandroid.MicroJobs}:
android.view.InflateException: Binary XML file line #8: Error
inflating class java.lang.reflect.Constructor
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2140)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2156)
at android.app.ActivityThread.access$1800(ActivityThread.java:112)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1580)
at android.os.Handler.dispatchMessage(Handler.java:88)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:3742)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:497)
at dalvik.system.NativeStart.main(Native Method)
Caused by: android.view.InflateException: Binary XML file line #8: Error
inflating class
java.lang.reflect.Constructor
at android.view.LayoutInflater.createView(LayoutInflater.java:512)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:564)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:617)
at android.view.LayoutInflater.inflate(LayoutInflater.java:407)
at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
at
com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:227)
at android.app.Activity.setContentView(Activity.java:1569)
at com.microjobsinc.mjandroid.MicroJobs.onCreate(MicroJobs.java:132)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1122)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2103)
... 11 more
Caused by: java.lang.reflect.InvocationTargetException
at com.google.android.maps.MapView.<init>(MapView.java:227)
at java.lang.reflect.Constructor.constructNative(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:424)
at android.view.LayoutInflater.createView(LayoutInflater.java:499)
... 21 more
Caused by: java.lang.IllegalArgumentException: You need to specify an API Key for
each MapView.
See the MapView documentation
for details.
at com.google.android.maps.MapView.<init>(MapView.java:263)
at com.google.android.maps.MapView.<init>(MapView.java:244)
... 25 more The first three errors basically tell us that Android could not
start our application because it could not inflate the Views it found
in our layout file. The last error block we showed in the output
clearly tells us we need an API Key for each MapView. Logcat is often
the best way to get insight into errors where there isn't specific
information otherwise. 5.2.3.2. Writing your own logcat entriesTo write your own entries from your application into logcat,
Android provides methods corresponding to the different entry
priorities. The methods are all of the form: Log.x(String tag, String message, [Throwable exception]) where x can be v, d,
i, w, or e,
and the optional exception makes it easy to report exceptions that you
didn't anticipate in your code but encounter within a try/catch block.
For example, look at the onItemSelected method for
the Spinner in
MicroJobs.java: try {
mc.animateTo(mMyLocationOverlay.getMyLocation());
}
catch (Exception e) {
Log.i("MicroJobs", "Unable to animate map", e);
}
mvMap.invalidate();5.2.4. Android Debug Bridge (adb)Android comes with a specialized command-line debug utility
called adb. It lets you control a device or emulator
from your host, offering the kind of remote terminal or remote shell
service that embedded programmers have come to expect when working with
their target systems. Invoke the adb client from
a command prompt on the host (Start Run cmd.exe on Windows, or open
a terminal window on Linux or OS X). The client talks to an
adb server that runs in background on the host and
processes requests. If the server isn't running when you start the
client, it starts the server for you. The server in turn communicates with
adb daemons that run on either a device or an
emulator. All of this communication is through TCP/IP ports. A single
client/server can deal with multiple devices and emulators, but to
simplify things for our discussion, we'll assume there's only
one. If you just type adb at the command prompt,
you get the help information for adb: Android Debug Bridge version 1.0.20
-d - directs command to the only connected USB device
returns an error if more than one USB device
is present.
-e - directs command to the only running emulator.
returns an error if more than one emulator
is running.
-s <serial number> - directs command to the USB device or emulator with
the given serial number
-p <product name or path> - simple product name like 'sooner', or
a relative/absolute path to a product
out directory like 'out/target/product/sooner'.
If -p is not specified, the ANDROID_PRODUCT_OUT
environment variable is used, which must
be an absolute path.
devices - list all connected devices
device commands:
adb push <local> <remote> - copy file/dir to device
adb pull <remote> <local> - copy file/dir from device
adb sync [ <directory> ] - copy host -> device only if changed
(see 'adb help all')
adb shell - run remote shell interactively
adb shell <command> - run remote shell command
adb emu <command> - run emulator console command
adb logcat [ <filter-spec> ] - View device log
adb forward <local> <remote> - forward socket connections
forward specs are one of:
tcp:<port>
localabstract:<unix domain socket name>
localreserved:<unix domain socket name>
localfilesystem:<unix domain socket name>
dev:<character device name>
jdwp:<process pid> (remote only)
adb jdwp - list PIDs of processes hosting a JDWP transport
adb install [-l] [-r] <file> - push this package file to the device and install it
('-l' means forward-lock the app)
('-r' means reinstall the app, keeping its data)
adb uninstall [-k] <package> - remove this app package from the device
('-k' means keep the data and cache directories)
adb bugreport - return all information from the device
that should be included in a bug report.
adb help - show this help message
adb version - show version num
DATAOPTS:
(no option) - don't touch the data partition
-w - wipe the data partition
-d - flash the data partition
scripting:
adb wait-for-device - block until device is online
adb start-server - ensure that there is a server running
adb kill-server - kill the server if it is running
adb get-state - prints: offline | bootloader | device
adb get-product - prints: <product-id>
adb get-serialno - prints: <serial-number>
adb status-window - continuously print device status for a specified
device
adb remount - remounts the /system partition on the device
read-write
networking:
adb ppp <tty> [parameters] - Run PPP over USB.
Note: you should not automatically start a PDP connection.
<tty> refers to the tty for PPP stream. Eg. dev:/dev/omap_csmi_tty1
[parameters] - Eg. defaultroute debug dump local notty usepeerdns
adb sync notes: adb sync [ <directory> ]
<localdir> can be interpreted in several ways:
- If <directory> is not specified, both /system and /data partitions will be
updated.
- If it is "system" or "data", only the corresponding partition
is updated.Here are a few of the more useful adb
commands. There is much more information about these and other
adb commands in the Android documentation and
online.
adb devices Displays a list of devices and emulators that the
adb server knows about. This is a good way to
find the TCP/IP port for an emulator or device if you don't
already know it. The port number is also displayed in the title of
each emulator at the top of its window. If there's only one device
or emulator running (the normal case, unless you're debugging a
multidevice application), any adb commands
you issue automatically go to that target. The -s
and -e options are provided for multidevice
applications to let you specify a device or emulator.
adb shell This connects you with a shell running on the target and gives
you a # prompt. The shell is a simplified Unix-like shell, so you
can use the usual shell commands (ls,
cat, rm,
ps, etc.) to explore the target and make
changes as appropriate. Ctrl-D or exit will
get you out of the shell and back to your environment on the
host.
sqlite3
[path_to_database]A particularly useful shell command (you have to get into the shell with
adb shell first) for manipulating SQLite database files. The
sqlite3 program is further described in Chapter 8, and on the SQLite
website (). You can
optionally include the path to the database file you want to
manipulate (the MJAndroid
database, for example, would be in
data/data/com.microjobsinc.mjandroid/databases/MJAndroid).
adb logcat
[filter_spec]This is another way of looking at the logcat log on the target. When you
run it, it dumps the existing log to your virtual terminal and
continues to send additional log entries as they are generated in
the running system. The command is normally entered with a
trailing &, the Unix parameter for "run this in a separate
process," so that you can go on and use the terminal for other
commands (including, eventually, to kill the logcat process). The
filter specs are of the form
tag:priority, where tag and
priority were described in Section 5.2.3. So the command to see all AndroidRuntime log entries
of priority E would be: adb logcat AndroidRuntime:E & This is also useful for reading the "other" logs, of which
there are two: radio and events. The radio log is accessed through
a command like: adb -b radio & Similarly, to read the events log, enter: adb -b events &
adb install
[-l] [-r]
file_specThis can be used to install or reinstall an application.
The -l option forward-locks the installation
(preventing the application from being copied later to another
device), and the
-r option reinstalls the application without
overwriting the existing
application data. The file_spec must be
a valid, signed .apk file for
the application to be installed.
adb uninstall
[-k]
packageThis uninstalls the application with the given package
name. The package parameter needs to be
the full name of the package, without the
".apk" extension. So to uninstall MicroJobs, for example, you'd
type: adb uninstall com.microjobsinc.mjandroid If you want to keep the application's associated data, you
include the -k option.
adb push
local
remoteThis command copies a file from the
local name on the host to the
remote name on the target.
adb pull remote
localThis is the counterpart to the previous command, and
copies a file from the target to the host.
5.2.5. DDMS: Dalvik Debug Monitor ServiceInstalling the Android Software Development Kit adds DDMS to the Eclipse
integrated development environment, providing a window-oriented
interface to Android-specific debug information on the target. The most
frequently used perspectives are displayed in the upper-right corner of
the Eclipse window. If there's a DDMS button there, you can just click
on it to switch to DDMS. If not, in that same area there is a little
window symbol with a + sign in its upper-right corner. Clicking on this
window will open a menu of Perspectives, including DDMS. The DDMS perspective has four panes by default. Starting from the
upper left and going left to right down the screen, these are:
Devices This lists the available target devices connected to
Eclipse, and the processes running on each device. The default
emulator device is labeled with its port number (5554). There are
also some toolbar buttons in this pane, described later in this
section.
Threads/Heap/File Explorer This provides three different views of what is going on
in the target. The Threads tab shows the currently active threads
in the selected "client," which is the application selected in the
Devices pane. To see the Threads information, you have to click
the "Update Threads" button at the top of the Devices pane. The
Heap tab shows the state of the VM's heap memory, and is updated
at each garbage collect. Again, in order to see the Heap
information, you need to enable it by clicking the "Update Heap"
button at the top of the Devices pane, and you may need to
exercise the application for a while until the VM decides a
garbage collect is required before the information will be
updated. You can also force a garbage collect by clicking on the
"Cause GC" button in the Heap view.
Emulator Control This gives you control of the Telephony and Location emulation
functions:
Telephony Emulator You can simulate voice and data operation in a
variety of network states (unregistered, home, roaming,
searching, denied) and at a variety of network speeds and
latencies. It's useful to vary these parameters during
application testing to be sure that your application
responds appropriately in all typical situations. You can
also simulate incoming voice and SMS calls from a specific
number (to test Caller ID), and create the SMS message to be
received.
Location Emulator Here you can send a specific location fix to the
Location Provider by entering a latitude and longitude. You
can alternatively load a GPX or KML file of locations to be
played back to the Location Provider in a continuous
sequence, as though the target was moving around.
Logcat/Console/Outline/Properties This is similar to the "catchall" pane in the Debug perspective, providing a collection of
useful tabs that display the indicated information.
Screen Capture This isn't a pane, but one of the toolbar buttons in the
Display pane. It looks like a very small Android screen, and when
you click it, it captures and displays what is currently showing
on the target screen. It gives you the opportunity to save the
capture to a PNG file, which you can then use as you would any
other image.
5.2.6. TraceviewMaybe the problem you're trying to debug isn't about
functionality. Maybe your application does exactly what it's supposed to
do, but takes too long to do it. Wouldn't it be nice to have a way of
seeing how the methods within your classes are interacting, and even to
keep track of the relative time spent executing in each method?
Traceview is a utility that allow you just that kind of visibility. It
consists of two parts, one that you enable before running your program
and one that you work with after the run in order to diagnose your
findings:
Runtime data collection You can enable and disable logging for your application.
While enabled, routines are linked into your application that
create a binary trace file on the target. The trace file records
every method instantiation and the time spent in each
method.
Trace analysis If you then copy the binary trace file from the target to
your host, you can run a trace analysis program that displays all
the information from the file in graphical form. You can easily
observe which methods are consuming most of the runtime, and drill
down into those methods to find out which methods they in turn
call and which of them consume the most time.
5.2.6.1. Trace data collectionThe routines to perform trace data collection are provided in
the Android Software Development Kit. All you have to do is: Import the Debug package
(android.os.Debug) into your application. Call startMethodTracing
when you want to start collecting trace
information. Call stopMethodTracing
when you're done.
The tracing routines always write their trace information to a
file on the target's SD card. If you're running on a real device, you
need to plug in an SD card. If you're debugging on the emulator, you
need to create a virtual SD card and tell the emulator to use
it: Create a virtual SD card with mksdcard. From the host command prompt, use the
mksdcard utility to create a file that the
emulator can use as a virtual SD card: $ mksdcard -l ANDROID 1024M filename You can create the file anywhere you like, but the root
directory for your project is a good place. The utility will
allocate a file as big as the size you've given in the
mksdcard command (1 GB in the example
shown). Tell the emulator to use the virtual SD card. In Eclipse, choose Window Preferences Android Launch.
You'll see a box there for emulator options. Add the following
option: -sdcard filename Use the complete path to the file, so the emulator can
always find it, no matter where it's running from.
As an example of the code needed, let's add tracing to MicroJobs
and collect some data. We add tracing to MicroJobs.java as follows: ...
import android.os.Debug;
...
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// start trace
Debug.startMethodTracing("x");
...
// stop tracing when application ends
@Override
public void onDestroy() {
super.onDestroy();
Debug.stopMethodTracing();
}
Running MJAndroid now creates a file named x.trace on the virtual SD card on the target. When tracing is
enabled, the Dalvik virtual machine is noticeably slower to start up
and slower to run, because it is mapping the virtual SD card into
memory, and collecting all the method call and timing data for you as
it runs. For this example we went through a few UI operations and then
closed the application. To analyze x.trace, move it
back to the host: $ adb pull sdcard/x.trace x.trace and start the Traceview program: $ traceview pathnamex.trace For the moment at least, Traceview expects the full pathname of
the trace file. You are rewarded with a display of all the methods that were
called between the time you started and stopped the trace—not just the
methods in your application, but all the methods
that were called. The top part of the display is the Timeline Panel,
which looks something like Figure 5-12. The numbered line across the
top is a timeline (in milliseconds), with each application thread
listed as a separate row. Within each row, each method invocation is
shown as a little colored block (a little hard to see at the startup
resolution). The colors map to a list of methods shown in Figure 5-12. You can zoom in on a region of interest by moving the mouse into
the timeline area, clicking the left mouse button at the start time of
interest, dragging to the stop time, and releasing the button. The
timeline then zooms in, as shown in Figure 5-13. As you move the mouse
from left to right, the timeline cursor shows the sequence of method
calls, and the method names are called out in the upper right. 
The bottom part of the Traceview display lists each method, in
declining order by the amount of time spent in it. The first part of
that list is shown in Figure 5-14. 
The columns in this display have the following meanings:
Name You can't see colors here, but on the screen, the color in
the color-coded box to the left of each name tracks to the
timeline shown in Figure 5-12. The 15 colors get
reused in order by inclusive time, as you go down the
list.
Incl% and Inclusive The time (and percentage of total time) spent in this
method, including all the methods that it called. The times are
in milliseconds, but they should be interpreted with care.
Because tracing slows down execution considerably, these times
do not represent the true runtimes under normal execution. They
do provide accurate relative timing information when comparing
the runtimes of two methods.
Excl% and Exclusive The time (and percentage of total time) spent actually
executing in this method. In other words, any time spent in
nested functions is removed from these two fields. The same
timing caveats apply to Exclusive times as to Inclusive.
Calls+Recursive calls Two values: the number of times this method was called
externally and the number of times it called itself.
Time/Call Simply the quotient of the second column divided by the
sum of the numbers in the sixth column.
When you select a method by clicking on its name in the Profile
Panel, Traceview adjusts the pane to bring that method to the top of
the view, and opens a list of Parent and Child methods, as shown in
Figure 5-15. "Parents" are methods
that call this method. "Children" are methods called by this
method. 
Clearly, there is a lot of information available in the
Traceview records, and a full exploration is beyond the scope of this
book. We'll leave other features of Traceview for you to explore, such
as the use of Native Tracing to trace the QEMU emulator itself, the
use of the other Debug methods to get timing information, and the use
of the dmtracedump utility to generate call
graphs.
 |