This is an old revision of the document!
Android Mobile Development
Resources
App Lifecycle
- onCreate()
- onStart()/onRestart()
- onResume()
- onPause()
- onStop()
- onDestroy()
Activities
Activities are equivalent to forms, and can be call directly by any other activity or app.
findViewById()
is a way to locate resources within Activity.
Event Listeners
- onClick()
- onFocusChange()
- onLongClick()
- onKey()
- onTouch()
Example 1:
public class MainActivity extends AppCompatActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Button btnAdd = (Button) findViewById(R.id.btnAdd); btnAdd.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // Do something, such as add to values EditText txtVal1 = (EditText) findViewById(R.id.txtVal1); EditText txtVal2 = (EditText) findViewById(R.id.txtVal2); int val1 = (int) Integer.parseInt(txtVal1.getText().toString()); int val2 = (int) Integer.parseInt(txtVal2.getText().toString()); int result = val1 + val2; final TextView lblResult = (TextView) findViewById(R.id.lblResult); lblResult.SetText(result + ""); // append empty string to convert operation to string Log.d("MyApp", "We clicked a button!"); Toast.makeText(this, "We clicked a button!", Toast.LENGTH_SHORT).show(); } }); } }
Example 2: Sharing onClickListener with multiple buttons in same Activity:
public class MainActivity extends AppCompatActivity implements View.OnClickListener { // Resources private TextView txt; private Button btn; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); txt = (TextView) findViewById(R.id.txtTest); btn = (Button) findViewById(R.id.btnTest); btn.setOnClickListener(this); } @Override public void onClick(View view) { // do something switch(view.getId()) { case R.id.btnTest: Log.d("MyApp", "We clicked a button!"); txt.SetText("We clicked a button!"); Toast.makeText(this, "YEs!!", Toast.LENGTH_SHORT).show(); break; // case ... } } }
Intents
Call for an activity into action (your own or other apps), which can carry a data payload. Eg: Calling dialer from your app, or calling email client when sending an email, or calling a new activity from within your app.
To deliver an intent:
- context.startActivity()
- context.startService()
- context.sendBroadcast()
To handle an intent:
- IntentService
- BroadcastReceiver
Implicit Intent
Intents that do not define which activity will handle the request, but rather seek a registered app to handle the provided data payload.
// Call dialer app to handle phone number Intent intentDialNumber = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:4071233500")); if (intentDialNumber.resolveActivity(getPackageManager()) != null) { startActivity(intentDialNumber); } // Call contacts to handle contact selection Intent intentSelectContact = new Intent(Intent.ACTION_DIAL, new Uri("content://contacts")); if (intentSelectContact.resolveActivity(getPackageManager()) != null) { startActivity(intentSelectContact); } // Call web browser to handle URL Intent intentViewWebsite = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.acme.com")); if (intentViewWebsite.resolveActivity(getPackageManager()) != null) { startActivity(intentViewWebsite); } // Call a mapping app to handle geolocation (lat,long,zoom) Intent intentShowLocation = new Intent(Intent.ACTION_VIEW, Uri.parse("geo:28.6027902,-81.4232732,14z")); if (intentShowLocation.resolveActivity(getPackageManager()) != null) { startActivity(intentShowLocation); } // Display all activities supporting Action View that can handle intent Intent intentShowAllActivities = new Intent(Intent.ACTION_VIEW); if (intentShowAllActivities.resolveActivity(getPackageManager()) != null) { startActivity(intentShowAllActivities); }
Explicit Intent
Intents that fully define the required activity that should handle the action and its data payload.
For example, in the MainActivity
, you can define an intent:
//... public class MainActivity extends AppCompatActivity { @Override public void onClick(View view) { switch(view.getId()) { case R.id.btnShowIntent: Intent intentDataHandler = new Intent(this, TargetActivity.class); intentDataHandler.putExtra("Key1", "Value1"); // data payload (optional) intentDataHandler.putExtra("Key2", "Value2"); // data payload (optional) intentDataHandler.putExtra("com.acme.myapp.Key3", "Value3"); // use full path with key (recommended) startActivity(intentDataHandler); break; } } }
In your target activity, retrieve the intent as follows:
//... public class TargetActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(saveInstanceState); setContentView(R.layout.activity_target); Bundle bundle = getIntent().getExtras(); // get data payload (if available) String str = bundle.getString("Key1"); Toast.makeText(this, str, Toast.LENGTH_SHORT).show(); // Better yet if (getIntent().hasExtra("Key2")) { str = getIntent().getExtras().getString("Key2"); Toast.makeText(this, str, Toast.LENGTH_SHORT).show(); } } }
Intent Examples
For example, in the MainActivity
, you can define an intent:
//... public class MainActivity extends AppCompatActivity implements View.OnClickListener { // Resources private TextView txtHello; private Button btnDialNumber; private Button btnViewWebsite; //... @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); txtHello = (TextView) findViewById(R.id.txtHello); btnDialNumber = (Button) findViewById(R.id.btnDialNumber); btnDialNumber.setOnClickListener(this); btnViewWebsite= (Button) findViewById(R.id.btnViewWebsite); btnViewWebsite.setOnClickListener(this); //... } @Override public void onClick(View view) { switch(view.getId()) { case R.id.btnDialNumber: Intent intentDialNumber = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:4071233500")); if (intentDialNumber.resolveActivity(getPackageManager()) != null) { startActivity(intentDialNumber); } break; case R.id.btnViewWebsite: Intent intentViewWebsite = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.acme.com")); if (intentViewWebsite.resolveActivity(getPackageManager()) != null) { startActivity(intentViewWebsite); } break; case R.id.btnShowLocation: Intent intentShowLocation = new Intent(Intent.ACTION_VIEW, Uri.parse("geo:28.6027902,-81.4232732,14z" // lat,long,zoom )); if (intentShowLocation.resolveActivity(getPackageManager()) != null) { startActivity(intentShowLocation); } break; case R.id.btnShowAllActivities: // Display all activities supporting Action View that can handle intent Intent intentShowAllActivities = new Intent(Intent.ACTION_VIEW); if (intentShowAllActivities.resolveActivity(getPackageManager()) != null) { startActivity(intentShowAllActivities); } break; case R.id.btnShowToast: Intent intentShowToast = new Intent(MainActivity.this, SampleActivity.class // target activity ); if (intentShowToast.resolveActivity(getPackageManager()) != null) { startActivity(intentShowToast); } break; case R.id.btnShowSampleActivity: Intent intentShowSampleActivity = new Intent("com.acme.myapp.SampleActivity"); if (intentShowSampleActivity.resolveActivity(getPackageManager()) != null) { startActivity(intentShowSampleActivity); } break; } } }
activity_main.xml
:
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.acme.myapp.MainActivity"> <Button android:id="@+id/btnDialNumber" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="8dp" android:layout_marginStart="8dp" android:layout_marginTop="24dp" android:text="@string/live" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/btnViewWebsite" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="8dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:text="@string/archives" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.501" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/btnDialNumber" /> <!-- More controls ... --> </android.support.constraint.ConstraintLayout>
In the manifest.xml
, you can add intent filters:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.acme.myapp"> <application ...> <activity android:name=".MainActivity" android:label="@string/app_name" android:theme="@style/AppTheme.NoActionBar"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".SampleActivity"> <intent-filter> <!-- Action Name to call directly --> <action android:name="com.acme.myapp.SampleActivity" /> <!-- Action Category. Required when including an action name --> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> <activity android:name=".Sample2Activity"> <intent-filter> <!-- Optional: Action Type by which to respond --> <action android:name="android.intent.action.VIEW" /> <!-- Action Category. Required when including an action name --> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> </application> </manifest>
Debugging with logcat
Log.d("MyAppTag", "A debug message"); // standard debug message Log.e("MyAppTag", "A debug message"); // error message Log.w("MyAppTag", "A debug message"); // warning message Log.i("MyAppTag", "A debug message"); // info message
ListView
Resources
Under resources (app
> res
> values
), add string arrays in strings.xml
. These will be data bound to a ListView
control:
<resources> <!-- Other resources... --> <string name="app_name">MyApp</string> <!-- String arrays for ListView --> <string-array name="arrProducts"> <item>Table</item> <item>Chair</item> <item>Stool</item> </string-array> <string-array name="arrPrices"> <item>$1.00</item> <item>$1.50</item> <item>$1.25</item> </string-array> <string-array name="arrColors"> <item>Red</item> <item>Blue</item> <item>Green</item> </string-array> </resources>
Data Binding
In the default onCreate()
method, add references to the ListView
:
package com.acme.myapp; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // ADD ListView here... } }
Add a ListView
with a custom item view using an ItemAdapter
. You can choose the type of item view:
TextView layout for item
To use a custom layout based on TextView
layout, create ListViewDetail layout:
- Go to project tree, select
app
>res
>layout
. Right-click and selectNew
>Layout resource file
. - File name:
listview_detail
- Root element:
TextView
Activity code:
public class MainActivity extends AppCompatActivity { // Properties ListView lstProducts; String[] arrProducts; String[] arrPrices; String[] arrColors; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Resources res = getResources(); lstProducts = (ListView) findViewById(R.id.lstProducts); arrProducts = res.getStringArray(R.array.arrProducts); arrPrices = res.getStringArray(R.array.arrPrices); arrColors = res.getStringArray(R.array.arrColors); // Example: Using layout resource based on TextView lstProducts.setAdapter(new ArrayAdapter<String>( this, // context R.layout.listview_detail, // detail view layout arrProducts // data )); } }
RelativeLayout/ConstraintLayout layout for item
You will need the following:
Item-Detail Activity (to be used by ItemAdapter)
To use a custom layout based on RelativeLayout
or ConstraintLayout
, create ListViewDetail layout:
- Go to project tree, select
app
>res
>layout
. Right-click and selectNew
>Layout resource file
. - File name:
listview_detail
- Root element:
RelativeLayout
orConstraintLayout
- Edit detail form by adding controls (TextView, ImageView, etc.) that can be associated with the different attributes (fields) for the item object represented.
Activity code:
import com.acme.myapp.ItemAdapter; public class MainActivity extends AppCompatActivity { ListView lstProducts; String[] arrProducts; String[] arrPrices; String[] arrColors; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Resources res = getResources(); lstProducts = (ListView) findViewById(R.id.lstProducts); arrProducts = res.getStringArray(R.array.arrProducts); arrPrices = res.getStringArray(R.array.arrPrices); arrColors = res.getStringArray(R.array.arrColors); // Example: Using custom ItemAdapter with custom layout ItemAdapter itemAdapter = new ItemAdapter( this, // context arrProducts, arrPrices, arrColors // data ); lstProducts.setAdapter(itemAdapter); } }
ItemAdapter
Create class ItemAdapter
- Go to project tree, select
app
>java
><your app package name>
. Right-click and selectNew
>Java Class
. - Name:
ItemAdapter
- Kind:
Class
- Superclass:
android.widget.BaseAdapter
package com.acme.myapp; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; public class ItemAdapter extends BaseAdapter { // Properties LayoutInflater mInflater; String[] arrProducts; String[] arrPrices; String[] arrColors; // // Constructor: Create custom contructor so properties get assigned right away // public ItemAdapter(Context cx, String[] prod, String[] prices, String[] colors) { arrProducts = prod; arrPrices = prices; arrColors = colors; mInflater = (LayoutInflater) cx.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public int getCount() { return arrProducts.length; } @Override public Object getItem(int idx) { return arrProducts[idx]; } @Override public long getItemId(int idx) { return idx; } @Override public View getView(int idx, View view, ViewGroup viewGroup) { // Use layout inflater. Use listview_detail.xml layout View vw = mInflater.inflate(R.layout.listview_detail, null); TextView txtProduct = (TextView) vw.findViewById(R.id.txtProduct); TextView txtPrice = (TextView) vw.findViewById(R.id.txtPrice); TextView txtColor = (TextView) vw.findViewById(R.id.txtColor); String strProduct = arrProducts[idx]; String strPrice = arrPrices[idx]; String strColor = arrColors[idx]; txtProduct.setText(strProduct); txtPrice.setText(strPrice); txtColor.setText(strColor); return vw; } }
ImageView
- Copy images to
app
>res
>drawable
folder in project tree. - Create an additional activity to display list item detail (including image)
- Add controls to display item properties in activity canvas.
TextView
control for item name and description.ImageView
control for item image.
Add an ItemClickListener
for the ListView
in MainActivity
activity. This will launch the secondary activity with the ListView
item details:
protected void onCreate(Bundle savedInstanceState) { // ... lstTeams.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Log.d("RoboticsLeague", "Loading rubric for Team " + (position+1)); Toast.makeText(getApplicationContext(), "Loading rubric for Team " + (position+1), Toast.LENGTH_SHORT).show(); Intent showRubricActivity = new Intent(getApplicationContext(), RobotRubricActivity.class); showRubricActivity.putExtra("com.voirtech.roboticsleague.TEAM_ID", (position+1)+""); startActivity(showRubricActivity); } }); }
On the secondary activity, process the intent:
package com.acme.roboticsleague; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.SeekBar; import android.widget.TextView; import android.widget.Toast; public class RobotRubricActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_robot_rubric); Intent intent = getIntent(); String strTeamId = intent.getExtras().getString("com.acme.roboticsleague.TEAM_ID"); TextView lblTeamId = (TextView) findViewById(R.id.lblTeamId); lblTeamId.setText("Team " + strTeamId); Button btnSaveRubric = (Button) findViewById(R.id.btnSaveRubric); btnSaveRubric.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // Do something, such as add to values SeekBar barDurability = (SeekBar) findViewById(R.id.barDurability); SeekBar barMechanicalEfficiency = (SeekBar) findViewById(R.id.barMechanicalEfficiency); SeekBar barMechanization = (SeekBar) findViewById(R.id.barMechanization); String valDurability = (String) (barDurability.getProgress() + ""); String valMechanicalEfficiency = (String) (barMechanicalEfficiency.getProgress() + ""); String valMechanization = (String) (barMechanization.getProgress() + ""); //final TextView lblResult = (TextView) findViewById(R.id.lblResult); //lblResult.SetText(result + ""); // append empty string to convert operation to string String msg = String.format("Saved evaluation at: %s, %s, %s", valDurability, valMechanicalEfficiency, valMechanization); Log.d("RoboticsLeague", msg); Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show(); } }); } }
Secondary Activity
The secondary activity with item details would look like:
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".RobotRubricActivity"> <TextView android:id="@+id/lblMechanicalDesign" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginTop="56dp" android:text="Mechanical Design" android:textStyle="bold" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/lblDurability" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_marginTop="4dp" android:text="Durability" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/lblMechanicalDesign" /> <TextView android:id="@+id/lblMechanicalEfficiency" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_marginTop="12dp" android:text="Mechanical Efficiency" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/lblDurability" /> <TextView android:id="@+id/lblMechanization" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_marginTop="12dp" android:text="Mechanization" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/lblMechanicalEfficiency" /> <TextView android:id="@+id/lblTeamId" android:layout_width="85dp" android:layout_height="27dp" android:layout_marginEnd="268dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:text="Team ID" android:textAlignment="viewStart" android:textSize="18sp" android:textStyle="bold" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <SeekBar android:id="@+id/barDurability" style="@style/Widget.AppCompat.SeekBar.Discrete" android:layout_width="156dp" android:layout_height="23dp" android:layout_marginEnd="16dp" android:layout_marginTop="76dp" android:max="4" android:progress="3" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" /> <SeekBar android:id="@+id/barMechanicalEfficiency" style="@style/Widget.AppCompat.SeekBar.Discrete" android:layout_width="156dp" android:layout_height="23dp" android:layout_marginEnd="16dp" android:layout_marginTop="8dp" android:max="4" android:progress="2" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@+id/barDurability" /> <SeekBar android:id="@+id/barMechanization" style="@style/Widget.AppCompat.SeekBar.Discrete" android:layout_width="156dp" android:layout_height="23dp" android:layout_marginEnd="16dp" android:layout_marginTop="8dp" android:max="4" android:progress="3" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@+id/barMechanicalEfficiency" /> <Button android:id="@+id/btnSaveRubric" android:layout_width="87dp" android:layout_height="34dp" android:layout_marginEnd="8dp" android:layout_marginTop="4dp" android:text="Save" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/lblRobotDesignRubric" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="4dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:text="Robot Design Rubric" android:textSize="18sp" app:layout_constraintEnd_toStartOf="@+id/btnSaveRubric" app:layout_constraintStart_toEndOf="@+id/lblTeamId" app:layout_constraintTop_toTopOf="parent" /> </android.support.constraint.ConstraintLayout>