Download 6pp

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
11/13/2015
Fragment Lifecycle
Exam 2 Review
Akhilesh Tyagi
Design Flexibility
public class MySkeletonFragment extends Fragment {
// Called when the Fragment is attached to its parent Activity.
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Get a reference to the parent Activity.
}
An example of how two UI modules defined by fragments can be
combined into one activity for a tablet design, but separated for
a handset design
●
Using fragments in activity
XML
Activity layout XML can include fragments.
<!‐‐ activity_name.xml ‐‐>
<LinearLayout ...>
<fragment ...
android:id="@+id/id1"
android:name="ClassName1" />
<fragment ...
android:id="@+id/id2" android:name="ClassName2" />
</LinearLayout>
// Called to do the initial creation of the Fragment.
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Initialize the Fragment.
}
• onCreate(): The system calls this when creating the fragment. Within your implementation, you should initialize essential components of the fragment that you want to retain when the fragment is paused or stopped, then resumed.
• onCreateView(): The system calls this when it's time for the fragment to draw its user interface for the first time. To draw a UI for your fragment, you must return a View from this method that is the root of your fragment's layout. You can return null if the fragment does not provide a UI.
Marty Stepps, Stanford CS193A
1
11/13/2015
// Called once the Fragment has been created in order for it to
// create its user interface.
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Create, or inflate the Fragment's UI, and return it. // If this Fragment has no UI then return null.
return inflater.inflate(R.layout.my_fragment, container, false);
}
Resource file my_fragment.xml
Should the inflated layout be attached
To the container?
Fragment template
public class Name extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup vg, Bundle bundle) {
// load the GUI layout from the XML
return inflater.inflate(R.layout.id, vg, false);
}
public void onActivityCreated(Bundle savedState) { super.onActivityCreated(savedState);
// ... any other GUI initialization needed
}
// Called at the end of the active lifetime.
@Override
public void onPause(){
// Suspend UI updates, threads, or CPU intensive processes that don't //need to be updated when the Activity isn't the active foreground // activity. Persist all edits or state changes as after this call the process is likely to be killed.
super.onPause();
}
// Called to save UI state changes at the
// end of the active lifecycle.
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save UI state changes to the savedInstanceState.
// This bundle will be passed to onCreate, onCreateView, and
// onCreateView if the parent Activity is killed and restarted.
super.onSaveInstanceState(savedInstanceState);
}
XML Fragment layouts
• Fragment element well suited for static layouts
• If the layout is to be dynamically modified in the program, use containers to pass to fragment managers.
// any other code (e.g. event‐handling)
}
Marty Stepps, Stanford CS193A
// Called at the start of the visible lifetime.
@Override
public void onStart(){
super.onStart();
// Apply any required UI change now that the Fragment is visible.
}
// Called at the start of the active lifetime.
@Override
public void onResume(){
super.onResume();
// Resume any paused UI updates, threads, or processes required
// by the Fragment but suspended when it became inactive.
}
<?xml version="1.0" encoding="UTF‐8"?>
<LinearLayout android:layout_height="match_parent" android:layout_width="match_parent" android:orientation="horizontal" xmlns:android="http://schemas.android.com/apk/res/android
">
<FrameLayout android:layout_height="match_parent" android:layout_width="match_parent" android:layout_weight="1" android:id="@+id/ui_container"/>
<FrameLayout android:layout_height="match_parent" android:layout_width="match_parent" android:layout_weight="3" android:id="@+id/details_container"/>
</LinearLayout>
2
11/13/2015
Fragment Transactions
• To add, remove, and replace fragments within an activity.
Fragment vs. activity
●
Fragment code is similar to activity code, with a few changes:
–
FragmentManager fragManager = getFragmentManager(); FragmentTransaction transaction = fragManager.beginTransaction(); transaction.add(R.id.container, firstFragment); transaction.commit(); •
• Many activity methods aren't present in the fragment, but you can call
• getActivity to access the activity the fragment is inside of.
–
• Button b = (Button) findViewById(R.id.but);
• Button b = (Button)
getActivity().findViewById(R.id.but);
Sometimes also use getView to refer to the activity's layout
–
Event handlers cannot be attached in the XML any more. :‐(
–
Passing information to a fragment (via Intents/Bundles) is trickier.
–
Fragment initialization code must be mindful of order of execution.
●
●
●
●
Must be attached in Java code instead.
The fragment must ask its enclosing activity for the information.
Does it depend on the surrounding activity being loaded? Etc. Typically move onCreate code to onActivityCreated.
Marty Stepps, Stanford CS193A
public class MyFragmentActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Inflate the layout containing the Fragment containers
setContentView(R.layout.fragment_container_layout);
FragmentManager fm = getFragmentManager();
// Check to see if the Fragment back stack has been populated
// If not, create and populate the layout.
DetailsFragment detailsFragment = (DetailsFragment) fm.findFragmentById(R.id.details_container);
Fragment onClick listener
●
Activity:
<Button android:id="@+id/b1" android:onClick="onClickB1" ... />
●
Fragment:
<Button android:id="@+id/b1" ... />
// in fragment's Java file
Button b = (Button) getActivity().findViewById(r.id.b1); b.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View view) {
// whatever code would have been in onClickB1
}
});
Marty Stepps, Stanford CS193A
Communicating with the Activity
if (detailsFragment == null) {
FragmentTransaction ft = fm.beginTransaction(); ft.add(R.id.details_container, new DetailsFragment());
ft.add(R.id.ui_container, new MyListFragment());
ft.commit();
}
}
}
• a fragment can access the Activity instance with getActivity() and easily perform tasks such as find a view in the activity layout:
View listView = getActivity().findViewById(R.id.list);
• activity can call methods in the fragment by acquiring a reference to the Fragment from FragmentManager, using findFragmentById()
ExampleFragment fragment = (ExampleFragment)
getFragmentManager().findFragmentById(R.id.exampl
e_fragment);
3
11/13/2015
Fragment that accepts parameters
public class Name extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.name, container, false);
}
Intents
●
intent: a bridge between activities;
a way for one activity to invoke another
–
–
–
the activity can be in the same app or in a different app
can store extra data to pass as "parameters" to that activity
second activity can "return" information back to the caller if needed
@Override
public void onActivityCreated(Bundle savedState) { super.onActivityCreated(savedState);
// extract parameters passed to activity from intent Intent intent = getActivity().getIntent();
int name1 = intent.getIntExtra("id1", default);
String name2 = intent.getStringExtra("id2", "default");
// use parameters to set up the initial state
...
}
Marty Stepps, Stanford CS193A
Communication between fragments
●
●
One activity might contain multiple fragments. The fragments may want to talk to each other.
–
–
Use activity's getFragmentManager method.
its findFragmentById method can access any fragment that has an id.
Activity act = getActivity();
if (act.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
// update other fragment within this same activity
FragmentClass fragment = (FragmentClass) act.getFragmentManager().findFragmentById(R.id.id);
fragment.methodName(parameters);
}
Marty Stepps, CS193A, Stanford
Intent Object
• The main information that can be contained in an intent object :
• Component name: The name of the component that should handle the intent.
• Action: An action to be preformed such as initiating a phone call in an activity or handling a low battery warning in a broadcast. • Data: Data to be acted on. • Category: Additional information about the component handling the intent such as a widget, home, preference. • Extras: Key value pairs containing additional information that should be passed to the component. • Flags: These are contained in the intent API and have many different functions for the system on how to handle the intent.
Marty Stepps, Stanford CS193A
Using Intents to Launch Activities
Intents
• To open a different application screen (Activity) in your application, call startActivity, passing in an Intent
startActivity(myIntent);
• The Intent can either explicitly specify the class to open, or include an action that the target should perform. Run time will choose the implicit Activity to open with “Intent resolution.”
4
11/13/2015
Intent Resolution
• Intents can be divided into two groups:
• Explicit intents: These designate a component by name and are generally used locally for internal messages.
• Implicit intents: Do not name a target and are generally used by outside applications. • For implicit intents the Android system will search components using intent filters to find the best match.
Implicit Intents and Late Runtime Binding
• Implicit Intents are a mechanism that lets anonymous application components service action requests.
• implicit Intent to use with startActivity, specifies an action to perform and, optionally, supplies the data on which to perform that action.
if (foundPhoneNumer) {
Intent intent = new Intent(Intent.ACTION_DIAL,
Uri.parse(“tel:555-2368”));
startActivity(intent);
}
Extracting extra data
●
In the second activity that was invoked, you can grab any extra data that was passed to it by the calling activity.
–
You can access the Intent that spawned you by calling getIntent.
–
The Intent has methods like getExtra, getIntExtra, getStringExtra,
etc. to extract any data that was stored inside the intent.
public class SecondActivity extends Activity {
...
public void onCreate(Bundle savedState) {
super.onCreate(savedState); setContentView(R.layout.activity_second); Intent intent = getIntent();
String extra = intent.getExtra("name");
...
}
}
Explicit Intent with Data/Arguments
Intent i = new Intent(this, ActivityB.class); i.putExtra("myString1", "This is a message for ActivityB"); i.putExtra("myInt1", 100); startActivity(i);
• The data is received at the target activity as part of a Bundle object which can be obtained via a call to getIntent().getExtras().
• ActivityB retrieves the data:
Bundle extras = getIntent().getExtras(); if (extras != null) { String myString = extras.getString("myString1"); int myInt = extras.getInt("myInt1"); }
Intents and Manifests
<?xml version="1.0" encoding="utf‐8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.ebookfrenzy.Intent1" android:versionCode="1" android:versionName="1.0" > <uses‐sdk android:minSdkVersion="10" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" >
<activity android:label="@string/app_name" android:name="ActivityA" >
<intent‐filter > <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> </intent‐filter> </activity> <activity android:name="ActivityB" android:label="ActivityB" > </activity> </application> </manifest>
• Subactivity ActivityB returns the result with:
public void finish() {
Intent data = new Intent();
data.putExtra("returnString1", "Message
to parent activity");
setResult(RESULT_OK, data);
super.finish(); }
Marty Stepps, CS193A, Stanford
5
11/13/2015
ActivityA receiving results
protected void onActivityResult(int requestCode, int resultCode, Intent data) { String returnString; if (resultCode == RESULT_OK && requestCode == REQUEST_CODE) { if (data.hasExtra("returnString1")) { returnString = data.getExtras().getString("returnString1"); } } }
Intent Filters
• Because intent filters must be seen by the Android system before launching a component; they are often placed in the Android Manifest file instead of Java Code.
• Implicit intents are tested against three filters of a component to see if they are correct.
Category
• category Use the android:category attribute to specify under which circumstances the action should be serviced
ALTERNATIVE: The alternative category specifies that this action should be available as an alternative to the default action.
BROWSABLE: Specifies an action available from within the browser
DEFAULT: Set this to make a component the default action. This is also necessary for Activities that are launched using an explicit Intent
GADGET: By setting the gadget category, you specify that this Activity can run embedded inside another Activity.
HOME: The home Activity is the first Activity displayed when the device starts
LAUNCHER: Using this category makes an Activity appear in the application launcher.
• Action
• Category
• Data
Actions
ACTION_CALL
activity
Initiate a phone call.
ACTION_EDIT
activity
Display data for the user to edit.
ACTION_MAIN
activity
Start up as the initial activity of a
task, with no data input and no
returned output.
ACTION_SYNC
activity
Synchronize data on a server with
data on the mobile device.
ACTION_BATTERY_LOW
broadcast receiver
A warning that the battery is low.
ACTION_HEADSET_PLUG
broadcast receiver
A headset has been plugged into
the device, or unplugged from it.
ACTION_SCREEN_ON
broadcast receiver
The screen has been turned on.
ACTION_TIMEZONE_CHANGED
broadcast receiver
The setting for the time zone has
changed.
Data
• Data tag specifies the data types handled by this component.
• android:host – specifies a valid host name (iastate.edu)
• android:mimetype
• android:path – valid path values for URIs
• android:port – valid ports for a host
6
11/13/2015
Intent Filter Example
<activity android:name=”.EarthquakeDamageViewer”
android:label=”View Damage”>
<intent‐filter>
<action
android:name=”com.paad.earthquake.intent.action.SHOW_DAM
AGE”>
</action>
<category android:name=”android.intent.category.DEFAULT”/>
<category
android:name=”android.intent.category.ALTERNATIVE_SELECTED”
/>
<data android:mimeType=”vnd.earthquake.cursor.item/*”/>
</intent‐filter>
</activity>
Listening for Broadcasts with Broadcast Receivers
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//TODO: React to the Intent received.
}}
• To enable a Broadcast Receiver, it needs to be registered, either in code or within the application manifest. When registering a Broadcast Receiver, you must use an Intent Filter to specify which Intents it is listening for.
public class LifeformDetectedBroadcastReceiver extends BroadcastReceiver {
public static final String BURN =
“com.paad.alien.action.BURN_IT_WITH_FIRE”;
@Override
public void onReceive(Context context, Intent intent) {
// Get the lifeform details from the intent.
Uri data = intent.getData();
String type = intent.getStringExtra(“type”);
double lat = intent.getDoubleExtra(“latitude”, 0);
double lng = intent.getDoubleExtra(“longitude”, 0);
Location loc = new Location(“gps”);
loc.setLatitude(lat);
loc.setLongitude(lng);
if (type.equals(“alien”)) {
Intent startIntent = new Intent(BURN, data);
startIntent.putExtra(“latitude”, lat);
StartIntent.putExtra(“longitude”, lng);
context.startActivity(startIntent);
}}}
Registering Broadcast Receivers in Application Manifest
<receiver android:name=”.LifeformDetectedBroadcastRec
eiver”>
<intent‐filter>
<action android:name=”com.paad.action.NEW_LIF
EFORM”/>
</intent‐filter>
</receiver>
Registering Broadcast Receivers in Code
// Create and register the broadcast receiver.
IntentFilter filter = new IntentFilter(NEW_LIFEFORM_DETECTED);
LifeformDetectedBroadcastReceiver r = new LifeformDetectedBroadcastReceiver();
registerReceiver(r, filter);
Preferences storage
• A SharedPreferences object points to a file containing key‐value pairs and provides simple methods to read and write them.
• getSharedPreferences() — Use this if you need multiple shared preference files identified by name, which you specify with the first parameter. You can call this from any Context in your app.
• getPreferences() — Use this from an Activity if you need to use only one shared preference file for the activity. Because this retrieves a default shared preference file that belongs to the activity, you don't need to supply a name.
7
11/13/2015
SharedPreferences files
• accesses the shared preferences file that's identified by the resource string R.string.preference_file_key and opens it using the private mode so the file is accessible by only your app. When naming your shared preference files, you should use a name that's uniquely identifiable to your app, such as "com.example.myapp.PREFERENCE_FILE_KEY"
• Context context = getActivity();
SharedPreferences sharedPref = context.getSharedPreferences(
getString(R.string.preference_file_key), Context.MODE_PRIVATE);
Read from Shared Preferences
• call methods such as getInt() and getString(), providing the key for the value you want, and optionally a default value to return if the key isn't present
SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
int defaultValue = getResources().getInteger(R.string.saved_high_score_
default);
long highScore = sharedPref.getInt(getString(R.string.saved_high_score)
, defaultValue);
Nameless Activity SharedPrerences file
boolean isTrue = mySharedPreferences.getBoolean(“isTrue”, false);
float lastFloat = mySharedPreferences.getFloat(“lastFloat”, 0f);
int wholeNumber = mySharedPreferences.getInt(“wholeNumber”, 1);
long aNumber = mySharedPreferences.getLong(“aNumber”, 0);
stringPreference = mySharedPreferences.getString(“textEntryValue”,
“”);
• SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_P
RIVATE);
• If you create a shared preferences file with MODE_WORLD_READABLE or MODE_W
ORLD_WRITEABLE, then any other apps that know the file identifier can access your data.
SharedPreferences sharedPref = getActivity().getPreferences
(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putInt(getString(R.string.saved_high_score)
, newHighScore);
editor.putBoolean(“isTrue”, true);
editor.putFloat(“lastFloat”, 1f);
editor.putInt(“wholeNumber”, 2);
editor.putLong(“aNumber”, 31);
editor.putString(“textEntryValue”, “Not Empty”);
editor.commit();
Multiple preference files
●
You can call getSharedPreferences and supply a file name if you want to have multiple pref. files for the same activity:
SharedPreferences prefs =
getSharedPreferences(
"filename", MODE_PRIVATE); SharedPreferences.Editor prefsEditor =
prefs.edit(); prefsEditor.putInt("name", value); prefsEditor.putString("name", value);
...
prefsEditor.commit();
Marty Stepps, CS193A, Stanford
8
11/13/2015
Putting it all together –
Accelerometer mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
if (mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null){
List<Sensor> gravSensors = mSensorManager.getSensorList(Sensor.TYPE_GRAVITY);
for(int i=0; i<gravSensors.size(); i++) {
if ((gravSensors.get(i).getVendor().contains("Google Inc.")) &&
(gravSensors.get(i).getVersion() == 3)){
// Use the version 3 gravity sensor.
mSensor = gravSensors.get(i);
}
}
}
public class sensorexample extends Activity implements SensorEventListener {
private SensorManager senSensorManager;
private Sensor senAccelerometer;
Reference to system
sensor service
@Override
protected void onCreate(Bundle savedInstanceState) {
Reference to default
accelerometer
Need to check if it exists
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sensorexample);
senSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
senAccelerometer =
senSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
senSensorManager.registerListener(this, senAccelerometer,
SensorManager.SENSOR_DELAY_NORMAL);
Register the listener to call back
when sensor event occurs
}
Called when accelerometer registers a new event
such as motion along any axis
else{
// Use the accelerometer.
if (mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null){
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
}
else{
// Sorry, there are no accelerometers on your device.
// You can't play this game.
}
}
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
Sensor mySensor = sensorEvent.sensor;
if (mySensor.getType() == Sensor.TYPE_ACCELEROMETER) {
Acceleration values along
float x = sensorEvent.values[0];
the three axis
float y = sensorEvent.values[1];
float z = sensorEvent.values[2];
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
Important – Sensors drain battery resource.
Sensors keep acquiring data during onPause if
not unregistered
public class SensorActivity extends Activity implements SensorEventListener {
private SensorManager mSensorManager;
private Sensor mLight;
@Override
public final void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mLight = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
protected void onPause() {
super.onPause();
senSensorManager.unregisterListener(this);
}
Re-register Sensorevent listener to continue
acquiring data during onResume
protected void onResume() {
super.onResume();
senSensorManager.registerListener(this, senAccelerometer,
SensorManager.SENSOR_DELAY_NORMAL);
}
}
9