Khalil Gibran خليل جبران
Khalil Gibran خليل جبران
Your children are not your children,
They are the sons and daughters of life´s longing for itself.
They come through you but not from you.
And though they are with you, they belong not to you.
You may give them your love but not your thoughts,
For they have their own thoughts.
You may house their bdoies but not their souls,
For their souls dwell in the house of tomorrow,
Which you can not visit, not even in your dreams.
You may strive to be like them, but seek not to make them like you,
For life goes not backwards nor tarries with yesterday.
You are the bows from which your children as living arrows are sent forth.
The arhcer sees the mark uopn the ptah of the infniite.
And He bends you with His might that His arrows may go swift and far.
Let your bending in the archer's hadns be for happiness;
For even as He loves the arrow that flies,
So He loves the bow that is stable.
Khalil Gibran خليل جبران
Yuor chidrlen are not yuor chlirden.
Tehy are the snos and duahgetrs of Lfie´s lonigng for istlef.
Tehy cmoe through you but not form you.
And thuogh tehy are wtih you, tehy beolng not to you.
You may give tehm yuor lvoe but not yuor thuohgts.
For tehy hvae their own thuohgts.
You may huose their bdoies but not their suols,
For their suols dewll in the huose of toomrorw,
Whcih you canont viist, not eevn in your draems.
You may stirve to be like tehm, but seek not to mkae tehm lkie you.
For lfie geos not bacwkard nor tarries with yesetrday.
You are the bows from whcih your chidlren as liivng arorws are snet fotrh.
The arhcer sees the mark uopn the ptah of the infniite.
And He bedns you with His mihgt that His arorws may go swfit and far.
Let your benidng in the arcehr's hadns be for hapipness;
For eevn as He loevs the arorw that fleis,
So He loevs the bow taht is stbale.
Getting started with the web guide is an introduction to the basics of the three languages, HTML
, CSS
, and JavaScript
. Navigate through each activity and complete all suggested code.
To build websites, you should know about HTML
. For an overview, take a brief look at HTML — structuring the web — and complete the following modules and the assessments.
Cascading Stylesheets — or CSS — is the first technology you should start learning after HTML. Take a brief look at Learn to style HTML using CSS — and follow the guides and complete the assessments in the following modules.
By default, HTML is accessible, if used correctly. Web accessibility involves ensuring that content remains accessible, regardless of who and how the web is accessed. Take a brief look at Accessibility overview — and follow the guides and complete the assessments in the following modules.
N.B. The lab test questions are based on the exercises above.
The aim is to have an overview understanding of Hypertext Transfer Protocol (HTTP). How does HTTP allows for surfing the web? and what are the common security issues on the web?
Create an HTML file and markup the following questions (and answers). Save the file as http_exercise.html
The answers are in the relevant articles in the HTTP tutorials.
get
and post
request.
JavaScript is more difficult to learn than related technologies such as HTML and CSS. Before attempting to learn JavaScript, you are strongly advised to get familiar with at least these two technologies first.
Take a brief look at JavaScript — and follow the guides and complete the code and any assessments in the following modules.
The Getting started with the Web, HTML and CSS lab exercises form the basis of the multiple choice questions in the lab test.
Example:
What is an HTML head
?
The second assessment is in two parts. The Lab Exercises and a project to create a Website for a topic of your own choosing.
Create a folder named, wd and save all your Lab Exercise and Website Project files in this folder. N.B. wd is the folder you will host on a Web server.
labs
folder. Please follow naming conventions for files and folders
labs.html
file.
labs.html
file<!DOCTYPE html>
<html>
<head>
<title>labs</title>
<meta charset="utf-8" />
<meta name="author" content="insert your name here" />
<meta name="description" content="Portfolio of lab exercises" />
</head>
<body>
<main class="panel">
<header>
<h1>
Website Development
</h1>
<h2>
Your full name
</h2>
<p>
<strong>ID: <em>insert your id</em></strong>,
<strong>Group: <em>insert your group</em></strong>
</p>
</header>
<h2>
Lab exercises
</h2>
<header>Getting started with the web</header>
<ul>
<li>
<a href="insert_your_url_for_this_exercise">
Getting started with the web</a>
</li>
</ul>
<header>HTML — Structuring the web</header>
<ul>
<li>
<a href="insert_your_url_for_this_exercise">
Marking up a letter</a>
</li>
<li>
<a href="insert_your_url_for_this_exercise">
Structuring a page of content</a>
</li>
<li>
<a href="insert_your_url_for_this_exercise">
Mozilla splash page</a>
</li>
<li>
<a href="insert_your_url_for_this_exercise">
Structuring planet data</a>
</li>
</ul>
<header>CSS — Styling the web</header>
<ul>
<li>
<a href="insert_your_url_for_this_exercise">
Fundamental CSS comprehension</a>
</li>
<li>
<a href="insert_your_url_for_this_exercise">
Typesetting a community school homepage</a>
</li>
<li>
<a href="insert_your_url_for_this_exercise">
Creating fancy letterheaded paper</a>
</li>
<li>
<a href="insert_your_url_for_this_exercise">
A cool looking box</a>
</li>
<li>
<a href="insert_your_url_for_this_exercise">
Fundamental Layout Comprehension</a>
</li>
</ul>
<header>Accessibility — Make the web usable by everyone</header>
<ul>
<li>
<a href="insert_your_url_for_this_exercise">
Accessibility troubleshooting</a>
</li>
</ul>
<p class="green">
N.B. The lab test questions are based on the exercises above.
</p>
<hr />
<header>JavaScript — Dynamic client</header>
<ul>
<li>
<a href="insert_your_url_for_this_exercise">
Silly story generator</a>
</li>
<li>
<a href="insert_your_url_for_this_exercise">
A dynamic shopping list</a>
</li>
</ul>
<header>HTTP & Security</header>
<ul>
<li>
<a href="insert_your_url_for_this_exercise">
HTTP & Security</a>
</li>
</ul>
<h2>Main Website</h2>
<ul>
<li>
<a href="insert_your_url_for_this_exercise">Page 1</a>
</li>
<li>
<a href="insert_your_url_for_this_exercise">Page 2</a>
</li>
<li>
<a href="insert_your_url_for_this_exercise">Page 3</a>
</li>
<li>
<a href="insert_your_url_for_this_exercise">Page 4</a>
</li>
<li>
<a href="insert_your_url_for_this_exercise">Page 5</a>
</li>
</ul>
</main>
</body>
</html>
labs.html
will be typically displayed in a browser.ID: your id, Group: your group
N.B. The lab test questions are based on the exercises above.
labs.html
file, and insert your details (your full name, id and group) in the labs.html
file
labs.html
file, and update the hyperlink href="insert_your_url_for_this_exercise"
with the URL of your exercise. Please use relative URLs
view page source
for each page and check for errors (highlighted in red)
labs.html
file on the server and check for any broken links.
wd
folder to save all your project files.
view page source
and check for errors (highlighted in red)
labs.html
file and update the href
addresses for the project pages. Please use relative URLs.
project
folder to the server. Upload the wd folder to the Web server and surf the project pages for any broken links.
JavaScript
and the more complex Manipulating documents APIs. Try the Active learning exercise and modify the shopping list by styling it and adding an update button and validation for the form input.
<html>
<head>
<title>My test page</title>
</head>
<body>
⋮
</body>
</html>
HTML
is a document oriented specification<html>
<head>
<meta charset="utf-8">
<title>My test page</title>
</head>
<body>
<h1>Hello world!</h1>
⋮
</body>
</html>
Browser converts HTML to Document Object Model(DOM)
var myHeading = document.querySelector('h1');
myHeading.onclick = function() {
alert('Ouch! Stop poking me!');
myHeading.textContent = 'Hello world!';
myHeading.style.color = "red";
}
How many syntactical rules?
html, body, nav, section, article, headings, paragraphs, lists, forms, footers,
etc.
<html>
<head>
<title>My test page</title>
</head>
<body>
⋮
</body>
</html>
<p>
A site where the learned share questions:
<a href="edge.org">edge.org</a>
</p>
/>
.<img src="fun.png" alt="kids playing" />
<message>
<warning>
Hello World
<!--missing </warning> -->
</message>
<message>
<warning>
Hello World
</warning>
</message>
<!ELEMENT message (warning)>
<!ELEMENT warning (#PCDATA)>
jokes, joke, punchline, question, answer, genre
<?xml version="1.0" encoding="UTF-8"?>
<?doctype jokes SYSTEM "jokes.dtd"?>
<jokes>
<joke>
<question>
Why did the chicken cross the road?
</question>
<punchline>
To get to the other side!
</punchline>
</joke>
<joke>
<question>
What did the gold fish say to her mate swimming in a Tank?
</question>
<punchline>
I didn't know you could drive!
</punchline>
</joke>
</jokes>
doctype
and the DTD?<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT jokes (joke+)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT joke (question, punchline)>
<!ELEMENT question (#PCDATA)>
<!ELEMENT punchline (#PCDATA)>
jokes {
font-family: verdana, Courier, mono;
font-size: 48px;
background-color:#CCFFFF;
margin: 40px;
}
joke {
display: block;
background-color:#FFFF99;
border: 2px solid green;
border-radius: 5px;
margin: 1em;
padding: 1em;
}
question {
display: block;
color:#CC0000;
}
punchline {
display: block;
color:#000099;
}
doctype
, browsers correct with "quirk mode"
XHTML
is XML well-formed and valid to a DTD
<p>
Let's use: <span>CSS</span>
</p>
span {
border: 1px solid black;
background-color: red;
}
Let's use: Cascading Style Sheet
<p id="special" class="general">
some content
</p>
p { color: red; }
#special { color: green; }
.general { color: blue; }
class
has higher specificity than element type p
id
has higher specificity than class
/* These styles will style our link in all states */
a {
color: blue;
font-weight: bold;
}
/* declare visited links to be the same
color as non visited links */
a:visited {
color: blue;
}
/* Highlight the link when it is hovered over (mouse over),
activated (mouse down) or focused (keyboard) */
a:hover,
a:active,
a:focus {
color: darkred;
text-decoration: none;
}
/* import another CSS file */
@import "layout.css";
@media (min-width: 801px) {
body {
margin: 0 auto;
width: 800px;
}
}
The CSS box model is the foundation of layout on the Web
Types of CSS boxes (set with disply
property)
For children of the box and complex layout:
<link rel="stylesheet" href="style.css">
<style>
h1 { color: red; }
</style>
<h1 style="color: blue;">Hello World!</h1>
text/html, text/css, text/javascript
image/jpeg, image/png, image/svg+xml
audio/mpeg, audio/vorbis
font/woff, font/ttf
video/mp4, video/ogg
multipart/form-data
audio
and video
elements<audio controls>
<source src="bethoven.mp3" />
<!-- more sources with differnet formats … -->
Your browser does not support the audio element.
</audio>
<video controls="controls">
<source src="earth.ogv" />
<!-- more sources with differnet formats … -->
Your browser does not support the video element.
</video>
<p>CSS is declarative</p>
p { background-color: red; }
CSS is declarative
const myParagraph = document.querySelector("p");
myParagraph.style.color = "black";
myParagraph.style.backgoroundColor = "red";
The internet is a world-wide network of computers that makes the Web possible.
Finding Computers
The aim is to have an overview understanding of Hypertext Transfer Protocol (HTTP). How does HTTP allows for surfing the web? and what are the common security issues on the web?
Create an HTML file and markup the following questions (and answers). Save the file as http_exercise.html
The answers are in the relevant articles in the HTTP tutorials.
get
and post
request.
text/html, text/css, text/javascript
image/jpeg, image/png, image/svg+xml
audio/mpeg, audio/vorbis
font/woff, font/ttf
video/mp4, video/ogg
multipart/form-data
The biggest library humanity has ever created, accessible to a paragraph amongst the trillions of documents growing by the second!
Start wih a review — indicates the JAVA and OO knowlege you should have before starting with Android development.
can you explain static types and methods?
if (true) {
continue with the lab exercises
} else {
Read Introduction to Programming in Java ‐ from MIT
Watch Java Memory Management, video from Virtual Pair Programmers
Think Java is useful as reference
Use the android & stackoverflow search in the header
}
The Introduction to Programming in Java is a good concise reference. See the lecture notes and complete the exercises. This is a minimum needed before attempting to code in any framework such as Android.
See the side panel for Lecture notes and Lab exercises. Complete the lab exercises and read the corresponding articles in the Reading and Lab test preparation.
The code for this exercise can be found at: https://github.com/ebbi/todo-first-app.git
First todo app : MVC, Manifest, Activity, onCreate, View Objects, lifecycle, Listeners, Anonymous functions, event handlers, callbacks, Bundle, Resources
Model
objects, the M in MVC, implement the application logic and the data the logic is applied to. The Todo
app should implement the logic for creating and updating todo lists. For simplicity, in this implementation the data is a simple static-array
defined as a resource; in later exercises, the model logic and data is abstracted into its own model classes.
Android View
objects, the V in MVC, know how to draw themselves on the screen and respond to user input. The layout and the View objects hierarchy are defined in XML and are inflated into View
objects as part of a controller class initialisation.
Controller objects, the C in MVC, (typically, Activity
classes in Android), connect the view and the model objects together by responding to events triggered by View objects and manage the flow of data between the model and the view. A click
on a Button
View object is a common example of an event handled by a controller class.
Android framework lends itself to the MVC architecture and it follows naturally particularly with the view objects and layout being abstracted and separately defined in XML and the Activity
classes controlling the User Interaction(UI) on the view objects. The separation of the Model and the Controller has to follow good programming practice. A controller as its name suggest should only have control logic and delegate all else to model classes.
In Android Studio: Start a new Android Studio project Application Name:Android_todo_first
Company Domain:example.com
(check theproject name
is at the end of the project location pathname.) Next select the option, Phone and Tablet and from the drop-down list, select: API 27: Android 8.1 (Oreo) Next Select Empty Activity Next change the Activity Name toTodoActivity
, keep the defaults Finish Android Studio creates all the necessary files and opens the IDE. Run > Run App Setup or use an existing virtual device, choose Nexus 5X API 27 targeted for Android 8.1 (Google Play) (installing the virtual device may take some time.) Once Android is running, the default 'Hello World!' message is displayed.
This first Todo
prototype cycles through a list of Todos without any further complexity or persistent storage. As such all that is needed is a todos
array which can be stored as a string-array
resource.
todos
string array as a resource
Open the res/values/string.xml
file and replace the resources
XML element with the following:
<resources>
<string name="app_name">Android_todo_first</string>
<string-array name="todos">
<item>Wake up</item>
<item>Drink Coffee</item>
<item>Make at least one person laugh</item>
<item>Plant a tree</item>
<item>Ponder on duality of existance</item>
<item>Go to sleep</item>
</string-array>
</resources>
As part of the build process, the SDK tools generate symbols for each resource, which you can use in your application code to access the resources.
Resources are the additional files and static content that your code uses, such as bitmaps, layout definitions, user interface strings, animation instructions, and more. See: App resources overview
Symbols, app_name
and todos
can now be used as global variables!
The Android View
class represents the basic building block for user interface components. Android provides a set of User Interactive components (button, text fields, etc.) referred to as widgets. View
is the base class for widgets. The View
widgets can be grouped together into invisible container classes known as layouts
.
Android also provides other UI modules for special interfaces such as dialogs, notifications, and menus.
. To get started, read layouts and review Layouts and resources for the UI
Todo
View
The Todo
view definition below is an XML definition of a ConstraintLayout
container that contains the definition of a TextView
widget intended to hold the todo
text and two Button
widgets for next and prev cycling through the todos
.
Open the res/layout/activity_todo.xml
file and replace the content with the following view definition.
Todo
view definition<?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=".TodoActivity">
<TextView
android:id="@+id/textViewTodo"
android:layout_width="330dp"
android:layout_height="336dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="16dp"
android:text="@string/todos"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.515"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.502"
android:layout_marginBottom="16dp"
tools:layout_editor_absoluteY="76dp"/>
<Button
android:id="@+id/buttonPrev"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="176dp"
android:text="@string/prev"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/buttonNext"/>
<Button
android:id="@+id/buttonNext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginEnd="16dp"
android:text="@string/next"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
</android.support.constraint.ConstraintLayout>
Note, the errors, Cannot resolve symbol
for resource names.
To define these resources (constant strings!), open the res/values/string.xml
file and insert the following after the app_name
definition.
<string name="todos">Todos</string>
<string name="next">Next</string>
<string name="prev">Prev</string>
Run the app to see the view.
Android Activity
is the controller class for any view and it's user interaction. For a brief overview, read the first section on activities.
The TodoActivity
class has the default skeleton of an activity controller
class with the default onCreate
method override.
The first call in onCreate
is to the parent onCreate
to complete task such as building the View hierarchy. And second, a call to setContentView(R.layout.activity_todo)
. If this is not clear, please read the first section on activities.
Run the app and remind yourself of the view. The User interaction to be coded is with the click events on the prev
and next
view buttons.
A click event on an object requires a click listener
and a corresponding handler method to respond to the click event. The following implementation reuses the view object setOnClickListener
and an anonymous function to handle the event.
Handling the click event is to override the onClick
event with code to update the textView
object with the current todo
data. Before this, the todo
data has to be retrieved from the string-array
.
Overall logic:
TodoTextView
object for displaying todos
mTodos
, from res/values/strings.xml
mTodos
array in the TodoTextView
buttonNext
to override its setOnClickListener
View.OnClicklistener
function as a handler for the buttonNext.onClickListener
.
onClick
method in the anonymous function to cycle the mTodo
array (checking for the end of array) and update the TodoTextView
with the current todo.
TodoActivity
codepublic class TodoActivity extends AppCompatActivity {
private String[] mTodos;
private int mTodoIndex = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
/* call the super class onCreate to complete the creation
of activity with state changes */
super.onCreate(savedInstanceState);
// set the user interface layout for this Activity
setContentView(R.layout.activity_todo);
// initialize member TextView so we can manipulate it later
final TextView TodoTextView;
TodoTextView = (TextView) findViewById(R.id.textViewTodo);
// read the todo array from res/values/strings.xml
Resources res = getResources();
mTodos = res.getStringArray(R.array.todos);
// display the first task from mTodo array in the TodoTextView
TodoTextView.setText(mTodos[mTodoIndex]);
Button buttonNext;
buttonNext = (Button) findViewById(R.id.buttonNext);
// OnClick listener for the Next button
buttonNext.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
mTodoIndexx += 1;
TodoTextView.setText(mTodos[mTodoIndex]);
}
});
}
}
TodoActivity
class with the code above
Cannot resolve symbol
.
Next
button crashes on the last item in the Todos
array.
Compile time errors are generally to do with syntactical rules and relatively easy to correct. Read the error message (at least twice!) and if it is not clear, search the error message in known sites such as Android Developer API Guides (note, the site has a powerful search) and Stack overflow.
Run time errors are due to inconsistency in the program logic or algorithm. For example, the TodoActivity
runs fine until the index is incremented beyond the last element of the todos
array.
If the run time error message was not immediately clear then the next step is to see the stack trace in the Android Monitor tab (bottom tool bar). There is generally a link with the class name and line number that you could click. This is the last statement that could not be executed.
If examining the stack trace did not resolve the run time error; it is useful to set a debugging break point at the line number the execution stopped.
mTodoIndex
values until it crashes.
TodoActivity
error ArrayIndexOutOfBoundsExceptionThere is a failure in the logic in that the index for the array is incremented without checking for the end of the array. This leads to an attempt to access a non-existent element of the array, hence, ArrayIndexOutOfBoundsException
Correct code that does check for the size of the array:
mTodoIndex = (mTodoIndex + 1) % todos.length;
(Note, % in Java returns the remainder, hence the index will never exceed the array size an alternative less efficient solution would be to test for the size of the array).
To see the rotation problem:
Every instance of an Activity
has a life cycle and transitions between 4 states namely, resumed, paused, stopped and nonexistent with corresponding methods: onCreate, onDestroy, onStart, onStop, onResume
and onPause
. These methods are called life cycle callbacks. We override these callbacks and Android calls the life cycle callbacks at the appropriate time such as after rotating the phone.
Read this overview of Activity lifecycle and state.
The solution to rotation problem is to store the TODO_INDEX
across rotation state changes. On rotating the phone, Android calls the Activity
's callback method onSaveInstanceState(Bundle)
. This method can be overridden and include code to store the TODO_INDEX
.
/* In case of state change, such as rotating the phone,
store the mTodoIndex */
/* override to write the value of mTodoIndex into
the Bundle with TODO_INDEX as its key */
private static final String TODO_INDEX = "todoIndex";
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putInt(TODO_INDEX, mTodoIndex);
}
Once the phone is rotated, Android calls the Activity
's onCreate(Bundle savedInstanceState)
callback method. Note, the Bundle
object savedInstanceState
has the TODO_INDEX, mTodoIndex)
key, value pair. The index can be retrieved in the onCreate
callback method and the correct todo
displayed.
/* check for saved state due to changes such as rotation
and restore any saved state such as the TODO_INDEX */
if (savedInstanceState != null){
mTodoIndex = savedInstanceState.getInt(TODO_INDEX, 0);
}
Run the app, press Next, rotate the phone and the same todo
should display, whereas previously it reset to the first todo
.
Android detects the device configuration change and looks for resources that better match the changed configuration. For views, Android uses a configuration qualifier namely, using -land
suffix in the directory name.
Try the following, to create a new landscape todo
view.
app/src/main/res
res
folder and create a new Directory named, layout-land
layout-land
directory and create a new file named, activity_todo.xml
(the same filename as the portrait view definition)
activity_todo.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=".TodoActivity">
<TextView
android:id="@+id/textViewTodo"
android:layout_width="330dp"
android:layout_height="336dp"
android:layout_marginBottom="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="16dp"
android:text="@string/todos"
android:textColor="@android:color/holo_green_dark"
android:textSize="36sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.515"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.502"
tools:layout_editor_absoluteY="76dp"/>
<Button
android:id="@+id/buttonPrev"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="176dp"
android:text="@string/prev"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.23"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/buttonNext"/>
<Button
android:id="@+id/buttonNext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginRight="16dp"
android:text="@string/next"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
</android.support.constraint.ConstraintLayout>
TodoActivity
Next
button crashing at the end of the Todos
array. (see the Debug section)
Next
, add the code for the Prev
button.
: MVC, Manifest, Activity, onCreate, View Objects, lifecycle, Listeners, Anonymous functions, event handlers, callbacks, Bundle, Resources
manifest
main activity
, walk-through the code showing your understanding of the design and the implementation. How many steps and questions can you write down from the start in manifest
to the view being displayed?
onCreate
callback method
/* call the super class onCreate to complete the creation
of activity with state changes */
super.onCreate(savedInstanceState);
/* set the user interface layout for this Activity */
setContentView(R.layout.activity_todo);
R
?savedInstanceState
and Bundle
?activity_todo
?event
and a similar walk-through the event
handler
The code for this exercise can be found at: https://github.com/ebbi/todo-detail-app.git
Todo detail app : Intent, Extra, Communicating between activities, Static method, MVC, Activity, Intent, View Objects, Listeners, Anonymous functions, event handlers, callbacks, lifecycle, state instances, Bundle
The MVC implementation of a todo list of todos each with a todo detail. In terms of a class diagram, this could be a todolist
activity class associated with a todoDetail
Activity class. To create these classes an intent
communication object is passed from the todoList
activity to the ActivityManger
in Android which returns the intended todoDetail
object. This is after a user event selecting a todo for its details. Consider the following sequence diagram and follow the steps to create a todoDetailApp
.
In Android Studio: Start a new Android Studio project Application Name:todo-detail-app
Company Domain:example.com
(check theproject name
is at the end of the project location pathname.) Next select the option, Phone and Tablet and from the drop-down list, select: API 27: Android 8.1 (Oreo) Next Select Empty Activity Next change the Activity Name toTodoActivity
, keep the defaults Finish Android Studio creates all the necessary files and opens the IDE. Run > Run App Setup or use an existing virtual device, choose Nexus 5X API 27 targeted for Android 8.1 (Google Play) (installing the virtual device may take some time.) Once Android is running, the default 'Hello World!' message is displayed.
A very basic model for testing is an array of todos
with a corresponding array of todo_detail
.
Open the res/values/string.xml
file and replace the resources
XML element with the corresponding content from the git repository.
As part of the build process, the SDK tools generate symbols for each resource, which you can use in your application code to access the resources.
Resources are the additional files and static content that your code uses, such as bitmaps, layout definitions, user interface strings, animation instructions, and more. See: App resources overview
Symbols, app_name
and todos
can now be used as global variables!
The Android View
class represents the basic building block for user interface components. Android provides a set of User Interactive components (button, text fields, etc.) referred to as widgets. View
is the base class for widgets. The View
widgets can be grouped together into invisible container classes known as layouts
.
Android also provides other UI modules for special interfaces such as dialogs, notifications, and menus.
. To get started, read layouts and review Layouts and resources for the UI
TodoDetail
View
The TodoDetail
view definitions have the ConstraintLayout
container that contains the definition of the remainning widgets intended to hold the todos and their details.
Replace the res/layout/
files with the corresponding content from the git repository
Note, the errors, Cannot resolve symbol
for resource names.
To define these resources, replace the res/values/string.xml
file with the corresponding content from the git repository
Run the app to see the view.
TodoActivity
controller has a Todo details button click event and associated onClick handler.
onclick
handler calls a static
method in the TodoDetail
controller, passing it the id of the todo and receiving the intent object.
Intent intent = TodoDetailActivity.newIntent(
TodoActivity.this, mTodoIndex);
startActivityForResult(intent, IS_SUCCESS);
starts the TodoDetailActivity
and any result can be accessed in the TodoActivity
by overriding the onActivityResult
method
TodoActivity
and TodoDetailActivity
classes.
Next
, add the code for the Prev
button.
: Intent, Extra, Communicating between activities, Static method
manifest
main activity
, walk-through the code showing your understanding of the design and the implementation of the todo detail use case. How many steps and questions can you write down from the start in manifest
to the view being displayed?
onCreate
callback method
detail
click event.
onCick
event handler
buttonTodoDetail.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
/* Note, the child class being called has a static method
determining the parameter to be passed to it in the intent
object */
Intent intent = TodoDetailActivity.newIntent(
TodoActivity.this, mTodoIndex);
/* second param requestCode identifies the call as there
could be many "intents" */
startActivityForResult(intent, IS_SUCCESS);
/* The result will come back through */
onActivityResult(requestCode, resultCode, Intent) method */
}
});
newIntent
?todo
index stored?event
and a similar walk-through the event
handler in the detail
view checkbox for completed todos
todo
(similar to checkbox for completed todo)
onActivityResult
The code for this exercise can be found at: https://github.com/ebbi/todo-fragment-app.git
Todo fragment app : MVC, FragmentManager, FragmentTransaction, Fragment, Inflater, View Objects, callbacks
Whilst the Android XML view definition and view objects provide for seperation of the V in MVC, the view remains tightly coupled with the Activity class. This is problematic in principle. The V in MVC needs to be more decoupled and further abstracted so that it could be composed and recomposed as necessary at run time.
It is true that an Activities view may change at run time but the code for the change is inside the activity, hence the tight coupling. To decouple is to abstract the view control code out of the Activity and delegate it to another class. This is achieved in Android with fragments.
A fragment is a controller object that an activity can delegate view management tasks to. The Activity's own view can have a placeholder(s) defined to insert any framgent(s) view. This decoupling allows for views to be dynamically recomposed as the result of device or user requirements and events.
Note in the following class diagram for an example todo fragmnet app:
In Android Studio: Start a new Android Studio project Application Name:todo-fragment-app
Company Domain:example.com
(check theproject name
is at the end of the project location pathname.) Next select the option, Phone and Tablet and from the drop-down list, select: API 27: Android 8.1 (Oreo) Next Select Empty Activity Next change the Activity Name toTodoActivity
, keep the defaults Finish Android Studio creates all the necessary files and opens the IDE. Run > Run App Setup or use an existing virtual device, choose Nexus 5X API 27 targeted for Android 8.1 (Google Play) (installing the virtual device may take some time.) Once Android is running, the default 'Hello World!' message is displayed.
support-v4
which includes fragment support android.support.v4.app.Fragment
support-v7, appcompat-v7, recyclerview-v7
and many moreThe following are brief highlights of the important points (the code can be found at: https://github.com/ebbi/todo-fragment-app.git)
Being a controller class, the TodoFragment sits between the model and the view and supports the getter and setter methods for the data in the view.
The model is currently a Plane Old Java Object(POJO) with the getter and setter methods for the data that represents a Todo. See the Todo.java class.
The data source is abstracted to TodoDS java class. Note, the class has:
private
constructor
public static get
method to return the same TodoModel object instance (simple implementation of Singleton pattern)
Consider the Class diagram
onCreate
has a FragmentManager
FragmentManager
dynamically loads the fragment views within a fragment transaction
onCreateView
uses the inflator
class to create the view objects from the XML definitions
manifest
main activity
, walk-through the code showing your understanding of the design and the implementation of the todo fragment. How many steps and questions can you write down from the start in manifest
to the view being displayed?
inflator
do?
onCreate
and onCreateView
?
TodoModel
(currently not used; see the todo-list-app as an example of (non persistant) CRUD operation for creating and updating todos). Implement CRUD operation use cases.
The code for this exercise can be found at: https://github.com/ebbi/todo-component-app
Todo component app : Vertical and horizontal swipes with RecyclerView and ViewPager, Fragments, Toolbar + Create, Read, Update a todo
view
objects to fill a screen
RecyclerView
relies on an Adapter
with a typical sequence of calls:
getItemCount()
viewHolder
with a call to the adapter's onCreateViewHolder()
viewHolder view
RecyclerView
places the list item on the screenviewHolder
's have been created to fill the screen, they are reusedRecyclerView
& Todo fragmentsRecyclerView
in the onCreateView
methodIn TodoListFragment:
private RecyclerView mTodoRecyclerView;
mTodoRecyclerView = (RecyclerView)
view.findViewById(R.id.todo_recycler_view);
// it will crash without a LayoutManager
mTodoRecyclerView.setLayoutManager(
new LinearLayoutManager(getActivity()) );
Fragments
, RecyclerView
has its own view
hierarchyIn fragment_todo_list.xml:
<?xml version="1.0" encoding="utf-8"?>
<!-- A RecyclerView with some commonly used attributes -->
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/todo_recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" />
ViewHolder
to inflate and fill the layoutIn TodoListFragment:
public class TodoHolder extends RecyclerView.ViewHolder
implements View.OnClickListener {
public TodoHolder(LayoutInflater inflater, ViewGroup parent) {
super(inflater.inflate(
R.layout.list_item_todo, parent, false));
}
}
Adapter
and override three methodsIn TodoListFragment:
public class TodoAdapter extends
RecyclerView.Adapter<TodoListFragment.TodoHolder> {
private List<Todo> mTodos;
public TodoAdapter(List<Todo> todos) {
mTodos = todos;
}
@Override
public TodoListFragment.TodoHolder onCreateViewHolder(
ViewGroup parent, int viewType) {
LayoutInflater layoutInflater =
LayoutInflater.from(getActivity());
return new TodoHolder(layoutInflater, parent);
}
@Override
public void onBindViewHolder(
TodoHolder holder, int position) {
Todo todo = mTodos.get(position);
holder.bind(todo);
}
@Override
public int getItemCount() {
return mTodos.size();
}
}
Seperating creation and binding allows views to be (Recycled) reused
ViewHolder
constructorViewHolder
relies on a bind(data)
method to set the values of views it holds.
TodoModel
constructor and increase the loop to 30 test todos.
The code for this exercise can be found at: https://github.com/ebbi/todo-persistence-app
SQlite
— Create, Read, Update TodoTodo Fragment App
and Todo Component App
examples
From Android Documentation on android.database.sqlite
Caution: Although these APIs are powerful, they are fairly low-level and require a great deal of time and effort to use:
For these reasons, we highly recommended using the Room Persistence Library as an abstraction layer for accessing information in your app's SQLite databases.
package database;
import java.util.Date;
import java.util.UUID;
public class TodoDbSchema {
public static final class TodoTable {
public static final String NAME = "todos";
public static final class Cols {
public static final String UUID = "uuid";
public static final String TITLE = "title";
public static final String DETAIL = "detail";
public static final String DATE = "date";
public static final String IS_COMPLETE = "isComplete";
}
}
}
/* Columns can be refered to in a Java safe way */
TodoDbSchema.Cols.TITLE
SQLiteOpenHelper
class handles building a DBpackage database;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import database.TodoDbSchema.TodoTable;
public class TodoBaseHelper extends SQLiteOpenHelper {
private static final int VERSION = 1;
private static final String DATABASE_NAME = "todo.db";
public TodoBaseHelper(Context context) {
super(context, DATABASE_NAME, null, VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table " + TodoTable.NAME + "(" +
TodoTable.Cols.UUID + ", " +
TodoTable.Cols.TITLE + ", " +
TodoTable.Cols.DETAIL + ", " +
TodoTable.Cols.DATE + ", " +
TodoTable.Cols.IS_COMPLETE + ")"
);
}
@Override
public void onUpgrade(SQLiteDatabase db,
int oldVersion, int newVersion) {
}
}
SQLiteOpenHelper
to create a DBpublic class TodoModel {
private static TodoModel sTodoModel;
private static Context mContext;
private SQLiteDatabase mDatabase;
public static TodoModel get(Context context) {
mContext = context.getApplicationContext();
if (sTodoModel == null) {
sTodoModel = new TodoModel(context);
}
return sTodoModel;
}
private TodoModel(Context context){
mContext = context.getApplicationContext();
mDatabase = new TodoBaseHelper(mContext)
.getWritableDatabase();
}
/* insert seed test data */
}
⋮
ContentValues
class to store key/value maps/* Model static method for ContentValues */
private static ContentValues getContentValues(Todo todo) {
ContentValues contentValues = new ContentValues();
contentValues.put(
TodoDbSchema.TodoTable.Cols.UUID, todo.getId().toString());
contentValues.put(
TodoDbSchema.TodoTable.Cols.TITLE, todo.getTitle());
contentValues.put(
TodoDbSchema.TodoTable.Cols.DETAIL, todo.getDetail());
contentValues.put(
TodoDbSchema.TodoTable.Cols.DATE, todo.getDate().getTime());
contentValues.put(
TodoDbSchema.TodoTable.Cols.IS_COMPLETE, todo.isComplete()==1 ? 1 : 0);
return contentValues;
}
public void addTodo(Todo todo){
ContentValues contentValues = getContentValues(todo);
/* contentValues = null raises an exception except
when 2nd parameter is null in which case a new row is inserted */
mDatabase.insert(TodoDbSchema.TodoTable.NAME, null, contentValues);
}
public void updateTodo(Todo todo){
String uuidString = todo.getId().toString();
ContentValues contentValues = getContentValues(todo);
/* stop sql injection, pass uuidString to new String
so, it is treated as string rather than code */
mDatabase.update(TodoDbSchema.TodoTable.NAME, contentValues,
TodoDbSchema.TodoTable.Cols.UUID + " = ?",
new String[] { uuidString });
}
SQLiteDatabase.query()
has many overloads
corresponding to a SQL query SELECT columns FROM Table WHERE wherArgs GROUPBY, HAVING, ORDERBY, LIMIT
.
SQLiteDatabase.query()
returns a cursor
object Cursor cursor = mDatabase.query(TodoDbSchema.TodoTable.NAME, … )
Cursor
interface provides random read-write access to the result set returned by a database query.cursor.getColumnIndex(TodoDbSchema.TodoTable.Cols.TITLE));
CursorWrapper
to subclass Cursor
public class TodoCursorWrapper extends CursorWrapper {
public TodoCursorWrapper(Cursor cursor){
super(cursor);
}
public Todo getTodo() {
String uuidString = getString(
getColumnIndex(TodoDbSchema.TodoTable.Cols.UUID));
String title = getString(
getColumnIndex(TodoDbSchema.TodoTable.Cols.TITLE));
String detail = getString(
getColumnIndex(TodoDbSchema.TodoTable.Cols.DETAIL));
Long date = getLong(
getColumnIndex(TodoDbSchema.TodoTable.Cols.DATE));
int isComplete = getInt(
getColumnIndex(TodoDbSchema.TodoTable.Cols.IS_COMPLETE));
Todo todo = new Todo(UUID.fromString(uuidString));
todo.setTitle(title);
todo.setDetail(detail);
todo.setDate(new Date(date));
todo.setComplete(isComplete);
return todo;
}
}
select
(Read) using TodoCursorWrapper
private TodoCursorWrapper queryTodoList(
String whereClause, String[] whereArgs) {
Cursor cursor = mDatabase.query(
TodoDbSchema.TodoTable.NAME, null, whereClause, whereArgs, …
);
return new TodoCursorWrapper(cursor);
}
TodoCursorWrapper
public Todo getTodo(UUID id){
TodoCursorWrapper cursor = queryTodoList(
TodoDbSchema.TodoTable.Cols.UUID + " = ?",
new String[] {id.toString() }
);
try {
if (cursor.getCount() == 0) {
return null;
}
cursor.moveToFirst();
return cursor.getTodo();
} finally {
cursor.close();
}
}
TodoCursorWrapper
public List<Todo> getTodoList() {
List<Todo> todoList = new ArrayList<>();
TodoCursorWrapper cursor = queryTodoList(null, null);
try {
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
todoList.add(cursor.getTodo());
cursor.moveToNext();
}
} finally {
cursor.close();
}
return todoList;
}
SQLiteOpenHelper
change the version number and update the tables in the onUpgrade
method
SQLiteOpenHelper.onCreate()
is called and a new database instance is created).SQL
statement for correct syntax.
The Room persistence library provides an abstraction layer over SQLite to allow for more robust database access while harnessing the full power of SQLite.
The code for this exercise can be found at: https://github.com/ebbi/TodoMVVM
MVVM is the Android recommended architecture. This lab exercise is an MVVM implementation of the Todo app.
MVVM is the Android recommended app architecture built arround a set of Architecture Components designed to work together. The components are lifecycle aware and make code design, implementation and maintenance much easier to manage.
Entity
Room
ORM classSQLite
databaseRoom
persistence library on its own threadDAO
SQL
queriesRoom
databaseDAO
to issue queries to the SQLite
database ( and thnkfully, hides SQLiteOpenHelper
)Repository
Repository
is also used to manage multiple data sources.ViewModel
Repository
and the UI. ViewModel
instances survive Activity
/Fragment
recreation.LiveData
LiveData
is aware of the relevant lifecycle status changes while observing.Fragment
transactions and seperation of concerns is achieved with ViewModel
and LiveData
implementing the observer pattern.
ViewModel
allows data to survive accross process rather than Activity
lifecycle, hence, configuration changes (such as screen rotations) are easier to manage.
LiveData
implements the observer pattern and is an observable data-holder class and a lifecycle aware component. UI Controllers can observe relevant data and LiveData
can notify them of data changes. This allows for views to be built only when actual changes to data occurs.
The Room
persistency library provides ORM and makes it easy to build a local cache layer, improving performance and the user experience with less reliance on data pulled from the network.
Create a new empty project named, TodoMVVM
API 27: Android 8.1 (Oreo)
Virtual Device: Nexus 5X API 27
Edit build.gradle (Project: TodoMVVM) and add:
ext {
roomVersion = '2.2.1'
archLifecycleVersion = '2.2.0-rc01'
coreTestingVersion = '2.1.0'
materialVersion = '1.0.0'
}
Edit build.gradle (Module: TodoMVVM) for dependencies
(insert at the end of the dependencies block, before the } )
// Room components
implementation "androidx.room:room-runtime:$rootProject.roomVersion"
annotationProcessor "androidx.room:room-compiler:$rootProject.roomVersion"
androidTestImplementation "androidx.room:room-testing:$rootProject.roomVersion"
// Lifecycle components
implementation "androidx.lifecycle:lifecycle-extensions:$rootProject.archLifecycleVersion"
annotationProcessor "androidx.lifecycle:lifecycle-compiler:$rootProject.archLifecycleVersion"
// UI
implementation "com.google.android.material:material:$rootProject.materialVersion"
// Testing
androidTestImplementation "androidx.arch.core:core-testing:$rootProject.coreTestingVersion"
Sync Now (in Android Studio, top right corner)
Do not proceed unless the Sync completes without errors!
Entity
An entity
is an annotated class that describes a database table. Room uses the properties of this entity class to create columns in the database table. The same entity
is used to instantiate objects from rows of data in the database.
Create a new class file named Todo
and insert the following code:
Todo
entityimport androidx.annotation.NonNull;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
/**
* A basic class representing a two-column todo_database table.
*
* @ Entity - annotate the class as an entity and supply a table name if not class name.
* @ PrimaryKey - identify the primary key.
* @ ColumnInfo - supply the column name if it is different from the variable name.
*
* See the documentation for the full set of annotations.
* https://developer.android.com/topic/libraries/architecture/room.html
*/
@Entity(tableName = "todo_table")
public class Todo {
@PrimaryKey
@NonNull
@ColumnInfo(name = "title")
private String mTitle;
private String mDetail;
public Todo(@NonNull String title) {
this.mTitle = title;
}
public String getTitle() {
return this.mTitle;
}
String getDetail() {
return this.mDetail;
}
void setDetail(String mDetail) {
this.mDetail = mDetail;
}
}
The class is a POJO with a set of attributes representing the database columns and getter, setter methods. Note the annotations identify how each part of this class relates to an entry in the database. Room
uses this information to generate code.
@Entity(tableName = "todo_table")
@Entity
class represents a SQLite table. The parameter tablename
can optionally set a different name than the default name of the class.@PrimaryKey
tittle
is the primary key.@NonNull
@ColumnInfo(name = "title")
getTitle()
and getDetail()
methods.The complete list of annotations can be found in the Room package summary reference. And see Defining data using Room entities for further examples uses of annotations.
API and dependancies are now setup, Run to make sure there are no errors Create a git branch, entity add code for Todo Git checkout master and merge entity branch Create a git branch, dao add code for TodoDao Git checkout master and merge entity branch Create a git branch, room add code for TodoRoomDatabase Git checkout master and merge room branch
The Room persistence library provides an abstraction layer over SQLite to allow for more robust database access while harnessing the full power of SQLite.
The Introduction to Programming in Java is a good concise reference. See the lecture notes and complete the exercises. This is a minimum needed before attempting to code in any framework such as Android.
static
types and methods?if (true) { continue to lab exercises } else { Read Introduction to Programming in Java ‐ from MIT Watch Java Memory Management, video from Virtual Pair Programmers Think Java is a good online reference book Use the android & stackoverflow search in the header }
Thread
is a sequence of instructions that can be managed independantly by a scheduler
Thread
s a Hello World exampleRunnable Interface
public void
with no argumentspublic void run()
Thread
) World (on another Thread
)public class ThreadDemo {
public static void main(String args[]) {
System.out.println("Hello (on a thread) World (on another thread)!");
/* annoymous class implementing Runnable interface run()
method passed to Runnable */
Runnable objHello = new Runnable() {
public void run() {
for(int i=1; i<=5; i++) {
System.out.println("Hello ");
/* do some nice processing! */
try { Thread.sleep(1000); } catch(Exception e){}
}
}
};
Runnable objWorld = new Runnable() {
/* annoymous class with run() method passed to Runnable */
public void run() {
for(int i=1; i<=5; i++) {
System.out.println("World");
try { Thread.sleep(3000); } catch(Exception e){}
}
}
};
Thread threadHello = new Thread(objHello);
Thread threadWorld = new Thread(objWorld);
threadHello.start();
try { Thread.sleep(1000); } catch(Exception e){}
threadWorld.start();
// System.out.println(threadHello.isAlive());
// try { threadHello.sleep(1000); } catch(Exception e){}
/* .join will force the calling thread to wait until it complete */
// try { threadHello.join(); } catch(Exception e){}
// try { threadWorld.join(); } catch(Exception e){}
/* check if method is alive after join */
System.out.println(threadHello.getName() + " " + threadHello.isAlive());
System.out.println(threadWorld.getName() + " " + threadWorld.isAlive());
System.out.println("Time for poetry");
}
}
Thread
s a Hello World Synchronised exampleRunnable Interface
public void
with no argumentspublic void run()
Thread
class DoWork {
/* Class to run in a thread
Simulate the load by the number of calls to increment */
int count;
/* needs to be synchronized and made thread safe */
public synchronized void increment() {
count++; // increment is more than one operation!
}
}
public class SyncDemo {
public static void main(String args[]) {
System.out.println("Synchronised value from both Hello and World threads");
DoWork doWork = new DoWork();
/* annoymous class implementing Runnable interface run()
method passed to Runnable */
Runnable objHello = new Runnable() {
public void run() {
for(int i=1; i<=1000; i++) {
doWork.increment();
}
System.out.println( doWork.count + " Hello ");
}
};
Runnable objWorld = new Runnable() {
public void run() {
for(int i=1; i<=1000; i++) {
doWork.increment();
}
System.out.println( doWork.count + " World ");
}
};
Thread threadHello = new Thread(objHello);
Thread threadWorld = new Thread(objWorld);
threadHello.start();
threadWorld.start();
/* .join will force the calling thread to wait until it complete */
// try { threadHello.join(); } catch(Exception e){}
// try { threadWorld.join(); } catch(Exception e){}
System.out.println(doWork.count + " reminders for poetry");
}
}
It is worth while investing time to know git; version control and collaboration is essential.
Use an existing account to signin OR create a new account on Github or Bitbucket.
(Note: You must complete the account creation by email verification.)
Once signed in to the remote repo (Github or Bitbucket), creat a new repository. (for the Repository name, use the project name) and leave the rest as default.
Once the remote repository is created, instructions to add this remote repository (or origin) to the local git repository is displayed.
echo "# insert name of the project" >> README.md
git init
git add .
git commit -am "first commit"
git remote add origin (insert the repo address)
git push -u origin master
Note: repo address is similar to:
https://github.com/you!/your_project_name!.git
A typical workflow to create a branch, try changes, and either delete or merge the changes
Create a new empty folder. Use a terminal and change directory (cd) to the folder. Edit a test file with a message, "Hello World" and save it.
git init
git status
git add .
git commit -am "initial setup"
git status
git log
git branch xyz
git checkout xyz
git status
git log
Edit the test file and add a message "Happy World!" and also duplicate the file
To reverse the changes:
git add .
git reset --hard HEAD
git status
Note the change have been reversed.
To commit the changes and merge it to the master branch:
git status
git add .
git commit -am "added happy and duplicated test file"
git checkout master
git merge xyz
git status
git log
Note, status
and log
are for information only.
git branch
‐ lists all branches
git push origin master
‐ copies the current master to the remote repo
ActivityManager
in the OS is in charge, not You!
Activity
class is the entry point for UI
main
thread? and is it MVC?
hello world
manifest
file<activity android:name=".HelloWorld">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
HelloWorldActivity
public class HelloWorldActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
/* call the super class onCreate to complete
the creation of Activity, such as the view hierarchy */
super.onCreate(savedInstanceState);
/* set the user interface layout for this Activity */
setContentView(R.layout.activity_helloWorld);
}
}
view
definition<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
…
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".HelloWorldActivity">
<TextView
android:id="@+id/textViewMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/message_text"
app:layout_constraintBottom_toBottomOf="parent"
… />
</android.support.constraint.ConstraintLayout>
and a file strings.xml in the res folder defines:
<resources>
<string name="message_text">Hello World</string>
…
<resources>
Hello World
walk-through?
@override
and callback
function?
Activity
life cycle related to callback
functions? Explain with rotation event as an example.Activity
and Intent
Activity
and Intent
Activity
— a single screen in an app
Intent
— a message object to start an activity
Activity
and Intent
communicate via the OS ActivityManager
Activity
in one App to use Activity
in another App
Activity
Activity
Activity
in onCreate()
callback
setContentView( findViewById( R.layout.activity_example )
onSaveInstanceState( Bundle )
onPause()
called when user leaves the activity
— serialise
Activity
in AndroidManifest.xml
Activity
state, persistance, & lifecycle
Activity
has four statesactive
(or running at the top of the activity stack)
paused
— alive in memeory, visible, lost focus
stopped
— obscured by another activity, alive im memory, not visible
paused
or stopped
— may lead to destroyed
& restarted
to previous state
Activity
‐ three key loopsonCreate
to onDestroy
onStart
to onStop
onResume
to onPause
Source code: https://github.com/ebbi/helloToast
@Override
protected void onCreate(Bundle savedInstanceState) {
...
Log.d(LOG_TAG, "-------");
Log.d(LOG_TAG, "onCreate");
...
}
@Override
public void onSaveInstanceState(Bundle outState) {
Log.d(LOG_TAG, "onSaveInstanceState");
...
}
@Override
public void onStart(){
super.onStart();
Log.d(LOG_TAG, "onStart");
}
@Override
protected void onPause() {
super.onPause();
Log.d(LOG_TAG, "onPause");
}
@Override
protected void onRestart() {
super.onRestart();
Log.d(LOG_TAG, "onRestart");
}
@Override
protected void onResume() {
super.onResume();
Log.d(LOG_TAG, "onResume");
}
@Override
protected void onStop() {
super.onStop();
Log.d(LOG_TAG, "onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(LOG_TAG, "onDestroy");
}
Bundle
key, value pairs
Source code: https://github.com/ebbi/helloToast
@Override
protected void onCreate(Bundle savedInstanceState) {
...
// Restore the state.
if (savedInstanceState != null) {
mCount = savedInstanceState.getInt("count");
mShowCount.setText(String.valueOf(mCount));
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("count", mCount);
}
Lifecycle
class & observer patternevents
— enumeration from framework and lifecycle
class
lifecycle
class events map to callback
methods
lifecycle
object
LifecycleObserver
allows for lifecycle-aware components (observer pattern to monitor lifecycle status)
Intent
Intent
— messaging object to request an action from another app component
Intent
— a passive data structure that holds an abstract description of an operation to be performed
Intent
constructorsIntent()
Intent( String action )
Intent( String action, URI uri )
Intent( Context context, Class<?>cls )
Intent( String action, Context packageContext, Class<?>cls )
Intent
examplessetAction(), putExtra, addCategory(), …
Intent
— action is defined, target component is unkownIntent intent = new Intent();
intent.setAction( Intent.ACTION_WEB_SEARCH );
intent.putExtra( SearchManager.QUERY,"search text" );
Intent browserIntent = new Intent(
Intent.ACTION_VIEW,
Uri.parse( "http://www.ecosia.com" )
);
browserIntent.addCategory( CATEGORY_BROWSABLE );
Intent
— target component is knownIntent intent = new Intent(
packageContext, ExampleActivity.class
);
intent.putExtra( "EX1","example value" );
intent.putExtra( "EX2","example value" );
late runtime binding between the code in different applications
intent
be instantiated?"from each according to their ability, to each according to their need"
Activity
has the Intent
data
Activity
uses the Intent
data
static
method in called Activity
public static Intent newIntent(
Context packageContext, int todoIndex){
Intent intent = new Intent(
packageContext, TodoDetailActivity.class);
intent.putExtra(TODO_INDEX,todoIndex);
return intent;
}
The calling activity:
Intent intent =
TodoDetailActivity.newIntent(TodoActivity.this, mTodoIndex);
Intent
result back
Activity
method startActivityForResult(Intent, requestCode)
startActivityForResult(Intent intent, int requestCode);
@Override
public void onClick(View v) {
Intent intent = TodoDetailActivity.newIntent(
TodoActivity.this, mTodoIndex);
// requestCode = int constant for a single activity
startActivityForResult(intent, IS_SUCCESS);
}
Activity
implement two method for setting results
setResult(int resultCode);
setResult(int resultCode, Intent intent);
resultCode
, is Activity.RESULT_OK
or Activity.RESULT_CANCELED
extras
in intent
for more data
Intent intent = new Intent();
intent.putExtra(IS_TODO_COMPLETE, isChecked);
setResult(RESULT_OK, intent);
Callback onActivityResult()
to retrieve any set result.
@Override
protected void onActivityResult(
int requestCode, int resultCode, Intent intent) {
if (intent != null) {
// data in intent from child activity
boolean isTodoComplete =
intent.getBooleanExtra(IS_TODO_COMPLETE, false);
…
}
}
interface
in the View
class that contains a single callback method
View.OnClickListener onClick()
View.OnLongClickListener onLongClick()
View.OnFocusChangeListener OnFocusChangeListener
View.OnKeyListener OnKeyListener()
View.OnTouchListener OnTouchListener()
View.OnCreateContextMenuListener OnCreateContextMenuListener()
View.onClickListener
fires an event that results in the corresponding event handler, onClick
call back method being called.
private
data conveniently available to anonymous inner class
listener
for each view
object
buttonNext.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
// do something when the button is clicked
}
});
interface
in the class definitionpublic class ActivityMain extends Activity
implements View.OnClickListener {
protected void onCreate(Bundle savedValues) {
…
Button button = (Button)findViewById(R.id.next);
button.setOnClickListener(this);
}
@Override
public void onClick(View view) {
// do something when the button is clicked
{
…
}
interface
for any view objects/* Create an anonymous implementation of OnClickListener
for all clickable view objects */
private View.OnClickListener mTodoListener =
new View.OnClickListener() {
public void onClick(View v) {
// get the clicked object and do something
switch (v.getId() {
case R.id.checkBoxIsComplete:
default:
break;
}
}
};
And the usage would be:
CheckBox checkboxIsComplete =
(CheckBox)findViewById(R.id.checkBoxIsComplete);
checkboxIsComplete.setOnClickListener(mTodoListener);
/*
listener implementation with the method name
defined in the view definition
*/
android:onClick = "onCheckboxIsCompleteClick"
with Activity method:
public void onCheckboxIsCompleteClick(View view) { … }
Activity
& View
Fragment
represents a behavior or a portion of user interface, has its own lifecycle, receives its own input events, and can be added or removed while the activity is running
support-v4
library includes fragment support
support-v7, appcompat-v7, recyclerview-v7
etc.FragmentManager
View
decoupled by delegating UI to Fragment
Activity
uses placeholder views for fragments
Activity
uses a FragmentManager
to dynamically add and remove Fragments
from Views
in a fragmentManager transaction
.
FragmentManager
transactions can change fragment combinations for different screen sizes
fragment
lives in a ViewGroup inside the activity's view hierarchy and affected by the Activity
lifecycle
Fragment
LifecycleonCreate()
initialize components of the fragment to retain when the fragment is paused or stopped, then resumed
onCreateView()
called for fragment to draw its user interface and return a view
onPause()
first indication user is leaving the fragment; persist session data
startActivityForResult()
is Fragment.startActivityForResult()
Activity.onActivityResult()
overide Fragment.Activity.onActivityResult()
Fragment
setResult, only Activity has Activity.setResult()
getActivity
method to access the parent Activity's intent data directly leads to coupling. getActivity().setResult(Activity.RESULT_OK, null);
Activity
Static method to bundle any arguments and return the fragmentFrameLayout
and remains the same throughout the lifecycle
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
fragments
to the activity's layout ‐ avoid coupling!
public class TodoFragment extends Fragment {
private Todo mTodo;
private CheckBox mCheckBoxIsComplete;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
mTodo = new Todo();
}
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(
R.layout.fragment_todo, container, false);
mCheckBoxIsComplete = (CheckBox)
view.findViewById(R.id.todo_complete);
mCheckBoxIsComplete.setOnCheckedChangeListener(
new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(
CompoundButton buttonView, boolean isChecked) {
mTodo.setComplete(isChecked);
}
});
return view;
}
}
Activity.onCreate
had protected
scope, Fragment.onCreate
is public
(reusable by any activity)
setContentView()
is no longer called in the onCreate
methodonCreateView()
explicitly inflates the fragment's view: inflater.inflate(R.layout.fragment_todo, container, false)
false
parameter indcates the host Activity will add the fragment)
int
reference; view.findViewById(R.id.todo_complete)
fragment
in any activity
public class TodoActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment);
FragmentManager fm = getSupportFragmentManager();
Fragment fragment =
fm.findFragmentById(R.id.fragment_container);
if (fragment == null){
Fragment todoFragment = new TodoFragment();
fm.beginTransaction()
.add(R.id.fragment_container, todoFragment)
.commit();
}
}
…
FragmentManger
keeps a Back stack of FragmentTransactions
that can be navigated and a list of Fragments
.FragmentTransactions
are used to add, remove, attach, detach
or replace
fragments.FragmentManager.beginTransaction
creates and returns an instance of FragmentTransaction
and not void
, hence it can be chained together..add
method has two parameters, the container view ID and a fragment
. The ID serves two purposes:
fragment
should appear.fragment
in the FragmentManager
list
Why check for null
?
fragment
may already be in the in the FragmentManager
list due to events such as destoyed on rotation or to reclaim memory.
What happens if the Activity
has resumed and a Fragment
is added?
FragmentManager
calls all the necessary methods to synchronise with the Activity
state.
onAttach(Context), onCreate(Bundle), onCreateView(…), onActivityCreated(Bundle), onStart()
and onResume
.
getActivity
method to access the parent Activity's intent data directly leads to coupling
fragment
leads to decoupling as any activity can pass its data and receive the fragment
In TodoFragment
public static TodoFragment newInstance(UUID todoId) {
Bundle args = new Bundle();
args.putSerializable(ARG_TODO_ID, todoId);
TodoFragment fragment = new TodoFragment();
fragment.setArguments(args);
return fragment;
}
/*
Any Activity (such as TodoActivity) can
call the static method and pass it's intent data
to be bundles and recieve the decoupled fragment
*/
protected Fragment createFragment(){
UUID todoId = (UUID) getIntent()
.getSerializableExtra(EXTRA_TODO_ID);
return TodoFragment.newInstance(todoId);
}
The same pattern was applied to decouple
intents with data being passed and a static
method returns the intent.
In TodoListFragment
public void onClick(View view) {
Intent intent = TodoActivity
.newIntent(getActivity(), mTodo.getId());
startActivity(intent);
}
and in TodoActivity:
public static Intent newIntent(
Context packageContext, UUID todoId) {
Intent intent = new Intent(packageContext,
TodoActivity.class);
intent.putExtra(EXTRA_TODO_ID, todoId);
return intent;
}
singleton
provides a simple implementation
public class TodoDS {
private static TodoDS sTodoDS;
private List<Todo> mTodoList;
public static TodoDS get(Context context) {
if (sTodoDS == null) {
sTodoDS = new TodoDS(context);
}
return sTodoDS;
}
private TodoDS(Context context){
mTodoList = new ArrayList<>();
// simulate some data for testing
for (int i=0; i < 3; i++){
Todo todo = new Todo();
todo.setTitle("Todo title " + i);
todo.setIsComplete(false);
mTodoList.add(todo);
}
}
public Todo getTodo(UUID todoId) {
for (Todo todo : mTodos) {
if (todo.getId().equals(todoId)){
return todo;
}
}
return null;
}
public List<Todo> getTodos() {
return mTodoList;
}
}
And the Todo
class
public class Todo {
private UUID mId;
private String mTitle;
private boolean mIsComplete;
public Todo() {
mId = UUID.randomUUID();
mDate = new Date();
}
public UUID getId() {
return mId;
}
public void setId(UUID id) {
mId = id;
}
public String getTitle() {
return mTitle;
}
public void setTitle(String title) {
mTitle = title;
}
}
ViewModel
retrieve data from model when requested from the viewActivities/Fragments
become very light weightViewModel
are decoupled from the viewViewModel
have process scopePresenter
calls the view to display
ViewModel
exposes stream of events for Views
to bind to. No need for all the MVP interfaces.
Observable
(Java 9 deprecated Observable)