Android UI Programming
Android UI Programming
Activity
● Android Application Component for UI
– Provides a window for user interaction
– Content area for views and widgets
– Requires lifecycle and state management
Example: HelloWorldActivity (Java)
package [Link];
import [Link];
import [Link];
public class HelloWorldActivity extends Activity
{
/** Called when the activity is first created.*/
@Override
public void onCreate(Bundle savedInstanceState)
{
[Link](savedInstanceState);
setContentView([Link]);
}
}
Example: HelloWorldActivity (Kotlin)
package [Link]
import [Link]
import [Link]
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
<activity
android:name="HelloWorldActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="[Link]" />
</application>
</manifest>
Activity Lifecycle
● Primary states
– Resumed : Activity in foreground – user can interact
– Paused : At least partially obscured by another activity – activity may be
partially visible but loses focus.
– Stopped : Completely hidden – not visible to user. Activity may exist in
memory, but in low memory situation, can be killed by OS.
Lifecycle and state management
● Need
– Stop animations / video and other actions consuming
CPU
– Release system resources such as handles to sensors
– Commit unsaved changes (if required)
● Method
– onPause() / onResume()
● release / acquire resources, stop / start CPU utilization
– onStop() / onStart() / onRestart()
● save / handle persistent data
– onSaveInstanceState() / onRestoreInstanceState()
● save / load transient data
Basic Activity Relationships
Provides access to
application global state
Useful for looking up assets,
resources and other
application level information
Visual components
[Link]
UI Development Approaches
● Programmatic
– Using Java/Kotlin code
– Dynamic view generation
– Slightly complicated to maintain
● Declarative
– Using XML
– Static views – may be further adjusted through
programmatic approach
– Easier to maintain
Example: Notes App
package [Link]; package [Link];
Java Kotlin
package [Link];
import [Link];
Programmatic Approach
import [Link];
import [Link];
...
class MainActivity :Activity() {
public class NotesActivity extends Activity var notes:ArrayList<Note?>? = null
{ var currentNote:Note? = null
ArrayList<Note> notes; var textArea:EditText? = null
Note currentNote;
EditText textArea;
public override fun onCreate(savedInstanceState:Bundle?) {
public void onCreate(Bundle savedInstanceState) [Link](savedInstanceState)
{ //setContentView([Link]);
[Link](savedInstanceState); createUi()
//setContentView([Link]);
createUi(); notes = ArrayList<Note?>()
notes = new ArrayList<Note>(); }
}
private fun saveNote() {
private void saveNote(){ val content = textArea!!.[Link]()
String content = [Link]().toString(); if (currentNote == null) {
if(currentNote == null){
currentNote = new Note(content); currentNote = Note(content)
[Link](currentNote); notes!!.add(currentNote)
} }
[Link](content); currentNote!!.setContent(content)
val text = "Note saved successfully"
String text = "Note saved successfully";
Toast toast = val toast = Toast.m akeText(this,text,Toast.LENGTH_SHORT)
[Link](this,text,Toast.LENGTH_SHORT); [Link]()
[Link](); }
}
private fun newNote() {
private void newNote(){ saveNote()
saveNote();
[Link](""); textArea!!.setText("")
currentNote = null; currentNote = null
} }
[Link](textArea);
[Link](createMenu());
setContentView(outerLayout);
}
[Link](saveButton);
[Link](newButton);
[Link](listButton);
return layout;
}
private fun createUi() { Programmatic Approach (Kotlin)
val outerLayout = LinearLayout(this)
[Link] =
[Link] s(
[Link] s.MATCH_PARENT,
[Link] s.MATCH_PARENT
)
[Link] = [Link]
textArea = EditText(this)
textArea!!.layoutParams = [Link] s(
[Link] s.MATCH_PARENT,
[Link] s.WRAP_CONTENT,
1f
)
textArea!!.hint = "Notes"
textArea!!.gravity = [Link]
[Link](textArea)
[Link](createMenu())
setContentView(outerLayout)
}
Design pattern
Makes incompatible interfaces work with each other
Converts the interface to the one client expects
Allows creating decoupled general-purpose
implementations that can work with each other using
adapter
Applicability
Adapters for third-party libraries
public class NoteAdapter extends // create as an inner class of NoteAdapter Java
[Link]<[Link]> {
private ArrayList<Note> mDataset; public class NoteViewHolder extends
[Link] {
public NoteAdapter(ArrayList<Note> ds) {
mDataset = ds; public TextView title;
} public TextView timestamp;
public Button remove;
public [Link]
onCreateViewHolder(ViewGroup parent, public NoteViewHolder(View v) {
int viewType) { super(v);
title = (TextView) [Link]([Link]);
View v = [Link]([Link]()) timestamp = (TextView)
.inflate([Link].note_list_item, parent, false); [Link]([Link]);
// specify an adapter
mAdapter = new NoteAdapter(dataSet);
[Link](new DividerItemDecoration(this, [Link]));
[Link](mAdapter);
}
timestamp =
override fun onBindViewHolder( [Link]<View>([Link]) as TextView
holder: NoteViewHolder, position: Int) {
remove =
// - get element from your dataset at this position [Link]<View>([Link].button_remove) as Button
// - replace the contents of the view with that element
val content = mDataset[position].content [Link] { v ->
[Link] = val pos = [Link] as Int
content!!.substring(0, [Link]("\n")) [Link](pos)
[Link] = mDataset[position].timeStamp notifyDataSetChanged()
[Link] = position }
} }
//register
notesLauncher = registerForActivityResult(
new [Link](),
new ActivityResultCallback<ActivityResult>() {
//register
notesLauncher = registerForActivityResult<Intent, ActivityResult>(
[Link]()
) { result ->
if ([Link] == RESULT_OK) {
val data = [Link]
val id = [Link]("id")
// handle incoming data
}
}
}
● User interaction
– EditText combined with TextWatcher
– Other views e.g. toggle buttons, SearchView, etc.
public class NoteAdapter extends [Link]<[Link]> implements Filterable
{ Java
private Filter filter;
private ArrayList<Note> notes;
private ArrayList<Note> filteredNotes;
...
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if(constraint != null && [Link]() > 0){
ArrayList<Note> filteredList = new ArrayList<Note>();
for(int i=0; i < [Link](); i++){
if([Link](i).getContent().contains(constraint)){
[Link]([Link](i));
}
}
[Link] = [Link]();
[Link] = filteredList;
}
else{
[Link] = [Link]();
[Link] = notes;
}
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
filteredNotes = (ArrayList<Note>) [Link];
notifyDataSetChanged();
}
}
}
Java
Invoking filter
class NoteAdapter(private val notes: ArrayList<Note>, ls: NoteItemClickListener) :
[Link]<NoteViewHolder>(), Filterable { Kotlin
private var filteredNotes: ArrayList<Note>
private val listener: NoteItemClickListener
private var filter: Filter? = null
override fun getFilter(): Filter? {
if (filter == null) {
filter = NotesFilter()
}
return filter
}
}
[Link] {
val pos = [Link] as Int
[Link](filteredNotes[pos])
}
}
}
}
Kotlin
Invoking filter
Basic state management
public class Note implements [Link]
{
...
}
try{
[Link]("noteslist",notes);
}
catch(Exception ex){ }
}
public void onRestoreInstanceState(Bundle savedInstanceState){
[Link](savedInstanceState);
try{
notes = (ArrayList<Note>)
[Link]("noteslist");
}
catch(Exception ex){ }
}
...
Implement
[Link]
• Inflate menu
• Handle actions
Initiate action mode
• View's long-click
Recyclerview layout changed listener
to allow selection
• call startActionMode