Boris Farber
Custom Software Solutions Expert
1
Effective Android Workshop
Disclaimer
2
Android, Google are registered trademarks of Google Inc.
All other trademarks and copyrights are the property of their
respective owners.
License (http://www.gnu.org/licenses/fdl.html)
3
Copyright (C) 2011Boris Farber. Permission is granted to copy,
distribute and/or modify this document under the terms of
the GNU Free Documentation License, Version 1.3 or any
later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no
Back-Cover Texts. A copy of the license is included in the
section entitled "GNU Free Documentation License".
Used the material from the following
Android courses and sites
4
https://sites.google.com/site/androidappcourse (with
permission)
http://www.eli.sdsu.edu/courses/fall08/cs683/notes/
(Open Content (http://www.opencontent.org/openpub/
license)
http://www.slideshare.net/AndroidDev/android-ui-design-
tips
http://www.ece.ncsu.edu/wireless/MadeInWALAN/Andr
oidTutorial/index.html (with permission)
Course Goal
5
To simulate real life Android development for Android
beginner developers
Requirements
6
Java experience
Language Model (basics)
Nested Classes
Threads
Collections
Effective Usage
Mobile working experience
Software/Framework Engineering
Framework Experience
Design Patterns
Workbooks and PC with strong cable connection
Methodology
7
Minimize slides maximize code
No slides with Copy/Paste APIs
Workshop after workshop
Reading working code
Updating and refactoring real applications
Working directly with real APIs and documentations (thus
simulate real world development)
Solving problems !
Workshops
8
First Application
UI
Blocks/Views
Synchronization
Services/Activities
Receivers/Intents
Final Project
Workshops
9
For each workshop
1. Download and Run the Application
2. Understand the application
3. Develop, test and present the workshop requirements
10
Introduction
Introduction to Android Open software platform for mobile development
A complete stack – OS, Middleware, Applications
An Open Handset Alliance (OHA) project
Powered by Linux operating system
Fast application development in Java
Open source under the Apache 2 license
11
Android
12
Google’s mobile phone OS and SDK Java only
Special VM
Nonstandard byte code
Eclipse is the development IDE
Linux
Application framework 2D & 3D graphics
Audio, video and still image support
SQLite database
Embeddable web browser
Hardware dependent Bluetooth, EDGE, 3G, WIFI
Camera, GPS, compass
Accelerometer
Android Design Philosophy
13
Applications should be:
Fast Resource constraints: <200MB RAM, slow processor
Responsive Apps must respond to user actions within 5 seconds
Secure Apps declare permissions in manifest
Seamless Usability is key, persist data, suspend services
Android kills processes in background as needed
Emulator
14
Very useful in developing applications
Not the same as running on real device
Emulator has bugs
Device has different bugs
Device has restriction and limitations
Eclipse starts emulator when run Android app
Can recompile and run app without exiting and restarting
emulator
15
Building Blocks/Buzzwords
Building Blocks of Android Application
16
AndroidManifest.xml
Activities
Views
Intents
Services
Notifications
Content Providers
Android Manifest
17
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.hello2"
android:versionCode="1"
android:versionName="1.0.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".HelloAndroid"
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>
</manifest>
Activities
Typically correspond to one UI screen
But, they can:
Be faceless
Be in a floating window
Return a value
18
Intent Receivers
Components that respond to broadcast ‘Intents’
Way to respond to external notification or alarms
Apps can invent and broadcast their own Intent
19
Intents
Think of Intents as a verb and object; a description of what
you want done
E.g. VIEW, CALL, PLAY etc..
System matches Intent with Activity that can best provide the
service
Activities and IntentReceivers describe what Intents they can
service
20
Intents
GMail
Contacts
Home
Blogger
Chat
Client component makes a request for a specific action
“Pick photo”
Picasa
System picks best component for that action
New components can use existing functionality
Blogger
Photo Gallery
21
Intent
22
Used to move from screen to screen.
Contains:
Data
Action,What you want done
MAIN, VIEW, PICK, EDIT, etc
Intent filter
What intents an activity can handle
To move to a new screen register an intent
startActivity(anIntent).
Service
23
Code that runs in the background
Can be long lived
No UI
Example
music player
listening to connection
ContentProviders
Enables sharing of data across applications
E.g. address book, photo gallery
Provides uniform APIs for:
querying
delete, update and insert.
Content is represented by URI and MIME type
24
View
25
An object that knows how to draw itself to the screen
Set of existing views or widgets
Can create your own view
Games
New widgets
Notifications
26
Icon that appears in the status bar
Used to notify user
SMS
Voicemail
27
Hello World!+ Analysis
Sample App
28
package com.android.hello2;
import android.app.Activity;
import android.os.Bundle;
public class HelloAndroid extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
Resources ids
29
package com.android.hello2;
public final class R {
public static final class attr {
}
public static final class drawable {
public static final int icon=0x7f020000;
}
public static final class layout {
public static final int main=0x7f030000;
}
public static final class string {
public static final int Foo=0x7f040002;
public static final int app_name=0x7f040001;
public static final int hello=0x7f040000;
}
}
Layout
30
<?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"
android:orientation="vertical"
android:paddingLeft="6dip"
android:paddingRight="6dip"
android:paddingBottom="3dip">
<EditText
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="Hello, Android from xml"/>
</LinearLayout>
Sum up session
You won't get very far just going through the Hello World
tutorial.
There's a ton of important information in the Developer's
guide. A lot of best practices are covered.
It is Java: You work in Java for most of your Android
programming. Don't spend time praising it. Don't spend time
complaining about it. Just work with it.
31
32
Effective Android Activities
Activity Lifecycle
33
Feel the Activity
34
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class CountStates extends Activity
{
int paused = 0;
int killed = 0;
int stopped = 0;
TextView text;
Feel the Activity
35
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
paused = savedInstanceState.getInt("paused");
killed = savedInstanceState.getInt("killed");
stopped = savedInstanceState.getInt("stopped");
}
text = new TextView(this);
text.setText("Paused: " + paused + " stopped: " +
stopped + " killed “ + killed);
setContentView(text);
}
Feel the Activity
36
protected void onResume() {
super.onResume();
text.setText("Paused: " + paused + " stopped: " + stopped + " killed
“+ killed);
}
protected void onStart() {
super.onStart();
text.setText("Paused: " + paused + " stopped: " + stopped + " killed
“+ killed);
}
protected void onStop() {
stopped++;
super.onStop();
}
Feel the Activity
37
protected void onPause() {
paused++;
super.onPause();
}
protected void onDestroy() {
killed++;
super.onDestroy();
}
protected void onSaveInstanceState(Bundle outState) {
outState.putInt("paused", paused);
outState.putInt("killed", killed);
outState.putInt("stopped", stopped);
}
}
Override onPause/onResume
Make use of onPause()/onResume to save or close what
does not need to be opened the whole time.
protected void onResume() {
mSensorManager.registerListener(...);
}
protected void onStop() {
mSensorManager.unregisterListener(...);
super.onStop();
}
38
39
Effective Android Intents
Code for this part
40
public void do() {
Intent explicitIntent = new
Intent(this,InvokedActivity.class);
explicitIntent.putExtra(“Key”, “Value”);
startActivity(explicitIntent);
}
Connect between
components
Pass values
Start !
Launching Services Activities
41
Methods in
android.content.Context
Action
startActivity(Intent)
startActivityForResult(Intent,
int)
Launch an Activity
sendBroadcast(Intent) send it to any interested
BroadcastReceiver
components
startService(Intent)
bindService(Intent,
ServiceConnection, int)
Start service
Abstract description of an operation to be performed
Intents
42
Explicit Intents
Specify the component (class) an intent is to run
Implicit Intents
System determines which component to
run.Information about the request is given
action, type, scheme, categories <intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
Implicit Intents
43
action
If given, must be listed by the component as one it handles.
String, which we can create
type
Retrieved from the Intent's data, if not already supplied in the Intent.
If given, must be listed by the component as one it handles
data that is not a content: URI and where no explicit type,
The scheme of the intent data (such as http: or mailto:) is considered
If given, must be listed by the component as one it handles
Categories
If given, all must be listed by the component as ones it handles
Launch Intents Always prepare and launch intents from a separate method and
name those methods consistently. The code to launch an intent usually requires minor changes and parameter tweaks as the project progresses.
It changes frequently, and often all the intent code is looked at together. Mixing it in next to other code causes nothing put lingering, hard to debug, headaches.
The performance cost is minimal, mistakes are easier to see, testing is easier, and you won't cringe when need to review all your intent related code.
44
Workshop
45
Write 2 basic programs that
Creates service
Registers receiver
46
Introduction to UI, part 1
View Hierarchy
47
An activity tree is a hierarchical tree
You show it by calling setContentView(rootNode) in the
activity
Layout
48
Defines how elements are
positioned relative to each other
(next to each other, under each
other, in a table, grid, etc.)
Can have a different layouts for
each ViewGroup
Widgets
49
All are View objects
Examples:
TextFields
EditFields
Buttons
Checkboxes
RadioButtons
etc.
All layouts are hierarchical
50
All screens are derived from view
51
Hierarchical views can include similar
groups
52
Children do as told in Android
53
TextView is child of parent viewgroup and fills, or
wraps content
There are many types of controls in
Android
54
Lists can be handled via adapters and filled
from xml file of values
55
Table layout allows for just that with
data
56
Views are tied to activities (screens) in
Android
57
One class per
activity, and
screen, which may
be done as xml file
One layout per activity (class)
58
main.xml goes with AuctionStart
list.xml goes with ListItems
hit_server.xml goes with
HitServer
Xml layout file details components
59
Hierarchy of views as noted earlier
Xml layout inflated in onCreate
60
Set value of inflated object
INCOMPLETE CODE
New view items and attached to xml
values
Summary
61
Need to provide permissions for network in manifest
Create tree of xml views for UI
Can re-use xml views for different displays
62
Introduction to UI, part 2
Goal
63
Familiarize with the main types of GUI components
Concepts:
Layouts
Widgets
Menus
Linear Layout
64
<?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"> <LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"> <TextView android:text="red" android:gravity="center_horizontal" […………………….]
</LinearLayout> <LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"> <TextView android:text="row one" android:textSize="15pt" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1"/> <TextView android:text="row two" android:textSize="15pt" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1"/>
[…………………………………..] </LinearLayout> </LinearLayout>
One Layout, two views
65
XML File vs Layout Preview
Relative Layout
66
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:id="@+id/label" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Type here:"/> <EditText android:id="@+id/entry" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="@android:drawable/editbox_background" android:layout_below="@id/label"/> <Button android:id="@+id/ok" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/entry" android:layout_alignParentRight="true" android:layout_marginLeft="10dip" android:text="OK" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toLeftOf="@id/ok" android:layout_alignTop="@id/ok" android:text="Cancel" /> </RelativeLayout>
Table Layout
67
<?xml version="1.0" encoding="utf-8"?> <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:stretchColumns="1"> <TableRow> <TextView android:layout_column="1" android:text="Open..." android:padding="3dip" /> <TextView android:text="Ctrl-O" android:gravity="right" android:padding="3dip" /> </TableRow> <TableRow> <TextView android:layout_column="1" android:text="Save..." android:padding="3dip" /> <TextView android:text="Ctrl-S" android:gravity="right" android:padding="3dip" /> </TableRow> <TableRow> <TextView android:layout_column="1" android:text="Save As..." android:padding="3dip" /> <TextView android:text="Ctrl-Shift-S" android:gravity="right" android:padding="3dip" /> </TableRow> <View android:layout_height="2dip" android:background="#FF909090" />
[………………………] </TableLayout>
List View
68
List of scrollable items
Application will inherit from ListActivity rather than Activity
Create ./res/layout/list_item.xml Layout for each item
Override the OnCreate method
69
public class HelloListView extends ListActivity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setListAdapter(new ArrayAdapter<String>(this, R.layout.list_item, COUNTRIES));
ListView lv = getListView();
lv.setTextFilterEnabled(true);
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// When clicked, show a toast with the TextView text
Toast.makeText(getApplicationContext(), ((TextView) view).getText(),
Toast.LENGTH_SHORT).show();
}
});
}
}
Setup the list for this
application, with this
layout and this content
Enables filtering by
keyboard
Small Toast showing the
text in the clicked item
for a short time
Run it!
70
Date Picker
71
Will display a dialogbox allowing to
change the date
Layout
72
<?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" android:orientation="vertical"> <TextView android:id="@+id/dateDisplay" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=""/> <Button android:id="@+id/pickDate" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Change the date"/> </LinearLayout>
OnCreate( )
73
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // capture our View elements mDateDisplay = (TextView) findViewById(R.id.dateDisplay); mPickDate = (Button) findViewById(R.id.pickDate); // add a click listener to the button mPickDate.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { showDialog(DATE_DIALOG_ID); } }); // get the current date final Calendar c = Calendar.getInstance(); mYear = c.get(Calendar.YEAR); mMonth = c.get(Calendar.MONTH); mDay = c.get(Calendar.DAY_OF_MONTH); // display the current date (this method is below) updateDisplay(); }
updateDisplay( )
74
// updates the date in the TextView private void updateDisplay() { mDateDisplay.setText( new StringBuilder() // Month is 0 based so add 1 .append(mMonth + 1).append("-") .append(mDay).append("-") .append(mYear).append(" ")); }
DatePickerDialog.OnDateSetListener( )
75
// the callback received when the user "sets" the date in the dialog private DatePickerDialog.OnDateSetListener mDateSetListener = new DatePickerDialog.OnDateSetListener() { public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { mYear = year; mMonth = monthOfYear; mDay = dayOfMonth; updateDisplay(); } };
onCreateDialog( )
76
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case DATE_DIALOG_ID:
return new DatePickerDialog(this,
mDateSetListener,
mYear, mMonth, mDay);
}
return null;
}
Run it!
77
Selected Listeners, from Android site
78
GestureDetector.OnGestureListener Notify when gestures occur
MenuItem.OnMenuItemClickListener a menu item is clicked.
View.OnClickListener a view is clicked.
View.OnCreateContextMenuListener the context menu for this view is being built.
View.OnFocusChangeListener the focus state of a view changed.
View.OnKeyListener a key event is dispatched to this view.
View.OnLongClickListener a view has been clicked and held.
View.OnTouchListener a touch event is dispatched to this view.
79
Introduction to UI, part 3
Hello Form Stuff
80
Custom Buttons
Edit Text
Check Boxes
Radio Boxes
Toggle Button
Rating Bar
Custom Button
81
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/android_pressed" android:state_pressed="true" /> <item android:drawable="@drawable/android_focused" android:state_focused="true" /> <item android:drawable="@drawable/android_normal" /> </selector>
<Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="10dp" android:background="@drawable/android_button" />
final Button button = (Button) findViewById(R.id.button); button.setOnClickListener(new OnClickListener() { public void onClick(View v) { // Perform action on clicks Toast.makeText(HelloFormStuff.this, "Beep Bop", Toast.LENGTH_SHORT).show(); } });
Edit Text
82
<EditText android:id="@+id/edittext" android:layout_width="fill_parent" android:layout_height="wrap_content"/>
final EditText edittext = (EditText) findViewById(R.id.edittext); edittext.setOnKeyListener(new OnKeyListener() { public boolean onKey(View v, int keyCode, KeyEvent event) { // If the event is a key-down event on the "enter" button if ((event.getAction() == KeyEvent.ACTION_DOWN) && (KeyEvent.KEYCODE_ENTER)) { // Perform action keyCode == on key press Toast.makeText(HelloFormStuff.this, edittext.getText(), Toast.LENGTH_SHORT).show(); return true; } return false; } });
Check Box
83
<CheckBox android:id="@+id/checkbox" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="check it out" />
final CheckBox checkbox = (CheckBox) findViewById(R.id.checkbox); checkbox.setOnClickListener(new OnClickListener() { public void onClick(View v) { // Perform action on clicks, depending on whether it's now checked if (((CheckBox) v).isChecked()) { Toast.makeText(HelloFormStuff.this, "Selected", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(HelloFormStuff.this, "Not selected", Toast.LENGTH_SHORT).show(); } } });
Radio Button
84
<RadioGroup android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical"> <RadioButton android:id="@+id/radio_red" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Red" /> <RadioButton android:id="@+id/radio_blue" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Blue" /> </RadioGroup>
private OnClickListener radio_listener = new OnClickListener() { public void onClick(View v) { // Perform action on clicks RadioButton rb = (RadioButton) v; Toast.makeText(HelloFormStuff.this, rb.getText(), Toast.LENGTH_SHORT).show(); } };
final RadioButton radio_red = (RadioButton) findViewById(R.id.radio_red); final RadioButton radio_blue = (RadioButton) findViewById(R.id.radio_blue); radio_red.setOnClickListener(radio_listener); radio_blue.setOnClickListener(radio_listener);
Toggle Button
85
<ToggleButton android:id="@+id/togglebutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textOn="Vibrate on"
android:textOff="Vibrate off"/>
final ToggleButton togglebutton = (ToggleButton) findViewById(R.id.togglebutton);
togglebutton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// Perform action on clicks
if (togglebutton.isChecked()) {
Toast.makeText(HelloFormStuff.this, "Checked", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(HelloFormStuff.this, "Not checked", Toast.LENGTH_SHORT).show();
}
}
});
Rating Bar
86
<RatingBar android:id="@+id/ratingbar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:numStars="5" android:stepSize="1.0"/>
final RatingBar ratingbar = (RatingBar) findViewById(R.id.ratingbar); ratingbar.setOnRatingBarChangeListener(new OnRatingBarChangeListener() { public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) { Toast.makeText(HelloFormStuff.this, "New Rating: " + rating, Toast.LENGTH_SHORT).show(); } });
Hello WebView
87
Making a window for viewing
web pages
/res/layout/main.xml
88
<?xml version="1.0" encoding="utf-8"?>
<WebView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/webview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
OnCreate( )
89
WebView mWebView;
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mWebView = (WebView) findViewById(R.id.webview); mWebView.getSettings().setJavaScriptEnabled(true); mWebView.loadUrl("http://www.google.com"); }
AndroidManifest
90
<uses-permission android:name="android.permission.INTERNET" />
<activity android:name=".HelloWebView" android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar">
Run it!
91
Relative Layout & Sum Up Love RelativeLayout: Most of the tutorials use LinearLayout, but you will find that
RelativeLayout is truly useful. Many layouts, like the GridLayout aren't used much at all. Play around with RelativeLayout
Use fill_parent with a top level RelativeLayout: A surprisingly common and hard to find problem is putting a wrap_content in a top level RelativeLayout and then wondering why unrelated fields far down in the hierarchy are rendering strangely.
Use empty layout items: You will often use empty items in your layouts just for positioning other layouts. For example, you might use an empty TextField, of width=0 and height=0 and centerInParent='True' just to anchor things relative to the middle of the screen. Also, you might have an empty TextField or LinearLayout so that you can give a layout_weight=1 to it and have it take up more screen space.
Set a layout background color: If you are having trouble figuring out your layout, try setting the background colors on some objects. It can highlight your mistakes faster than other tools, and shows some surprises that the IDE red box doesn't always help.
92
93
Threads and Services
Background Processes
94
One of the key strengths of Android is the ability to run
things in the background on Android
Threads
Run something in the background while user interacts with UI
Services
Regularly or continuously perform actions that don’t require a UI
Threads
95
Recall that Android ensures responsive apps by enforcing a 5
second limit on Activities
Sometimes we need to do things that take longer than 5
seconds, or that can be done while the user does something
else
Threads
96
Activities, Services, and Broadcast Receivers run on the main
application thread
We can start background/child threads to do things for us
Threads
97
private void methodInAndroidClass() {
Thread thread = new Thread(null, doSomething, “Background”);
thread.start();
}
private Runnable doSomething = new Runnable() {
public void run() { /* do the something here */ }
};
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
private void methodInAndroidClass() {
new Thread(){
public void run() {/* do the something here */ }
}.start();
}
Example
98
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new Thread() {
public void run() {
String maps = null;
try {
URL updateURL = new URL("http://simexusa.com/cm/mapdata.txt");
URLConnection conn = updateURL.openConnection();
int contentLength = conn.getContentLength();
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is,1024);
ByteArrayBuffer baf = new ByteArrayBuffer(contentLength);
int current = 0;
while((current = bis.read()) != -1){
baf.append((byte)current);
}
maps = new String(baf.toByteArray()); //Convert the Bytes read to a String.
} catch (Exception e) {}
}
}.start();
}
Get data from web in background
Now we want to display data on screen
Android Thread Constraints
99
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView hello = (TextView)this.findViewById(R.id.hellotv);
hello.setText("testing");
new Thread() {
public void run() {
String maps = null;
try {
URL updateURL = new URL("http://simexusa.com/cm/mapdata.txt");
URLConnection conn = updateURL.openConnection();
int contentLength = conn.getContentLength();
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is,1024);
ByteArrayBuffer baf = new ByteArrayBuffer(contentLength);
int current = 0;
while((current = bis.read()) != -1){
baf.append((byte)current);
}
maps = new String(baf.toByteArray()); //Convert the Bytes read to a String.
} catch (Exception e) {}
TextView hello = (TextView)findViewById(R.id.hellotv);
hello.setText(maps);
}}.start();
CalledFromWrongThreadException: Only the original
thread that created a view hierarchy can touch its views.
Android Thread Constraints
100
Child threads cannot access UI elements (views); these must be
accessed through the main thread
What to do?
Give results to main thread and let it use results
In Campus Maps I set a flag in the thread, then I added the menu item
dynamically in Activity.onPrepareOptionsMenu
Solution
101
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final TextView hello = (TextView)this.findViewById(R.id.hellotv);
hello.setText("testing");
new Thread() {
public void run() {
String maps = null;
try {
URL updateURL = new URL("http://simexusa.com/cm/mapdata.txt");
URLConnection conn = updateURL.openConnection();
int contentLength = conn.getContentLength();
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is,1024);
ByteArrayBuffer baf = new ByteArrayBuffer(contentLength);
int current = 0;
while((current = bis.read()) != -1){
baf.append((byte)current);
}
maps = new String(baf.toByteArray()); //Convert the Bytes read to a String.
} catch (Exception e) {}
hello.setText(maps);
}}.start();
Post to GUI Thread
102
Handler allows you to post Messages and Runnable objects to
threads
These can be scheduled to run at some point in the future, or
enqueued for another thread
Post to GUI Thread
103
public class BackgroundDemos extends Activity {
private Handler handler = new Handler();
private String maps = null;
TextView hello;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
hello = (TextView)this.findViewById(R.id.hellotv);
hello.setText("testing");
new Thread() {
public void run() {
try {
URL updateURL = new URL("http://simexusa.com/cm/mapdata.txt");
//code omitted here
maps = new String(baf.toByteArray()); //Convert the Bytes read to a String.
handler.post(doUpdateMaps);
} catch (Exception e) {} } }.start();
}
private Runnable doUpdateMaps = new Runnable() {
public void run() {
hello.setText(maps);
}
};}
Services
104
Services are like Activities, but without a UI
Services are not intended as background threads Think of a media player where the song keeps playing while the
user looks for more songs to play or uses other apps
Don’t think of a cron job (e.g. run every day at 3am), use Alarms to do this
Several changes in 2.0 related to Services See http://android-
developers.blogspot.com/2010/02/service-api-changes-starting-with.html
105
Update service
something is
happening via
startService()
Expose
interfaces via
Binder
Tradeoffs
106
If you application involves only activities and services use
messengers(threads running) and startService/startActivities
usually the simple desired case
If your application has more complicated objects that need to
communicate (or request “services” such as context) with
services and activities use binder. Think twice before applying
Creating the Service
107
Add to AndroidManifest.xml
<service android:enabled=“true” android:name=“.NewMapService”></service><
Create the class
public class NewMapService extends Service {
@Override
public void onCreate() {
}
@Override
public void onStart(Intent intent, int startId) {
//do something
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
Start/Stop the Service
108
public class MyActivity extends Activity {
@Override
public void onCreate() {
…
startService(new Intent(this, NewMapService.class);
}
@Override
public void onStop() {
…
stopService(new Intent(this, NewMapService.class));
}
}
Status Bar Notifications
109
NotificationManager nm = (NotificationManager)getSystemService(
Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.icon,
"NewMaps",System.currentTimeMillis());
String expandedTitle = "New Map Service";
String expandedText = "New Map Service is running";
Intent i = new Intent(this, NewMapService.class);
PendingIntent launchIntent = PendingIntent.getActivity( getApplicationContext(), 0, i, 0);
notification.setLatestEventInfo(
getApplicationContext(), expandedTitle, expandedText, launchIntent);
nm.notify(1,notification);
nm.cancel(1); //cancel a notification (id/parameters must match)
Other Notification
110
Sounds
Vibration
Flashing lights
Ongoing and Insistent
Workshop
111
Add functionality to your Hello Service program
Explain your solution
112
Intents and Broadcast Receivers
Intents
113
Allows communication between loosely-connected components
Allows for late run-time binding of components
Explicit
Intent myIntent = new Intent(AdventDevos.this, Devo.class);
myIntent.putExtra("ButtonNum", ""+index);
startActivity(myIntent);
//finish(); //removes this Activity from the stack
Implicit
Intent i = new Intent(Intent.ACTION_VIEW,
Uri.parse("http://www.biblegateway.com/passage/?searc h="+ passage +"&version=NIV"));
startActivity(i);
Other Native Android Actions
114
ACTION_ANSWER – handle incoming call
ACTION_DIAL – bring up dialer with phone #
ACTION_PICK – pick item (e.g. from contacts)
ACTION_INSERT – add item (e.g. to contacts)
ACTION_SENDTO – send message to contact
ACTION_WEB_SEARCH – search web
Sub-Activities
115
Activities are independent
However, sometimes we want to start an activity that gives us
something back (e.g. select a contact and return the result)
Use
startActivityForResult(Intent i,
int id)
instead of
startActivity(Intent)
Capturing Intent Return Results
116
class ParentActivity extends Activity {
private static final int SUB_CODE = 34;
…
Intent intent = new Intent(…);
startActivityForResult(intent, SUB_CODE);
…
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == SUB_CODE)
if (resultCode == Activity.RESULT_OK) {
Uri returnedUri = data.getData();
String returnedString = data.getStringExtra(SOME_CONSTANT,””);
…
}
if (resultCode == Activity.RESULT_CANCELED) { … }
}
};
Capturing Intent Return Results
117
class SubActivity extends Activity {
…
if (/* everything went fine */) {
Uri data = Uri.parse(“content://someuri/”);
Intent result = new Intent(null,data);
result.putStringExtra(SOME_CONSTANT, “This is some
data”);
setResult(RESULT_OK, result);
finish();
}
…
if (/* everything did not go fine or the user did not
complete the action */) {
setResult(RESULT_CANCELED, null);
finish();
}
…
};
Using a Native App Action
118
public class MyActivity extends Activity {
//from http://developer.android.com/reference/android/app/Activity.html
... static final int PICK_CONTACT_REQUEST = 0; protected boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { // When the user center presses, let them pick a contact. startActivityForResult( new Intent(Intent.ACTION_PICK, new Uri("content://contacts")), PICK_CONTACT_REQUEST); return true; } return false; } protected void onActivityResult(int requestCode,
int resultCode, Intent data) { if (requestCode == PICK_CONTACT_REQUEST) { if (resultCode == RESULT_OK) { // A contact was picked. Here we will just display it to // the user. startActivity(new Intent(Intent.ACTION_VIEW, data)); } }
}
}
Broadcasts and Broadcast Receivers
119
So far we have used Intents to start Activities
Intents can also be used to send messages anonymously
between components
Messages are sent with sendBroadcast()
Messages are received by extending the
BroadcastReceiver class
Sending a Broadacst
120
//…
public static final String MAP_ADDED =
“com.simexusa.cm.MAP_ADDED”;
//…
Intent intent = new Intent(MAP_ADDED);
intent.putStringExtra(“mapname”, “Cal
Poly”);
sendBroadcast(intent);
//…
Typically like a package name to
keep it unique
Receiving a Broadcast
121
public class MapBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Uri data = intent.getData();
String name = data.getStringExtra(“mapname”);
//do something
context.startActivity(…);
}
};
Broadcast Receivers are started automatically – you don’t have to try to keep an Activity running
Less than 5 seconds
Registering a BroadcastReceiver
122
Statically in ApplicationManifest.xml <receiver android:name=“.MapBroadcastReceiver”>
<intent-filter>
<action android:name=“com.simexusa.cm.MAP_ADDED”>
</intent-filter>
</receiver>
Dynamically in code (e.g. if only needed while visible) IntentFilter filter = new IntentFilter(MAP_ADDED);
MapBroadcastReceiver mbr = new MapBroadcastReceiver();
registerReceiver(mbr, filter);
…
unregisterReceiver(mbr);
Native Broadcasts
123
ACTION_CAMERA_BUTTON
ACTION_TIMEZONE_CHANGED
ACTION_BOOT_COMPLETED
requires RECEIVE_BOOT_COMPLETED permission
Intent Filters
124
Intent filters register application components with Android
Intent filter tags: action – unique identifier of action being serviced
category – circumstances when action should be serviced (e.g. ALTERNATIVE, DEFAULT, LAUNCHER)
data – type of data that intent can handle Ex. URI = content://com.example.project:200/folder/subfolder/etc
Components that can handle implicit intents (one’s that are not explicitly called by name), must declare category DEFAULT or LAUNCHER
Example
125
Link to Android Notepad example application
http://developer.android.com/guide/topics/intents/intents
-filters.html
Android References Download Apps-For-Android: This is a big chunk of useful source code
for a half dozen applications. It can supplement the sample applications
nicely and show different coding style solutions.
Download the source: You need the Android source to solve some
problems or, more likely, get past holes in the documentation. Your copy
does not need to perfect or kept up to date.
Learn to search your source: The fastest solution to many problems is to
find where a particular parameter is used in some other source. Put a
copy or link to the sample applications, apps-for-android applications,
and any other source you have under one directory tree. Use "grep -ir
funky_parameter sample_code/" or your favorite searching routine to
quickly find some code that uses that parameter.
126
Workshop
127
Add functionality
Explain your solution
Persistence
128
Persistence
Three ways to store data
Shared Preferences
Files
SQL (out of scope)
129
Shared Preferences
Three forms:
Share across all components in an application
getSharedPreferences(“SomeString”,Activity.MODE_PRIVATE);
Store only data needed by this Activity
getPreferences(Activity.MODE_PRIVATE);
Store only data needed by this Activity when Activity becomes inactive
(but not when finished)
Ex. Orientation change from portrait to landscape
use Bundle in onSaveInstanceState/onRestoreInstanceState/onCreate
130
Shared Preferences Across all components (from context)
public static final String CMPREFS = "CampusMapSharedPreferences";
private void savePreferences() {
SharedPreferences cmSharedPreferences =
getSharedPreferences(CMPREFS,Activity.MODE_PRIVATE);
SharedPreferences.Editor editor = cmSharedPreferences.edit();
editor.putBoolean(VIRTUAL_MODE, inVirtualMode);
editor.commit();
}
private void restorePreferences() {
SharedPreferences cmSharedPreferences =
getSharedPreferences(CMPREFS,Activity.MODE_PRIVATE);
inVirtualMode = cmSharedPreferences.getBoolean(VIRTUAL_MODE, true/*def value*/);
}
131
Shared Preferences Only for this Activity (each Activity has one)
private void savePreferences() {
SharedPreferences cmActivityPreferences =
getPreferences(Activity.MODE_PRIVATE);
SharedPreferences.Editor editor = cmActivityPreferences.edit();
editor.putBoolean(VIRTUAL_MODE, inVirtualMode);
editor.putInt(MAP_INDEX, curMapIndex);
editor.commit();
}
private void restoreUIState() {
SharedPreferences cmActivityPreferences =
getPreferences(Activity.MODE_PRIVATE);
inVirtualMode = cmActivityPreferences.getBoolean(VIRTUAL_MODE, true);
curMapIndex = cmActivityPreferences.getInt(MAP_INDEX, 0);
}
132
Files Generally not recommended to use files
Store read-only static files in res/raw
133
Files Standard java.io is available
Can also use openFileOutput and openFileInput
byte[] b = new String("Yo").getBytes();
try {
FileOutputStream fos =
openFileOutput("anotherExampleFile.txt",
Context.MODE_WORLD_WRITEABLE);
fos.write(b);
FileInputStream fis =
openFileInput("anotherExampleFile.txt");
fis.read(b);
} catch (IOException e) {}
134
Wrap Up
135
Wrap Up
136
Covered most of basic very basic Android APIs and usage
Practice Practice and Practice
Doesn’t covered 100% of API
No brain is not enough
No need, what is most important is cope with problems
From Here Advanced Android
137
NDK
Open Source project research
Appendix UI Sessions
138
Design Considerations
Dos and Don’t
Principles of Effective UI Design
Rules of Thumb
Testing
139
Now
Take 30 min and learn out sample android application
140
Design considerations
Physical screen size
Screen density
Portrait & landscape orientations
Primary UI interaction method
Touch-screen
D-pad/trackball
Soft & physical keyboard
141
Don’ts
DON’T simply port your UI from other platforms
Users should feel right at home
with your app on their device
Balance your brand and platform look
DON’T overuse modal progress & confirmation dialogs
DON’T create 1000 activities. When you open an activity,
it's another app open on the top on others. As a result,
closing the app one by one can eventually piss off the user, or
at least confuse him.
142
Don’ts
DON’T create rigid, absolute-positioned layouts
DON’T use px units, use dp (or sp for text)
DON’T use small font sizes
143
Dos
DO create versions of all resources for high
density screens
DO make large, obvious tap targets (buttons, list items)
DO follow Android icon guidelines
DO use proper margins and padding
144
Dos
DO support D-pad & trackball navigation
DO properly manage the activity stack
DO properly handle orientation changes
DO use theme/style, dimension, color
resources to reduce redundancy
145
Dos
Do design for big fingers.
Do design for interruption. It's a phone : it gets on and off,
calls income, music is played, etc. Your app will be open and
shut a 1000 times so cut loading, save the right states and
ensure congruency.
DO work with visual and interaction designer(s)
146
Principles of good interface design
1.Focus on the user
2. Make the right things visible
3. Show proper feedback
4. Be predictable
5. Be fault-tolerant
147
1. Know your users
Know your users
Age, skill level, culture, disabilities, etc.
What they want to do with your app
What kinds of devices they’ll be using
Where/when/how they’ll be using their devices
Design with a ‘user-first’ mentality
Users are generally task-driven
Test on real users, early and often
148
2. Make the right things visible
The most common operations should be immediately visible
and available
Secondary functionality can be reserved for the MENU
button
149
3. Show proper feedback
Have at least 4 states (<selector>) for all interactive UI
elements:
Make sure the effects of an action are clear and visible
Show adequate yet unobtrusive progress indicators
150
4. Be predictable
Do what the user expects
Properly interact with the activity stack
Show information and actions users expects to see (requires
testing or observation)
Use proper affordances If something is clickable, make sure
it looks clickable!
If complex instructions are required, rethink your design.
151
5. Be fault tolerant
Constrain possible operations to only those that make sense
Disable UI elements when appropriate
Limit the number of irreversible actions
Prefer ‘undo’ to confirmation dialogs
In fact, use as few modal dialogs as possible. They’re obtrusive.
Awareness about the ways in which devices can vary
is very important
152
Testing
Buy a real phone ASAP. There are plenty of things you just
can't know if you run your app only on the emulator.
Don't think about releasing your app without having using it
for at least 2 week yourself on the phone.
Desktop computer experience does not suit.
153
Rules of thumb 1 Read the UI guidelines
2 Understand and design for touch mode
3 But, support multiple interaction modes
4 Use notifications and the window shade
5 Support interaction between applications
6 Keep your UI fast and responsive
7 Use widgets and live folders
8 Handle screen orientation changes
9 Use images wisely
10 Use layouts that adapt to multiple devices
154
Appendix Platform High Level View
155
156
Linux Kernel
• Works as a HAL
• Device drivers
• Memory management
• Process management
• Networking
157
Libraries
• C/C++ libraries
• Interface through Java
• Surface manager – Handling UI Windows
• 2D and 3D graphics
• Media codecs, SQLite, Browser engine
158
Android Runtime
•Dalvik VM
•Dex files
•Compact and efficient than class files
•Limited memory and battery power
•Core Libraries
•Java 6 edition
•Collections, I/O etc…
159
Application Framework
• API interface
• Activity manager – manages application life cycle.
160
Applications
• Built in and user apps
• Can replace built in apps
161
162