2013-7-12
Make the Input Box Fill in the Screen Width
You can do this inside a LinearLayout with the weight property, which you can specify using the android:layout_weight attribute. if you give one view a weight of 2 and another one a weight of 1, the sum is 3, so the first view fills 2/3 of the remaining space and the second view fills the rest. If you add a third view and give it a weight of 1, then the first view (with weight of 2) now gets 1/2 the remaining space, while the remaining two each get 1/4.
The default weight for all views is 0, so if you specify any weight value greater than 0 to only one view, then that view fills whatever space remains after all views are given the space they require. So, to fill the remaining space in your layout with the EditText element, give it a weight of 1 and leave the button with no weight.
In order to improve the layout efficiency when you specify the weight, you should change the width of theEditText to be zero (0dp). Setting the width to zero improves layout performance because using "wrap_content"as the width requires the system to calculate a width that is ultimately irrelevant because the weight value requires another width calculation to fill the remaining space.
xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="@string/edit_message" />
Respond to the Send Button
To respond to the button's on-click event, open theactivity_main.xml layout file and add the android:onClickattribute to the
The android:onClick attribute’s value, "sendMessage", is the name of a method in your activity that the system calls when the user clicks the button.
Open the MainActivity class (located in the project's src/ directory) and add the corresponding method:
/** Called when the user clicks the Send button */
public void sendMessage(View view) {
// Do something in response to button
}
This requires that you import the View class:
import android.view.View;
In order for the system to match this method to the method name given to android:onClick, the signature must be exactly as shown. Specifically, the method must:
· Be public
· Have a void return value
· Have a View as the only parameter (this will be the View that was clicked)
Build an Intent
An Intent is an object that provides runtime binding between separate components (such as two activities). The Intent represents an app’s "intent to do something." You can use intents for a wide variety of tasks, but most often they’re used to start another activity.
Inside the sendMessage() method, create an Intent to start an activity called DisplayMessageActivity:
Intent intent = new Intent(this, DisplayMessageActivity.class);
The constructor used here takes two parameters:
· A Context as its first parameter (this is used because the Activity class is a subclass of Context)
· The Class of the app component to which the system should deliver the Intent (in this case, the activity that should be started)
An intent not only allows you to start another activity, but it can carry a bundle of data to the activity as well.
Intent intent = new Intent(this, DisplayMessageActivity.class);
EditText editText = (EditText) findViewById(R.id.edit_message);
String message = editText.getText().toString();
intent.putExtra(EXTRA_MESSAGE, message);
An Intent can carry a collection of various data types as key-value pairs called extras. The putExtra() method takes the key name in the first parameter and the value in the second parameter.
In order for the next activity to query the extra data, you should define the key for your intent's extra using a public constant. So add the EXTRA_MESSAGE definition to the top of the MainActivity class:
public class MainActivity extends Activity {
public final static String EXTRA_MESSAGE = "com.example.myfirstapp.MESSAGE";
...
}
It's generally a good practice to define keys for intent extras using your app's package name as a prefix. This ensures they are unique, in case your app interacts with other apps.
Start the Second Activity
To start an activity, call startActivity() and pass it your Intent. The system receives this call and starts an instance of the Activity specified by the Intent.
/** Called when the user clicks the Send button */
public void sendMessage(View view) {
Intent intent = new Intent(this, DisplayMessageActivity.class);
EditText editText = (EditText) findViewById(R.id.edit_message);
String message = editText.getText().toString();
intent.putExtra(EXTRA_MESSAGE, message);
startActivity(intent);
}
Create the Second Activity
If you're using a different IDE or the command line tools, create a new file named DisplayMessageActivity.java in the project's src/ directory, next to the original MainActivity.java file.
Because the ActionBar APIs are available only on HONEYCOMB (API level 11) and higher, you must add a condition around the getActionBar() method to check the current platform version. Additionally, you must add the@SuppressLint("NewApi") tag to the onCreate() method to avoid lint errors.
The Android lint tool is a static code analysis tool that checks your Android project source files for potential bugs and optimization improvements for correctness, security, performance, usability, accessibility, and internationalization.
The DisplayMessageActivity class should now look like this:
public class DisplayMessageActivity extends Activity {
@SuppressLint("NewApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display_message);
// Make sure we're running on Honeycomb or higher to use ActionBar APIs
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
// Show the Up button in the action bar.
getActionBar().setDisplayHomeAsUpEnabled(true);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
}
Add the title string
If you're using an IDE other than Eclipse, add the new activity's title to the strings.xml file:
...
Add it to the manifest
All activities must be declared in your manifest file, AndroidManifest.xml, using an
When you use the Eclipse tools to create the activity, it creates a default entry. If you're using a different IDE, you need to add the manifest entry yourself. It should look like this:
...
android:name="com.example.myfirstapp.DisplayMessageActivity"
android:label="@string/title_activity_display_message"
android:parentActivityName="com.example.myfirstapp.MainActivity" >
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.myfirstapp.MainActivity" />
The android:parentActivityName attribute declares the name of this activity's parent activity within the app's logical hierarchy. The system uses this value to implement default navigation behaviors, such as Up navigationon Android 4.1 (API level 16) and higher. You can provide the same navigation behaviors for older versions of Android by using the Support Library and adding the
Receive the Intent
Every Activity is invoked by an Intent, regardless of how the user navigated there. You can get the Intent that started your activity by calling getIntent() and retrieve the data contained within it.
To show the message on the screen, create a TextView widget and set the text using setText(). Then add theTextView as the root view of the activity’s layout by passing it to setContentView().
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get the message from the intent
Intent intent = getIntent();
String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);
// Create the text view
TextView textView = new TextView(this);
textView.setTextSize(40);
textView.setText(message);
// Set the text view as the activity layout
setContentView(textView);
}
Sending an intent to other apps
The intent created in this lesson is what's considered an explicit intent, because the Intent specifies the exact app component to which the intent should be given. However, intents can also be implicit, in which case the Intent does not specify the desired component, but allows any app installed on the device to respond to the intent as long as it satisfies the meta-data specifications for the action that's specified in various Intentparameters. For more information, see the class about Interacting with Other Apps.
Starting an Activity
Unlike other programming paradigms in which apps are launched with a main() method, the Android system initiates code in an Activity instance by invoking specific callback methods that correspond to specific stages of its lifecycle. There is a sequence of callback methods that start up an activity and a sequence of callback methods that tear down an activity.
you don't need to implement all the lifecycle methods.
there are several situations in which an activity transitions between different states that are illustrated in figure 1. However, only three of these states can be static. That is, the activity can exist in one of only three states for an extended period of time:
Resumed
In this state, the activity is in the foreground and the user can interact with it. (Also sometimes referred to as the "running" state.)
Paused
In this state, the activity is partially obscured by another activity—the other activity that's in the foreground is semi-transparent or doesn't cover the entire screen. The paused activity does not receive user input and cannot execute any code.
Stopped
In this state, the activity is completely hidden and not visible to the user; it is considered to be in the background. While stopped, the activity instance and all its state information such as member variables is retained, but it cannot execute any code.
The other states (Created and Started) are transient and the system quickly moves from them to the next state by calling the next lifecycle callback method. That is, after the system calls onCreate(), it quickly calls onStart(), which is quickly followed by onResume().
Specify Your App's Launcher Activity
The main activity for your app must be declared in the manifest with an
If either the MAIN action or LAUNCHER category are not declared for one of your activities, then your app icon will not appear in the Home screen's list of apps.
the system creates every new instance of Activity by calling its onCreate()method.
You must implement the onCreate() method to perform basic application startup logic that should happen only once for the entire life of the activity. For example, your implementation of onCreate() should define the user interface and possibly instantiate some class-scope variables.
Once the onCreate() finishes execution, the system calls the onStart() and onResume() methods in quick succession. Your activity never resides in the Created or Started states. Technically, the activity becomes visible to the user when onStart() is called, but onResume() quickly follows and the activity remains in the Resumed state until something occurs to change that, such as when a phone call is received, the user navigates to another activity, or the device screen turns off.
Destroy the Activity
last callback is onDestroy(). The system calls this method on your activity as the final signal that your activity instance is being completely removed from the system memory.
Most apps don't need to implement this method because local class references are destroyed with the activity and your activity should perform most cleanup during onPause() and onStop(). However, if your activity includes background threads that you created during onCreate() or other long-running resources that could potentially leak memory if not properly closed, you should kill them during onDestroy().
The system calls onDestroy() after it has already called onPause() and onStop() in all situations except one: when you call finish() from within the onCreate() method. In some cases, such as when your activity operates as a temporary decision maker to launch another activity, you might call finish() from withinonCreate() to destroy the activity. In this case, the system immediately calls onDestroy() without calling any of the other lifecycle methods.
Pausing and Resuming an Activity
When a semi-transparent activity obscures your activity, the system calls onPause() and the activity waits in the Paused state. If the user returns to the activity while it's still paused, the system calls onResume()。
However, once the activity is fully-obstructed and not visible, it stops。
When your activity receives a call to onPause(), it may be an indication that the activity will be paused for a moment and the user may return focus to your activity. However, it's usually the first indication that the user is leaving your activity.
When the system calls onPause() for your activity, it technically means your activity is still partially visible, but most often is an indication that the user is leaving the activity and it will soon enter the Stopped state. You should usually use the onPause() callback to:
· Stop animations or other ongoing actions that could consume CPU.
· Commit unsaved changes, but only if users expect such changes to be permanently saved when they leave (such as a draft email).
· Release system resources, such as broadcast receivers, handles to sensors (like GPS), or any resources that may affect battery life while your activity is paused and the user does not need them.
For example, if your application uses the Camera, the onPause() method is a good place to release it.
@Override
public void onPause() {
super.onPause(); // Always call the superclass method first
// Release the Camera because we don't need it when paused
// and other activities might need to use it.
if (mCamera != null) {
mCamera.release()
mCamera = null;
}
}
you should avoid performing CPU-intensive work during onPause(), such as writing to a database, because it can slow the visible transition to the next activity (you should instead perform heavy-load shutdown operations during onStop()).
You should keep the amount of operations done in the onPause() method relatively simple in order to allow for a speedy transition to the user's next destination if your activity is actually being stopped.
When your activity is paused, the Activity instance is kept resident in memory and is recalled when the activity resumes. You don’t need to re-initialize components that were created during any of the callback methods leading up to the Resumed state.
When the user resumes your activity from the Paused state, the system calls the onResume() method.
Be aware that the system calls this method every time your activity comes into the foreground, including when it's created for the first time. As such, you should implement onResume() to initialize components that you release during onPause() and perform any other initializations that must occur each time the activity enters the Resumed state (such as begin animations and initialize components only used while the activity has user focus).
Stopping and Restarting an Activity
There are a few of key scenarios in which your activity is stopped and restarted:
· The user opens the Recent Apps window and switches from your app to another app. The activity in your app that's currently in the foreground is stopped. If the user returns to your app from the Home screen launcher icon or the Recent Apps window, the activity restarts.
· The user performs an action in your app that starts a new activity. The current activity is stopped when the second activity is created. If the user then presses the Back button, the first activity is restarted.
· The user receives a phone call while using your app on his or her phone.
Because the system retains your Activity instance in system memory when it is stopped, it's possible that you don't need to implement the onStop() and onRestart() (or even onStart() methods at all. For most activities that are relatively simple, the activity will stop and restart just fine and you might only need to use onPause() to pause ongoing actions and disconnect from system resources.
When the user leaves your activity, the system calls onStop() to stop the activity (1). If the user returns while the activity is stopped, the system calls onRestart() (2), quickly followed by onStart() (3) and onResume() (4). Notice that no matter what scenario causes the activity to stop, the system always calls onPause() before calling onStop().
Once your activity is stopped, the system might destroy the instance if it needs to recover system memory. In extreme cases, the system might simply kill your app process without calling the activity's final onDestroy() callback, so it's important you use onStop() to release resources that might leak memory.
Although the onPause() method is called before onStop(), you should use onStop() to perform larger, more CPU intensive shut-down operations, such as writing information to a database.
When your activity is stopped, the Activity object is kept resident in memory and is recalled when the activity resumes. You don’t need to re-initialize components that were created during any of the callback methods leading up to the Resumed state. The system also keeps track of the current state for each View in the layout, so if the user entered text into an EditText widget, that content is retained so you don't need to save and restore it.
Even if the system destroys your activity while it's stopped, it still retains the state of the View objects (such as text in an EditText) in a Bundle (a blob of key-value pairs) and restores them if the user navigates back to the same instance of the activity。
When your activity comes back to the foreground from the stopped state, it receives a call to onRestart(). The system also calls the onStart() method, which happens every time your activity becomes visible (whether being restarted or created for the first time). The onRestart() method, however, is called only when the activity resumes from the stopped state, so you can use it to perform special restoration work that might be necessary only if the activity was previously stopped, but not destroyed.
Recreating an Activity
There are a few scenarios in which your activity is destroyed due to normal app behavior, such as when the user presses the Back button or your activity signals its own destruction by calling finish(). The system may also destroy your activity if it's currently stopped and hasn't been used in a long time or the foreground activity requires more resources so the system must shut down background processes to recover memory.
if the system destroys the activity due to system constraints (rather than normal app behavior), then although the actual Activity instance is gone, the system remembers that it existed such that if the user navigates back to it, the system creates a new instance of the activity using a set of saved data that describes the state of the activity when it was destroyed. The saved data that the system uses to restore the previous state is called the "instance state" and is a collection of key-value pairs stored in a Bundle object.
Your activity will be destroyed and recreated each time the user rotates the screen. When the screen changes orientation, the system destroys and recreates the foreground activity because the screen configuration has changed and your activity might need to load alternative resources (such as the layout).
By default, the system uses the Bundle instance state to save information about each View object in your activity layout (such as the text value entered into an EditText object).
To save additional data about the activity state, you must override the onSaveInstanceState() callback method. The system calls this method when the user is leaving your activity and passes it the Bundle object that will be saved in the event that your activity is destroyed unexpectedly. If the system must recreate the activity instance later, it passes the same Bundle object to both the onRestoreInstanceState() and onCreate() methods.
Save Your Activity State
static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
...
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save the user's current game state
savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
Restore Your Activity State
Both the onCreate() and onRestoreInstanceState() callback methods receive the same Bundle that contains the instance state information.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // Always call the superclass first
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
// Restore value of members from saved state
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
} else {
// Probably initialize members with default values for a new instance
}
...
}
Supporting Different Languages
To add support for more languages, create additional values directories inside res/ that include a hyphen and the ISO country code at the end of the directory name. For example, values-es/ is the directory containing simple resourcess for the Locales with the language code "es". Android loads the appropriate resources according to the locale settings of the device at run time.
Once you’ve decided on the languages you will support, create the resource subdirectories and string resource files. For example:
MyProject/
res/
values/
strings.xml
values-es/
strings.xml
values-fr/
strings.xml
Add the string values for each locale into the appropriate file.
At runtime, the Android system uses the appropriate set of string resources based on the locale currently set for the user's device.
You can use the locale qualifier (or any configuration qualifer) on any resource type, such as if you want to provide localized versions of your bitmap drawable. For more information, see Localization.
Supporting Different Screens
Android categorizes device screens using two general properties: size and density.
· There are four generalized sizes: small, normal, large, xlarge
· And four generalized densities: low (ldpi), medium (mdpi), high (hdpi), extra high (xhdpi)
Also be aware that the screens orientation (landscape or portrait) is considered a variation of screen size, so many apps should revise the layout to optimize the user experience in each orientation.
Create Different Layouts
To optimize your user experience on different screen sizes, you should create a unique layout XML file for each screen size you want to support. Each layout should be saved into the appropriate resources directory, named with a -
Android automatically scales your layout in order to properly fit the screen. Thus, your layouts for different screen sizes don't need to worry about the absolute size of UI elements but instead focus on the layout structure that affects the user experience (such as the size or position of important views relative to sibling views).
More information about how Android selects the appropriate resource is available in the Providing Resources guide.
If you want to provide a special layout for landscape, including while on large screens, then you need to use both the large and land qualifier:
MyProject/
res/
layout/ # default (portrait)
main.xml
layout-land/ # landscape
main.xml
layout-large/ # large (portrait)
main.xml
layout-large-land/ # large landscape
Main.xml
Android 3.2 and above supports an advanced method of defining screen sizes that allows you to specify resources for screen sizes based on the minimum width and height in terms of density-independent pixels. For more information, read Designing for Multiple Screens.
Create Different Bitmaps
To generate these images, you should start with your raw resource in vector format and generate the images for each density using the following size scale:
· xhdpi: 2.0
· hdpi: 1.5
· mdpi: 1.0 (baseline)
· ldpi: 0.75
This means that if you generate a 200x200 image for xhdpi devices, you should generate the same resource in 150x150 for hdpi, 100x100 for mdpi, and 75x75 for ldpi devices.
Then, place the files in the appropriate drawable resource directory:
MyProject/
res/
drawable-xhdpi/
awesomeimage.png
drawable-hdpi/
awesomeimage.png
drawable-mdpi/
awesomeimage.png
drawable-ldpi/
awesomeimage.png
Any time you reference @drawable/awesomeimage, the system selects the appropriate bitmap based on the screen's density.
Low-density (ldpi) resources aren’t always necessary. When you provide hdpi assets, the system scales them down by one half to properly fit ldpi screens.
Supporting Different Platform Versions
In order to provide the best features and functionality across several Android versions, you should use the Android Support Library in your app, which allows you to use several recent platform APIs on older versions.
Specify Minimum and Target API Levels
...
Check System Version at Runtime
private void setUpActionBar() {
// Make sure we're running on Honeycomb or higher to use ActionBar APIs
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
When parsing XML resources, Android ignores XML attributes that aren’t supported by the current device. So you can safely use XML attributes that are only supported by newer versions without worrying about older versions breaking when they encounter that code.
Use Platform Styles and Themes
To make your activity look like a dialog box:
To apply your own custom theme defined in /res/values/styles.xml:
To apply a theme to your entire app (all activities), add the android:theme attribute to the