0% found this document useful (0 votes)
4 views264 pages

Android Development

The document provides an overview of Android, an open-source mobile operating system developed by Google and the Open Handset Alliance, detailing its features, architecture, and core components. It explains the Android software stack, including the Linux kernel, Android Runtime, and application framework, as well as the fundamental building blocks of Android applications such as activities, services, and content providers. Additionally, it covers the Android Virtual Device (AVD) for testing applications and the process of creating a simple Android application using Android Studio.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
0% found this document useful (0 votes)
4 views264 pages

Android Development

The document provides an overview of Android, an open-source mobile operating system developed by Google and the Open Handset Alliance, detailing its features, architecture, and core components. It explains the Android software stack, including the Linux kernel, Android Runtime, and application framework, as well as the fundamental building blocks of Android applications such as activities, services, and content providers. Additionally, it covers the Android Virtual Device (AVD) for testing applications and the process of creating a simple Android application using Android Studio.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 264

Chapter One

1. Introduction

1.1 . What is Android


Android is open-source software packages and Linux based operating system for mobile devices such as tablet
computers and smartphones. And also, it is a mobile operating system based on a modified version of the Linux
kernel and other open source software, designed primarily for touchscreen mobile devices such as smartphones
and tablets. Hence, Android is developed by a consortium of developers known as the Open Handset Alliance,
with the main contributor and commercial marketer being google.

Therefore, it is developed by Google and later the OHA (Open Handset Alliance) which means a consortium of
84 companies such as google, samsung, AKM, synaptics, KDDI, Garmin, Teleca, Ebay, Intel etc. It was
established on 5th November, 2007, led by Google. It is committed to advance open standards, provide services
and deploy handsets using the Android Plateform. Java language is mainly used to write the android code even
though other languages can be used.

The first beta version of the Android Software Development Kit (SDK) was released by Google in 2007 where as
the first commercial version, Android 1.0, was released in September 2008.

On June 27, 2012, at the Google I/O conference, Google announced the next Android version, 4.1 Jelly Bean.
Jelly Bean is an incremental update, with the primary aim of improving the user interface, both in terms of
functionality and performance.

1.2 . Android features


The important features of android are given below:

1. It is open-source.

2. Anyone can customize the Android Platform.

3. There are a lot of mobile applications that can be chosen by the consumer.

4. It provides many interesting features like weather details, opening screen, live RSS (Really Simple
Syndication) feeds etc.
It provides support for messaging services(SMS and MMS), web browser, storage (SQLite), connectivity (GSM,
CDMA, Blue Tooth, Wi-Fi etc.), media, handset layout etc.

1.3 . Android Stack


Android is an open source, Linux-based software stack created for a wide array of devices and form factors. The
following diagram shows the major components of the Android platform. Let's see the android architecture first.

Fig 1: The Android


software stack.

Android architecture or Android software stack is categorized into five parts:


1. Linux kernel
2. Native libraries (middleware),
3. Android Runtime
4. Application Framework
i. The Linux Kernel
At the bottom of the layers the foundation of the Android platform is the Linux kernel. This provides a level of
abstraction between the device hardware and it contains all the essential hardware drivers like camera, keypad,
display etc. Also, the kernel handles all the things that Linux is really good at such as networking and a vast
array of device drivers, which take the pain out of interfacing to peripheral hardware.. For example, the Android
Runtime(ART) relies on the Linux kernel for underlying functionalities such as threading and low-level memory
management.

Using a Linux kernel allows Android to take advantage of keys security features and allows device
manufacturers to develop hardware drivers for a well-known kernel.

ii. Hardware Abstraction Layer (HAL)


The Hardware Abstraction Layer(HAL) provides standard interfaces that expose device hardware capabilities to
the higher-level Java API framework. The HAL consists of multiple library modules, each of which implements
an interface for a specific type of hardware component, such as the camera or Bluetooth module. When a
framework API makes a call to access device hardware, the Android system loads the library module for that
hardware component.

A summary of some key core Android libraries available to the Android developer is as follows −

l android.app − Provides access to the application model and is the cornerstone of all Android
applications.

l android.content − Facilitates content access, publishing and messaging between applications and
application components.

l android.database − Used to access data published by content providers and includes SQLite database
management classes.

l android.opengl − A Java interface to the OpenGL ES 3D graphics rendering API.

l android.os − Provides applications with access to standard operating system services including
messages, system services and inter-process communication.

l android.text − Used to render and manipulate text on a device display.

l android.view − The fundamental building blocks of application user interfaces.


l android.widget − A rich collection of pre-built user interface components such as buttons, labels, list
views, layout managers, radio buttons etc.

l android.webkit − A set of classes intended to allow web-browsing capabilities to be built into


applications.

Having covered the Java-based core libraries in the Android runtime, it is now time to turn our attention to the
C/C++ based libraries contained in this layer of the Android software stack.

iii. Android Runtime and Native c++ Libraries


This is the third section of the architecture and available on the second layer from the bottom. This section
provides a key component called Dalvik Virtual Machine which is a kind of Java Virtual Machine specially
designed and optimized for Android.

The Dalvik VM makes use of Linux core features like memory management and multi-threading, which is
intrinsic in the Java language. The Dalvik VM enables every Android application to run in its own process, with
its own instance of the Dalvik virtual machine.

The Android runtime also provides a set of core libraries which enable Android application developers to write
Android applications using standard Java programming language.

For devices running Android version 5.0 (API level 21) or higher, each app runs in its own process and with its
own instance of the Android Runtime(ART). ART is written to run multiple virtual machines on low-memory
devices by executing DEX files, a bytecode format designed specially for Android that's optimized for minimal
memory footprint. Build toolchains, such as Jack, compile Java sources into DEX bytecode, which can run on
the Android platform.

Some of the major features of ART include the following:

l Ahead-of-time (AOT) and just-in-time (JIT) compilation


l Optimized garbage collection (GC)
l On Android 9 (API level 28) and higher, conversion of an app package's Dalvik Excitable format(DEF)
files to more compact machine code.
l Better debugging support, including a dedicated sampling profiler, detailed diagnostic exceptions and
crash reporting, and the ability to set watchpoints to monitor specific fields
Prior to Android version 5.0 (API level 21), Dalvik was the Android runtime. If your app runs well on ART, then
it should work on Dalvik as well, but the reverse may not be true.

Android also includes a set of core runtime libraries that provide most of the functionality of the Java
programming language, including some Java 8 language feature, that the Java API framework uses.

Native C/C++ Libraries


Many core Android system components and services, such as ART and HAL, are built from native code that
require native libraries written in C and C++. The Android platform provides Java framework APIs to expose the
functionality of some of these native libraries to apps. For example, you can access OpenGL ES through the
Android framework’s Java OpenGL API to add support for drawing and manipulating 2D and 3D graphics in
your app.

If you are developing an app that requires C or C++ code, you can use the Android NDK to access some of these
native platform libraries directly from your native code.

iv. Java API Framework


The entire feature-set of the Android OS is available to you through APIs written in the Java language. These
APIs form the building blocks you need to create Android apps by simplifying the reuse of core, modular system
components and services, which include the following:

l A rich and extensible View System you can use to build an app’s UI, including lists, grids, text boxes,
buttons, and even an embeddable web browser
l A Resource Manager , providing access to non-code resources such as localized strings, graphics, and
layout files
l A Notfication Manager that enables all apps to display custom alerts in the status bar
l An Activity Manager that manages the lifecycle of apps and provides a common navigation back stack
l Content Provider that enable apps to access data from other apps, such as the Contacts app, or to share
their own data

Developers have full access to the same framework APIs that Android system apps use.

v. System Apps
Android comes with a set of core apps for email, SMS messaging, calendars, internet browsing, contacts, and
more. Apps included with the platform have no special status among the apps the user chooses to install. So a
third-party app can become the user's default web browser, SMS messenger, or even the default keyboard (some
exceptions apply, such as the system's Settings app).

The system apps function both as apps for users and to provide key capabilities that developers can access from
their own app. For example, if your app would like to deliver an SMS message, you don't need to build that
functionality yourself you can instead invoke whichever SMS app is already installed to deliver a message to the
recipient you specify.

The Application Framework layer provides many higher-level services to applications in the form of Java
classes. Application developers are allowed to make use of these services in their applications.
The Android framework includes the following key services −

l Activity Manager − Controls all aspects of the application lifecycle and activity stack.

l Content Providers − Allows applications to publish and share data with other applications.

l Resource Manager − Provides access to non-code embedded resources such as strings, color settings and
user interface layouts.

l Notifications Manager − Allows applications to display alerts and notifications to the user.

l View System − An extensible set of views used to create application user interfaces.

1.4 . Android Core Building Blocks


An android component is simply a piece of code that has a well defined life cycle e.g. Activity, Receiver,
Service etc. The core building blocks or fundamental components of android are activities, views, intents,
services, content providers, fragments and AndroidManifest.xml.

The basic components of any android application are as follows:

l Activities
l Services
l Broadcast Receivers
l Content Providers

1.4.1 . Activities
An activity is a class that represents a single screen. It is like a Frame in AWT or Swing in java. Since almost all
activities interact directly with the user, it is often helpful to think of an activity as the screen for a particular
action, such as logging in or taking a picture. Activity is a Java code that supports a screen or UI. Since mobile
phone screens are small, an activity typically takes up the whole screen. If you open multiple activities they are
stacked at top of each other . You can’t arrange activities side by side, like you can do with desktop windows.

Syntax

public class MainActivity extends Activity {

View: The view is everything you can see on the screen of the app — think of the individual UI elements like
buttons, labels, and text fields.
Intent
The main purpose of intent is to invoke individual components. Common uses include starting the service,
launching activities, displaying a list of contacts, dialing a phone number, or displaying a web page.
Intent is used to invoke components. It is mainly used to:

l Start the service


l Launch an activity
l Display a web page
l Display a list of contacts
l Broadcast a message
l Dial a phone call etc.

For example, you may write the following code to view the webpage.
Intent intent=new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.google.com"));
startActivity(intent);

1.4.2 . Services
A service is a component which runs in the background without direct interaction with the user. As the service
has no user interface, it is not bound to the lifecycle of an activity. They handle background processing
associated with an application. There are two types of services local and remote. Local service is accessed from
within the application whereas remote service,accessed remotely from other applications running on the same
device.
Syntax

public class MyService extends Service {

//block

1.4.3 . Broadcast Receivers


They handle communication between Android OS and applications. Now create the service implementation class
by inheriting the Service class and overriding its callback methods.

Syntax

public class MyReceiver extends BroadcastReceiver {

public void onReceive(context,intent){}

1.4.4 . Content Providers


Content Providers are used to share data between the applications. Such requests, handled by the methods of the
ContentResolver class. The data may be stored in the file system, the database or somewhere else entirely.

Syntax

public class MyContentProvider extends ContentProvider {

public void onCreate(){}

1.4.5 . Fragment
Fragments are like parts of activity. An activity can display one or more fragments on the screen at the same
time.

AndroidManifest.xml
It contains informations about activities, content providers, permissions etc. It is like the web.xml file in Java EE.

1.5 . Android Virtual Device (AVD)


It is used to test the android application without the need for mobile or tablet etc. It can be created in different
configurations to emulate different types of real devices.
1.5.1 . Android Emulator
The Android emulator is an Android Virtual Device (AVD), which represents a specific Android device. We
can use the Android emulator as a target device to execute and test our Android application on our PC. The
Android emulator provides almost all the functionality of a real device. We can get the incoming phone calls and
text messages. It also gives the location of the device and simulates different network speeds. Android emulator
simulates rotation and other hardware sensors. It accesses the Google Play store, and much more.

Fig 2: Android Emulator

1.5.2 . Install the emulator


The Android emulator is installed while installing the Android Studio. However some components of emulator
may or may not be installed while installing Android Studio. To install the emulator component, select the
Android Emulator component in the SDK Tools tab of the SDK Manager or click by AVD manager in the
icon.
Fig 3: Android manager icon

1.5.3 . Run an Android app on the Emulator


We can run an Android app form the Android Studio project, or we can run an app which is installed on the
Android Emulator as we run any app on a device.

To start the Android Emulator and run an application in our project:

1. In Android Studio, we need to create an Android Virtual Device (AVD) that the emulator can use to
install and run your app. To create a new AVD:-

2. Open the AVD Manager by clicking Tools > AVD Manager or Directly from an AVD manager.

fig 4: Steps for creating android emulator


Finally click on finished and the following interface will come

To start the emulator:

1. Open the AVD Manager.


2. Double-click an AVD, or click Run
While the emulator is running, we can run the Android Studio project and select the emulator as the target
device. We can also drag an APKs file to install on an emulator, and then run them.

Fig 5: run android emulator

To run an Android emulator that uses an AVD, double-click the AVD, or click Launch

l To stop the running emulator, right-click and select Stop, or click Menu ▼ and select Stop.
l If we want to clear the data from an emulator and return it to the initial state when it was first defined,
then right-click an AVD and select Wipe Data. Or click menu ▼ and select Wipe Data.
Chapter Two

2. Android Application

2.1 . Create Application


Let us start actual programming with Android Framework. Before you start writing your first example using
Android SDK, you have to make sure that you have set-up your Android development environment properly.

So let us proceed to write a simple Android Application which will print "Hello World!".

The first step is to create a simple Android Application using Android studio. When you click on Android studio
icon, it will show screen as shown below:

Fig 6: Start-up android studio interface


You can
start
your

application development by calling start a new android studio project. A new installation frame should ask
Application name, package information and location of the project.
Fig 7: Create new project steps

The next level of installation should contain selecting the activity to mobile, it specifies the default layout for
Applications.

After entered application name, it going to be called select the form factors your application runs on, here need
to specify Minimum SDK, in this document, I have declared as API 23: Android 6.0(Mashmallow) and will run
approximately 84.6% of devices on this API.

At the final stage it going to be open development tool to write the application code.

Fig 8: sample blocks of android studio


2.2 . Anatomy of Android Application
Before you run your app, you should be aware of a few directories and files in the Android project

Let us see each components in the following table:


no File or Folder Descriptions
1 AndroidManifest.xml
This is the manifest file which describes the fundamental characteristics of the app and
defines each of its components.
2 Java
This contains the .java source files for your project. By default, it includes an
MainActivity.java source file having an activity class that runs when your app is launched
using the app icon.
3
res/drawable-hdpi

This is a directory for drawable objects that are designed for high-density screens.

4 res/layout

This is a directory for files that define your app's user interface.

5 res/values

This is a directory for other various XML files that contain a collection of resources, such as
strings and colours definitions.

6 Build.gradle

This is an auto generated file which contains compileSdkVersion, buildToolsVersion,


applicationId, minSdkVersion, targetSdkVersion, versionCode and versionName

Following section will give a brief overview of the important application files.

2.3 . The Main Activity File

The main activity code is a Java file MainActivity.java. This is the actual application file which ultimately gets
converted to a Dalvik executable and runs your application. Following is the default code generated by the
application wizard for Hello World! Application.

package com.myandroid.helloworldapps;
import androidx.appcompat.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 );
}}
Here, R.layout.activity_main refers to the activity_main.xml file located in the res/layout folder. The onCreate()
method is one of many methods that are figured when an activity is loaded.

2.4 . The Manifest File

Whatever component we want develop as a part of our application, we must declare all its components in a
manifest.xml which resides at the root of the application project directory. This file works as an interface between
Android OS and your application, so if we do not declare your component in this file, then it will not be
considered by the OS. For example, a default manifest file will look like as following file

<?xml version="1.0" encoding="utf-8"?>


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="googlemaps.yohana.helloworldapps">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>

Here <application>...</application> tags enclosed the components related to the application. Attribute
android:icon will point to the application icon available under res/drawable-hdpi. The application uses the image
named ic_launcher.png located in the drawable folders

The <activity> tag is used to specify an activity and android:name attribute specifies the fully qualified class
name of the Activity subclass and the android:label attributes specifies a string to use as the label for the activity.
You can specify multiple activities using <activity> tags.
The action for the intent filter is named android.intent.action.MAIN to indicate that this activity serves as the
entry point for the application. The category for the intent-filter is named android.intent.category.LAUNCHER
to indicate that the application can be launched from the device's launcher icon.

The @string refers to the strings.xml file explained below. Hence, @string/app_name refers to the app_name
string defined in the strings.xml file, which is "HelloWorld". Similar way, other strings get populated in the
application.

Following is the list of tags which we will use in our manifest file to specify different Android application
components −

l <activity>elements for activities

l <service> elements for services

l <receiver> elements for broadcast receivers

l <provider> elements for content providers

2.5 . The Strings File

The strings.xml file is located in the res/values folder and it contains all the text that our application uses. A
string is a simple resource that is referenced using the value provided in the name attribute (not the name of the
XML file). So, we can combine string resources with other simple resources in the one XML file, under one
<resources> element.

For example, the names of buttons, labels, default text, and similar types of strings go into this file. This file is
responsible for their textual content. For example, a default strings file will look like as following file:

<resources>
<string name="app_name">HelloWorld</string>
<string name="hello_world">Hello world!</string>
<string name="menu_settings">Settings</string>
<string name="title_activity_main">MainActivity</string>
</resources>

Elements:
<resources>
Required. This must be the root node.
No attributes.

<string>
A string, which can include styling tags. Beware that must escape apostrophes and quotation marks.

attributes:
name
String. A name for the string. This name is used as the resource ID.

String array
A string array is a simple resource that is referenced using the value provided in the name attribute (not the
name of the XML file). As such, you can combine string array resources with other simple resources in the one
XML file, under one <resources> element.

syntax:
<resources>
<string-array name="array_name">
<item>item_name</item>
</string-array>

</resources>
elements:
<resources>
Required. This must be the root node.

No attributes.

<string-array>
Defines an array of strings. Contains one or more <item> elements.

attributes:
name
String. A name for the array. This name is used as the resource ID to reference the array.
<item>
A string, which can include styling tags. The value can be a reference to another string resource. Must be a
child of a <string-array> element. Beware that you must escape apostrophes and quotation marks.

No attributes.

example:
XML file saved at res/values/strings.xml:

<resources>
<string name="app_name">COVD-19 Detecction Apps</string>
<string-array name="ethiopia_town">
<item>Addis Ababa</item>
<item>Harar</item>
<item>Bahirdar</item>
<item>Jimma</item>
<item>Mekele</item>
<item>Dire Dawa</item>
</string-array>
</resources>

To access the string array:


Resources res = getResources();
String[] planets = res.getStringArray(R.array.planets_array);

2.6 . The Color File


A color value defined in XML. The color is specified with an RGB value and alpha channel. We can use a color
resource any place that accepts a hexadecimal color value. And also, we can use a color resource when a
drawable resource is expected in XML (for example, android:drawable="@color/green").

The value always begins with a pound (#) character and then followed by the Alpha-Red-Green-Blue
information in one of the following formats:
l #RGB
l #ARGB
l #RRGGBB
l #AARRGGBB
Note: A color is a simple resource that is referenced using the value provided in the name attribute (not the name
of the XML file). As such, we can combine color resources with other simple resources in the one XML file,
under one <resources> element.

file location:
res/values/colors.xml
The filename is arbitrary. The <color> element's name will be used as the resource ID.
resource reference:
In Java: R.color.color_name
In XML: @[package:]color/color_name
syntax:

<?xml version="1.0" encoding="utf-8"?>


<resources>

<color name="color_name">hexa_value</color>
<resources>

Elements:

<resources>
Required. This must be the root node.
No attributes.

<color>
A color expressed in hexadecimal, as described above.

attributes:
name
String. A name for the color. This will be used as the resource ID.

example:
XML file saved at res/values/colors.xml:

<?xml version="1.0" encoding="utf-8"?>


<resources>
<color name="colorPrimary">#6200EE</color>
<color name="colorPrimaryDark">#3700B3</color>
<color name="colorAccent">#03DAC5</color>
<color name="text_color">#FFF</color>
<color name="opaque_red">#f00</color>
<color name="tranlucent_red">#80ff0000</color>
<color name="blue">#03A9F4</color>
</resources>

This application code retrieves the color resource:


Java
Resources res = getResources();
int color = res.getColor(R.color.opaque_red);

This layout XML applies the color to an attribute:


<TextView
android:id="@+id/detailNameId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/text_color" />

2.7 . The Layout File


The activity_main.xml is a layout file available in res/layout directory, that is referenced by our application
when building its interface. We’ll modify this file very frequently to change the layout of our application. For our
"Hello World!" application, this file will have following content related to default layout :

<?xml version="1.0" encoding="utf-8"?>


<androidx.constraintlayout.widget.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=".MainActivity">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

This is an example of simple RelativeLayout which we will study in a separate chapter. The TextView is an
Android control used to build the GUI and it have various attributes like android:layout_width,
android:layout_height etc which are being used to set its width and height etc.. The @string refers to the
strings.xml file located in the res/values folder. Hence, @string/hello_world refers to the hello string defined in
the strings.xml file, which is "Hello World!".

1.1.1 . Create a new layout

To start a new constraint layout file, follow these steps:

1. In the Project window, click the module folder and then select File > New > XML > Layout XML.
2. Enter a name for the layout file and enter "androidx.constraintlayout.widget.ConstraintLayout" for the
Root Tag.
3. Click Finish.

Add or remove a constraint


To add a constraint, do the following:

1. Drag a view from the Palette window into the editor. When we add a view in a ConstraintLayout, it
displays a bounding box with square resizing handles on each corner and circular constraint handles on
each side.
2. Click the view to select it.
3. Do one of the following:
l Click a constraint handle and drag it to an available anchor point. This point can be the edge of
another view, the edge of the layout, or a guideline. Notice that as we drag the constraint handle,
the Layout Editor shows potential connection anchors and blue overlays.
l Click one of the Create a connection buttons in the Layout section of the Attributes
window, as shown in the following figure:

Figure . The Layout section of the Attributes window lets we create connections.

When the constraint is created, the editor gives it a default margin to separate the two views.

When creating constraints, remember the following rules:

l Every view must have at least two constraints: one horizontal and one vertical.
l We can create constraints only between a constraint handle and an anchor point that share the same plane.
So a vertical plane (the left and right sides) of a view can be constrained only to another vertical plane;
and baselines can constrain only to other baselines.
l Each constraint handle can be used for just one constraint, but you can create multiple constraints (from
different views) to the same anchor point.

We can delete a constraint by doing any of the following:

l Click on a constraint to select it, and then press Delete.


l Press and hold Control (Command on macOS), and then click on a constraint anchor. Note that the
constraint turns red to indicate that you can click to delete it, as shown in the following figure .

Figure. A red constraint indicates that you can click to delete it.

l In the Layout section of the Attributes window, click on a constraint anchor, as shown in the following
figure.

Figure. Click on a constraint anchor to delete it.

When we want to add opposing constraints on a view, the constraint lines become squiggly like a spring to
indicate the opposing forces. The effect is most visible when the view size is set to "fixed" or "wrap content," in
which case the view is centered between the constraints. If we instead want the view to stretch its size to meet
the constraints, switch the size to "match constraints"; or if we want to keep the current size but move the view
so that it is not centered, adjust the constraint bias.
And also we can use constraints to achieve different types of layout behavior, as described in the following
sections.

1.1.2 . Parent position

Constrain the side of a view to the corresponding edge of the


layout. In the left side of the view is connected to the left edge of
the parent layout. We can define the distance from the edge with
margin.

Figure. A horizontal constraint to the parent

1.1.3 . Order position

Define the order of appearance for two views, either vertically or


horizontally. As we have seen in the right figure, B is constrained to
always be to the right of A, and C is constrained below A. However,
these constraints do not imply alignment, so B can still move up and
down.

Figure. A
horizontal and vertical constraint

1.1.4 . Alignment

Align the edge of a view to the same edge of another view. In below figure , the left side of B is aligned to the
left side of A. If you want to align the view centers, create a constraint on both sides. And also we can offset the
alignment by dragging the view inward from the constraint. Since, we can also select all the views you want to
align, and then click Align in the toolbar to select the alignment type.
Figure(the left)A horizontal alignment constraint (the right) An offset horizontal alignment constraint

1.1.5 . Baseline alignment

Align the text baseline of a view to the text baseline of another view. In the
right figure, the first line of B is aligned with the text in A.

To create a baseline constraint, right-click the text view you want to


constrain and then click Show Baseline. Then click on the text baseline and
drag the line to another baseline.

Figure. A baseline alignment constraint

1.1.6 . Constrain to a guideline

We can add a vertical or horizontal guideline to which can constrain views, and the guideline will be invisible to
app users. The position the guideline within the layout based on either dp units or percent, relative to the layout's
edge. To create a guideline, click Guidelines in the toolbar,
and then click either Add Vertical Guideline or Add
Horizontal Guideline.

Drag the dotted line to reposition it and click the circle at the edge of
the guideline to toggle the measurement mode.

Figure. A view constrained to a guideline

1.1.7 . Constrain to a barrier

Similar to a guideline, a barrier is an invisible line that you can constrain views to. Except a barrier does not
define its own position; instead, the barrier position moves based on the position of views contained within it.
This is useful when you want to constrain a view to the a set of views rather than to one specific view.

For example, in the above figure shows view C is constrained to the right side of a barrier. The barrier is set to
the "end" (or the right side in a left-to-right layout) of both view A and view B. So the barrier moves depending
on whether the right side of view A or view B is is farthest right.

To create a barrier, follow these steps:


1. Click Guidelines in the toolbar, and then click Add Vertical Barrier or Add Horizontal Barrier.
2. In the Component Tree window, select the views you want inside the barrier and drag them into the
barrier component.

3. Select the barrier from the Component Tree, open the Attributes window, and then set the
barrierDirection.

Now we can create a constraint from another view to the barrier. And also, we can constrain views that are
inside the barrier to the barrier. This way, we can ensure that all views in the barrier always align to each other,
even if we don't know which view will be the longest or tallest.

We can also include a guideline inside a barrier to ensure a "minimum" position for the barrier.

Figure. View C is constrained


to a barrier, which moves based on the position/size of both view A and view B

1.2. Adjust the constraint bias


When we want to add a constraint to both sides of a view (and the view size for the same dimension is either
"fixed" or "wrap content"), the view becomes centered between the two constraints with a bias of 50% by
default. You can adjust the bias by dragging the bias slider in the Attributes window or by dragging the view.

Adjust the view size


We can use the corner handles to resize a view, but this hard codes the size so the view will not resize for

different content or screen sizes. To select a different sizing mode, click a view and open the Attributes
window on the right side of the editor.

Near the top of the Attributes window is the view inspector, which includes controls for several layout
attributes, as shown in figure 14 (this is available only for views in a constraint layout).

You can change the way the height and width are calculated by clicking the symbols indicated with callout 3 in
figure below. These symbols represent the size mode as follows (click the symbol to toggle between these
settings):

l Fixed: You specify a specific dimension in the text box below or by resizing the view in the
editor.

l Wrap Content: The view expands only as much as needed to fit its contents.

l Match Constraints: The view expands as much as possible to meet the constraints on each side
(after accounting for the view's margins). However, you can modify that behavior with the following
attributes and values (these attributes take effect only when you set the view width to match constraints):
l layout_constraintWidth_default
l spread: Expands the view as much as possible to meet the constraints on each side. This is
the default behavior.
l wrap: Expands the view only as much as needed to fit its contents, but still allows the
view to be smaller than that if the constraints require it. So the difference between this and
using Wrap Content (above), is that setting the width to Wrap Content forces the width
to always exactly match the content width; whereas using Match Constraints with
layout_constraintWidth_default set to wrap also allows the view to be smaller than the
content width.
l layout_constraintWidth_min

This takes a dp dimension for the view's minimum width.

l layout_constraintWidth_max

This takes a dp dimension for the view's maximum width.


Figure. When selecting a view, the Attributes window includes controls for 1 size ratio, 2 deleting constraints, 3
height/width mode, 4 margins, and 5 constraint bias. And also, we can highlight individual constraints in the
Layout Editor by clicking on them in the 6 constraint list.
However, if the given dimension has only one constraint,
then the view expands to fit its contents. Using this
mode on either the height or width also allows to set a
size ratio.
Note: You cannot use match_parent for any view in a
ConstraintLayout. Instead use "match constraints"
(0dp).

Figure. The view is set to a 16:9 aspect with the width


based on a ratio of the height.

1.2.1 . Set size as a ratio

When we want to set the view size to a ratio such as 16:9 if at least one of the view dimensions is set to "match
constraints" (0dp). To enable the ratio, click Toggle Aspect Ratio Constraint (callout 1 in figure above), and
then enter the width:height ratio in the input that appears.

If both the width and height are set to match constraints, we can click Toggle Aspect Ratio Constraint to select
which dimension is based on a ratio of the other. The view inspector indicates which is set as a ratio by
connecting the corresponding edges with a solid line.
1.3. Adjust the view margins

To ensure that all your views are evenly spaced, click Margin in the toolbar to select the default
margin for each view that you add to the layout. Any change you make to the default margin applies only to the
views you add from then on.

We can control the margin for each view in the Attributes window by clicking the number on the line that
represents each constraint (in figure 14, callout 4 shows the bottom margin is set to 16dp).

Figure. The toolbar's Margin button.


Control linear groups with a chain

Figure. A horizontal chain with two views


A chain is a group of views that are linked to each other with bi-directional position constraints. The views
within a chain can be distributed either vertically or horizontally.
Figure Examples of each chain style
Chains can be styled in one of the following ways:

.Spread: The views are evenly distributed (after margins are accounted for). This is the default.
.Spread inside: The first and last view are affixed to the constraints on each end of the chain and the rest are
evenly distributed.
.Weighted: When the chain is set to either spread or spread inside, you can fill the remaining space by
setting one or more views to "match constraints" (0dp). By default, the space is evenly distributed
between each view that's set to "match constraints," but you can assign a weight of importance to each
view using the layout_constraintHorizontal_weight and
layout_constraintVertical_weight attributes. If you're familiar with layout_weight in a
linear layout, this works the same way. So the view with the highest weight value gets the most amount of
space; views that have the same weight get the same amount of space.
.Packed: The views are packed together (after margins are accounted for). You can then adjust the whole
chain's bias (left/right or up/down) by changing the chain's head view bias.

The chain's "head" view (the left-most view in a horizontal chain and the top-most view in a vertical chain)
defines the chain's style in XML. However, you can toggle between spread, spread inside, and packed by

selecting any view in the chain and then clicking the chain button that appears below the view.

2.8 . Running the Application

Let's try to run our Hello World! application we just created. I assume you had created your AVD while doing
environment set-up. To run the app from Android studio, open one of your project's activity files and click Run
icon from the tool bar. Android studio installs the app on your AVD and starts it and if everything is fine with
your set-up and application, it will display following Emulator window
fig 8: Sample output on Android emulator

Congratulations!!! we have developed our first Android Application and now just keep following rest of the
tutorial step by step to become a great Android Developer. All the very best.

2.9 . Internal Details of Hello Android Example


Android application contains different components such as java source code, string resources, images, manifest
file, apk file etc. Let's understand the project structure of android application.
fig 9: Internal detail from sample code
Java Source Code
Let's see the java source file created by the Eclipse IDE:
package googlemaps.yohana.helloworldapps;
import androidx.appcompat.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 );
}
}

1. Activity is a java class that creates and default window on the screen where we can place different
components such as Button, EditText, TextView, Spinner etc. It is like the Frame of Java AWT. It
provides life cycle methods for activity such as onCreate, onStop, OnResume etc.
2. The onCreate method is called when Activity class is first created.
3. The setContentView(R.layout.activity_main) gives information about our layout resource.
Here, our layout resources are defined in activity_main.xml file.
File: activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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=".MainActivity">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

As you can see, a textview is created by the framework automatically. But the message for this string is defined
in the strings.xml file. The @string/hello_world provides information about the textview message. The value of
the attribute hello_world is defined in the strings.xml file.
File: strings.xml
<resources>
<string name="app_name">HelloWorld</string>
<string name="hello_world">Hello world!</string>
<string name="menu_settings">Settings</string>
<string name="title_activity_main">MainActivity</string>
</resources>

You can change the value of the hello_world attribute from this file.
Generated R.java file

It is the auto-generated file that contains IDs for all the resources of res directory. It is generated by aapt(Android
Asset Packaging Tool). Whenever you create any component on activity_main, a corresponding ID is created in
the R.java file which can be used in the Java Source file later.
APK File

An apk file is created by the framework automatically. If you want to run the android application on the mobile,
transfer and install it.
Resources

It contains resource files including activity_main, strings, styles etc.

2.9.1.1 . Manifest file

The AndroidManifest.xml file contains information of your package, including components of the application
such as activities, services, broadcast receivers, content providers etc.

It performs some other tasks also:

l It is responsible to protect the application to access any protected parts by providing the permissions.
l It also declares the android api that the application is going to use.
l It lists the instrumentation classes. The instrumentation classes provides profiling and other
informations. These informations are removed just before the application is published etc.

This is the required xml file for all the android application and located inside the root directory. A simple
AndroidManifest.xml file looks like this:

<?xml version="1.0" encoding="utf-8"?>


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="googlemaps.yohana.helloworldapps">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />


</intent-filter>
</activity>
</application>

</manifest>

Elements of the AndroidManifest.xml file


The elements used in the above xml file are described below.
<manifest>
manifest is the root element of the AndroidManifest.xml file. It has package attribute that describes the package
name of the activity class.
<application>
application is the subelement of the manifest. It includes the namespace declaration. This element contains
several subelements that declares the application component such as activity etc.
The commonly used attributes are of this element are icon, label, theme etc.
android:icon represents the icon for all the android application components.
android:label works as the default label for all the application components.
android:theme represents a common theme for all the android activities.
<activity>
activity is the subelement of application and represents an activity that must be defined in the
AndroidManifest.xml file. It has many attributes such as label, name, theme, launchMode etc.
android:label represents a label i.e. displayed on the screen.
android:name represents a name for the activity class. It is required attribute.
<intent-filter>
intent-filter is the sub-element of activity that describes the type of intent to which activity, service or broadcast
receiver can respond to.
<action>
It adds an action for the intent-filter. The intent-filter must have at least one action element.
<category>
It adds a category name to an intent-filter.

2.10 . Dalvik Virtual Machine (DVM)


As we know the modern JVM is high performance and provides excellent memory management. But it needs to
be optimized for low-powered handheld devices as well.
The Dalvik Virtual Machine (DVM) is an android virtual machine optimized for mobile devices. It optimizes
the virtual machine for memory, battery life and performance.
Dalvik is a name of a town in Iceland. The Dalvik VM was written by Dan Bornstein.
The Dex compiler converts the class files into the .dex file that run on the Dalvik VM. Multiple class files are
converted into one dex file.
Let's see the compiling and packaging process from the source file:

The javac tool compiles the java source file into the class file.
The dx tool takes all the class files of your application and generates a single .dex file. It is a platform-specific
tool.
The Android Assets Packaging Tool (aapt) handles the packaging process.

2.11 . Android Hide Title Bar and Full Screen Example

In this example, we are going to explain how to hide the title bar and how to display content in full screen mode.

2.11.1 . Code that hides title bar of activity


The getSupportActionBar() method is used to retrieve the instance of
ActionBar class. Calling the hide() method of ActionBar class hides
the title bar.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
getSupportActionBar().hide();

2.11.2 . Code that enables full screen mode of activity

The setFlags() method of Window class is used to display content in full screen mode. You need to pass the
WindowManager.LayoutParams.FLAG_FULLSCREEN constant in the setFlags method.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
this.getWindow().setFlags( WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);

2.11.3 . Android Hide Title Bar and Full Screen Example


Let's see the full code to hide the title bar in android.
Activity class
File: MainActivity.java
package googlemaps.yohana.helloworldapps;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.WindowManager;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
getSupportActionBar().hide();
this.getWindow().setFlags( WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
}

2.12 . Android Screen Orientation Example


The screenOrientation is the attribute of activity element. The orientation of android activity can be portrait,
landscape, sensor, unspecified etc. You need to define it in the AndroidManifest.xml file.

Syntax:
<activity android:name="package_name.our_Acctivity_name( e.g.MainActivity)"
android:screenOrientation="orientation_type([portrait,landscape,reversePortable...])">
</activity>
Example:
<activity android:name=".MainActivity"
android:screenOrientation="landscape">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />


</intent-filter>
</activity>
Or
<activity android:name=".MainActivity"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</activity
The common values for screenOrientation attribute are as follows:
Screen orientation
name Descriptions
portable taller not wider
wider not taller
landscape
sensor orientation is determined by the device orientation
sensor.
unspecified It is the default value. In such case, system chooses the orientation.
.Chapter Three
3. Android Activity and Services
3.1 . Introduction to Activities
The Activity class is a crucial component of an Android app, and the way activities are launched and put together
is a fundamental part of the platform's application model. Unlike programming paradigms in which apps are
launched with a main() method, the Android system initiates code in an Activity instance by invoking specific
callback methods that correspond to specific stages of its lifecycle.

An activity is a single, focused thing that the user can do. Almost all activities interact with the user, so the
Activity class takes care of creating a window for you in which you can place your UI with
setContentView(View). While activities are often presented to the user as full-screen windows, they can
also be used in other ways: as floating windows (via a theme with R.attr.windowIsFloating set), Multi-
Window mode or embedded into other windows. There are two methods almost all subclasses of Activity will
implement:

l onCreate(Bundle) is where you initialize your activity. Most importantly, here you will usually call
setContentView(int) with a layout resource defining your UI, and using findViewById(int)
to retrieve the widgets in that UI that you need to interact with programmatically.
l onPause() is where you deal with the user pausing active interaction with the activity. Any changes
made by the user should at this point be committed (usually to the ContentProvider holding the
data). In this state the activity is still visible on screen.
To be of use with Context.startActivity(), all activity classes must have a corresponding
<activity> declaration in their package's AndroidManifest.xml.

An activity provides the window in which the app draws its UI. This window typically fills the screen, but may
be smaller than the screen and float on top of other windows. Generally, one activity implements one screen in an
app. For instance, one of an app’s activities may implement a Preferences screen, while another activity
implements a Select Photo screen.

3.1.1 . Activity Lifecycle

Activities in the system are managed as activity stack. When a new activity is started, it is usually placed on the
top of the current stack and becomes the running activity. The previous activity always remains below it in the
stack, and will not come to the foreground again until the new activity exits. There can be one or multiple
activity stacks visible on screen.

An activity has essentially four states:

l If an activity is in the foreground of the screen (at the highest position of the topmost stack), it is active or
running. This is usually the activity that the user is currently interacting with.
l If an activity has lost focus but is still presented to the user, it is visible. It is possible if a new non-full-
sized or transparent activity has focus on top of your activity, another activity has higher position in
multi-window mode, or the activity itself is not focusable in current windowing mode. Such activity is
completely alive (it maintains all state and member information and remains attached to the window
manager).
l If an activity is completely obscured by another activity, it is stopped or hidden. It still retains all state and
member information, however, it is no longer visible to the user so its window is hidden and it will often
be killed by the system when memory is needed elsewhere.
l The system can drop the activity from memory by either asking it to finish, or simply killing its process,
making it destroyed. When it is displayed again to the user, it must be completely restarted and restored to
its previous state.

The entire lifecycle of an activity is defined by the following Activity methods. All of these are hooks that you
can override to do appropriate work when the activity changes state. All activities will implement
onCreate(Bundle) to do their initial setup; many will also implement onPause() to commit changes to
data and prepare to pause interacting with the user, and onStop() to handle no longer being visible on screen.
You should always call up to your superclass when implementing these methods.

onCreate()
You must implement this callback, which fires when the system creates your activity. Your implementation
should initialize the essential components of your activity: For example, your app should create views and bind
data to lists here. Most importantly, this is where you must call setContentView() to define the layout for
the activity's user interface.
When onCreate() finishes, the next callback is always onStart().

onStart()
As onCreate() exits, the activity enters the Started state, and the activity becomes visible to the user. This
callback contains what amounts to the activity’s final preparations for coming to the foreground and becoming
interactive.
onResume()
The system invokes this callback just before the activity starts interacting with the user. At this point, the activity
is at the top of the activity stack, and captures all user input. Most of an app’s core functionality is implemented
in the onResume() method.

The onPause() callback always follows onResume().

onPause()
The system calls onPause() when the activity loses focus and enters a Paused state. This state occurs when,
for example, the user taps the Back or Recents button. When the system calls onPuase() for your activity, it
technically means your activity is still partially visible, but most often is an indication that the user is leaving the
activity, and the activity will soon enter the Stopped or Resumed state.
An activity in the Paused state may continue to update the UI if the user is expecting the UI to update. Examples
of such an activity include one showing a navigation map screen or a media player playing. Even if such
activities lose focus, the user expects their UI to continue updating.
You should not use onPuase() to save application or user data, make network calls, or execute database
transactions. For information about saving data.
Once onPuase() finishes executing, the next callback is either onStop() or onResume(), depending on what
happens after the activity enters the Paused state.
onStop()
The system calls onStop() when the activity is no longer visible to the user. This may happen because the
activity is being destroyed, a new activity is starting, or an existing activity is entering a Resumed state and is
covering the stopped activity. In all of these cases, the stopped activity is no longer visible at all.
The next callback that the system calls is either onRestart(), if the activity is coming back to interact with
the user, or by onDestroy() if this activity is completely terminating.

onRestart()
The system invokes this callback when an activity in the Stopped state is about to restart. onRestart()
restores the state of the activity from the time that it was stopped.
This callback is always followed by onStart().

onDestroy()
The system invokes this callback before an activity is destroyed.
This callback is the final one that the activity receives. onDestroy() is usually implemented to ensure that all
of an activity’s resources are released when the activity, or the process containing it, is destroyed.
The following diagram shows the important state paths of an Activity. The square rectangles represent callback
methods you can implement to perform operations when the Activity moves between states. The colored ovals
are major states the Activity can be in.
fig 10: Android Activity Life-cycle

In general the movement through an activity's lifecycle looks like this:


Method Description
Kill-able Next
onCreate() Called when the activity is first created. This is where
you should do all of your normal static set up: create
views, bind data to lists, etc. This method also provides
you with a Bundle containing the activity's previously onStart
frozen state, if there was one. NO
Always followed by onStart().

Called after your activity has been stopped, prior to it


onRestart( being started again. Always followed by onStart()
) No
onStart()
Called when the activity is becoming visible to the user.
onStart() Followed by onResume() if the activity comes to the onResume()
foreground, or onStop() if it becomes hidden. No onPause()

Called when the activity will start interacting with the


user. At this point your activity is at the top of its
onResume() activity stack, with user input going to it.
No
Always followed by onPause(). onPause()

Called when the activity loses foreground state, is no


onPause() longer focusable or before transition to stopped/hidden Pre-
or destroyed state. The activity is still visible to user, so Build.V onResume()
ERSION_
it's recommended to keep it visually active and continue or
CODES.H
updating the UI. Implementations of this method must ONEYCOM onStop()
be very quick because the next activity will not be B
resumed until this method returns.

Followed by either onResume() if the activity returns


back to the front, or onStop() if it becomes invisible
to the user.
Called when the activity is no longer visible to the user.
onStop() This may happen either because a new activity is being
started on top, an existing one is being brought in front
of this one, or this one is being destroyed. This is Yes onRestart()
typically used to stop animations and refreshing the UI, onDestroy()
etc.
Followed by either onRestart() if this activity is
coming back to interact with the user, or
onDestroy() if this activity is going away
onD The final call you receive before your activity is
estroy() destroyed. This can happen either because the activity is
finishing (someone called Activity#finish on it), Yes
or because the system is temporarily destroying this
instance of the activity to save space. You can Nothing
distinguish between these two scenarios with the
Activity#isFinishing method.

Following is the content of the modified main activity file MainActivity.java. This file includes each of the
fundamental life cycle methods. The Log.d() method has been used to generate log messages.

package com.myservice.activitylifecycle;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
String text="Android Activity:";

//call when the activity firstly created


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
Log.d(text,"onCreate() invoked ");
}
/** Called when the activity is about to become visible. */
@Override
protected void onStart() {
super.onStart();
Log.d(text,"onRestart() invoked ");
}
@Override
protected void onRestart() {
super.onRestart();
Log.d(text,"onRestart() invoked ");
}
/** Called when the activity has become visible. */
@Override
protected void onResume() {
super.onResume();
Log.d(text,"onResume() invoked ");
}
/** Called when another activity is taking focus. */
@Override
protected void onPuase() {
super.onPuase();
Log.d(text,"onPause() invoked ");
}
/** Called when the activity is no longer visible. */
@Override
protected void onStop() {
super.onStop();
Log.d(text,"onStop() invoked ");
}
/** Called just before the activity is destroyed. */
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(text,"onDestroy() invoked ");
}
}

There are three key loops you may be interested in monitoring within your activity:

l The entire lifetime of an activity happens between the first call to onCreate(Bundle) through to a
single final call to onDestroy(). An activity will do all setup of "global" state in onCreate(), and
release all remaining resources in onDestroy(). For example, if it has a thread running in the background
to download data from the network, it may create that thread in onCreate() and then stop the thread in
onDestroy().
l The visible lifetime of an activity happens between a call to onStart() until a corresponding call to
onStop(). During this time the user can see the activity on-screen, though it may not be in the
foreground and interacting with the user. Between these two methods you can maintain resources that are
needed to show the activity to the user. For example, we can register a BroadcastReceiver in
onStart() to monitor for changes that impact our UI, and unregister it in onStop() when the user no longer
sees what we are displaying. The onStart() and onStop() methods can be called multiple times, as the
activity becomes visible and hidden to the user.
l The foreground lifetime of an activity happens between a call to onResume() until a corresponding
call to onPause(). During this time the activity is in visible, active and interacting with the user. An
activity can frequently go between the resumed and paused states -- for example when the device goes to
sleep, when an activity result is delivered, when a new intent is delivered -- so the code in these methods
should be fairly lightweight.

3.2 . Android Service


Android service is a component that is used to perform operations on the background such as playing music,
handle network transactions, interacting content providers etc. It doesn't has any UI (user interface). The service
runs in the background indefinitely even if application is destroyed. Moreover, service can be bounded by a
component to perform interactivity and inter process communication (IPC).

A Service is an application component representing either an application's desire to perform a longer-running


operation while not interacting with the user or to supply functionality for other applications to use. Each service
class must have a corresponding <service> declaration in its package's AndroidManifest.xml. Services can be
started with Context.startService() and Context.bindService().

Note that services, like other application objects, run in the main thread of their hosting process. This means that,
if your service is going to do any CPU intensive (such as MP3 playback) or blocking (such as networking)
operations, it should spawn its own thread in which to do that work. More information on this can be found in
Processes and Threads. The JobIntentService class is available as a standard implementation of Service
that has its own thread where it schedules its work to be done.

Most confusion about the Service class actually revolves around what it is not:

l A Service is not a separate process. The Service object itself does not imply it is running in its own
process; unless otherwise specified, it runs in the same process as the application it is part of.
l A Service is not a thread. It is not a means itself to do work off of the main thread (to avoid Application
Not Responding errors).
3.2.1 . Service Lifecycle

There are two reasons that a service can be run by the system. If someone calls Context.startService()
then the system will retrieve the service (creating it and calling its onCreate() method if needed) and then
call its onStartCommand(Intent, int, int) method with the arguments supplied by the client. The
service will at this point continue running until Context.stopService() or stopSelf() is called.

Note that multiple calls to Context.startService() do not nest (though they do result in multiple corresponding
calls to onStartCommand()), so no matter how many times it is started a service will be stopped once
Context.stopService() or stopSelf() is called; however, services can use their stopSelf(int) method to
ensure the service is not stopped until started intents have been processed.

There can be two forms of a service. The lifecycle of service can follow two different paths: started or bound.

1. Started
2. Bound
1) Started Service

A service is started when component (like activity) calls startService() method, now it runs in the background
indefinitely. It is stopped by stopService() method. The service can stop itself by calling the stopSelf() method.
2) Bound Service
A service is bound when another component (e.g. client) calls bindService() method. The client can unbind the
service by calling the unbindService() method. The service cannot be stopped until all clients unbind the
service.
Fig 11: Android service life-cycle

For started services, there are two additional major modes of operation they can decide to run in, depending on
the value they return from onStartCommand(): START_STICKY is used for services that are explicitly started
and stopped as needed, while START_NOT_STICKY or START_REDELIVER_INTENT are used for services
that should only remain running while processing any commands sent to them. See the linked documentation for
more detail on the semantics.

Clients can also use Context.bindService() to obtain a persistent connection to a service. This likewise
creates the service if it is not already running (calling onCreate() while doing so), but does not call
onStartCommand(). The client will receive the IBinder object that the service returns from its
onBind(Intent) method, allowing the client to then make calls back to the service. The service will remain
running as long as the connection is established (whether or not the client retains a reference on the service's
IBinder). Usually the IBinder returned is for a complex interface that has been written in aidl.

A service can be both started and have connections bound to it. In such a case, the system will keep the service
running as long as either it is started or there are one or more connections to it with the
Context.BIND_AUTO_CREATE flag. Once neither of these situations hold, the service's onDestroy()
method is called and the service is effectively terminated. All cleanup (stopping threads, unregistering receivers)
should be complete upon returning from onDestroy().

The following program shows how to use service and its life cycles

package com.myservice.serviceexample;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.widget.Toast;

public class MyService extends Service {


MediaPlayer myPlayer;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
Toast.makeText(this, "Service Created", Toast.LENGTH_LONG).show();
myPlayer = MediaPlayer.create(this,R.id.gone);
myPlayer.setLooping(false); // Set looping
}
@Override
public void onStart(Intent intent, int startid) {
Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
myPlayer.start();
}
@Override
public void onDestroy() {
Toast.makeText(this, "Service Stopped", Toast.LENGTH_LONG).show();
myPlayer.stop();
}
}

onStartCommand()
The system calls this method when another component, such as an activity, requests that the service be started,
by calling startService(). If you implement this method, it is your responsibility to stop the service when its work
is done, by calling stopSelf() or stopService() methods.
onBind()

The system calls this method when another component wants to bind with the service by calling bindService(). If
you implement this method, you must provide an interface that clients use to communicate with the service, by
returning an IBinder object. You must always implement this method, but if you don't want to allow binding, then
you should return null.
onUnbind()

The system calls this method when all clients have disconnected from a particular interface published by the
service.

onRebind()

The system calls this method when new clients have connected to the service, after it had previously been
notified that all had disconnected in its onUnbind(Intent).

onRebind()

The system calls this method when new clients have connected to the service, after it had previously been
notified that all had disconnected in its onUnbind(Intent).

onCreate()

The system calls this method when the service is first created using onStartCommand() or onBind(). This call is
required to perform one-time set-up.

onDestroy()

The system calls this method when the service is no longer used and is being destroyed. Your service should
implement this to clean up any resources such as threads, registered listeners, receivers, etc.

3.3 . Broadcast Receiver

Broadcast Receivers simply respond to broadcast messages from other applications or from the system itself.
These messages are sometime called events or intents. For example, applications can also initiate broadcasts to
let other applications know that some data has been downloaded to the device and is available for them to use, so
this is broadcast receiver who will intercept this communication and will initiate appropriate action.

There are following two important steps to make BroadcastReceiver works for the system broadcasted intents

l Creating the Broadcast Receiver.

l Registering Broadcast Receiver


There is one additional steps in case you are going to implement your custom intents then you will have to create
and broadcast those intents.

3.3.1 . Creating the Broadcast Receiver

A broadcast receiver is implemented as a subclass of BroadcastReceiver class and overriding the onReceive()
method where each message is received as a Intent object parameter.
package com.broadcast.broadcastreciver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

public class MyReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText( context,"test for brodcat reciver",Toast.LENGTH_LONG ).show();
}
}

3.3.2 . Registering Broadcast Receiver

An application listens for specific broadcast intents by registering a broadcast receiver in AndroidManifest.xml
file. Consider we are going to register MyReceiver for system generated event ACTION_BOOT_COMPLETED
which is fired by the system once the Android system has completed the boot process.

fig 12: Broadcast receiver


Broadcast-Receiver
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.myservice.activitylifecycle">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED">
</action>
</intent-filter>

</receiver>
</application>
</manifest>
Now whenever our Android device gets booted, it will be intercepted by BroadcastReceiver MyReceiver and
implemented logic inside onReceive() will be executed.

.
Chapter Four
4. User Interface

4.1 . What is Android User Interface


Android app's user interface is everything that the user can see and interact with. Android provides a variety of
pre-built UI components such as structured layout objects and UI controls that allow us to build the graphical
user interface for our app. Android also provides other UI modules for special interfaces such as dialogs,
notifications, and menus.

The basic building block for user interface is a View object which is created from the View class and occupies a
rectangular area on the screen and is responsible for drawing and event handling. View is the base class for
widgets, which are used to create interactive UI components like buttons, text fields, etc.

A layout defines the structure for a user interface in your app, such as in an activity. All elements in the layout
are built using a hierarchy of view and viewGroup objects. A view usually draws something the user can see and
interact with. Whereas a viewGroup is an invisible container that defines the layout structure for view and other
viewGroup objects, as shown in figure 1.

The ViewGroup is a subclass of View and provides invisible container that hold other Views or other
ViewGroups and define their layout properties.

The View
objects
are
usually
called
"widgets"
and can be
one of
many

subclasses, such as Button or TextView. The ViewGroup objects are usually called "layouts" can be one of many
types that provide a different layout structure, such as LinearLayout or ConstraintLayout .
You can declare a layout in two ways:

l Declare UI elements in XML. Android provides a straightforward XML vocabulary that corresponds to
the View classes and subclasses, such as those for widgets and layouts.

You can also use Android Studio's Layout Editor to build your XML layout using a drag-and-drop
interface.

l Instantiate layout elements at runtime. Your app can create View and ViewGroup objects (and
manipulate their properties) programmatically.

Declaring your UI in XML allows you to separate the presentation of your app from the code that controls its
behavior. Using XML files also makes it easy to provide different layouts for different screen sizes and
orientations (discussed further in Supporting Different Screen Sizes).

The Android framework gives you the flexibility to use either or both of these methods to build your app's UI.
For example, you can declare your app's default layouts in XML, and then modify the layout at runtime.

Tip:To debug your layout at runtime, use the Layout Inspector tool.

4.2 . Write the XML


Using Android's XML vocabulary, we can quickly design UI layouts and the screen elements they contain, in the
same way you create web pages in HTML with a series of nested elements.

Each layout file must contain exactly one root element, which must be a View or ViewGroup object. Once we've
defined the root element, we can add additional layout objects or widgets as child elements to gradually build a
View hierarchy that defines our layout.

For example, here's an XML layout that uses a horizontal ConstraintLayout to hold a TextView .

<?xml version="1.0" encoding="utf-8"?>


<androidx.constraintlayout.widget.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=".MainActivity"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

After declared a layout in XML, save the file with the .xml extension, in Android project's res/layout/ directory,
so it will properly compile.

4.2.1 . Load the XML Resource

When you compile your app, each XML layout file is compiled into a View resource. You should load the layout
resource from your app code, in your Activity.onCreate() callback implementation. Do so by calling
setContentView(), passing it the reference to your layout resource in the form of: R.layout.layout_file_name. For
example, if our XML layout is saved as main_layout.xml, you would load it for your Activity like so:

protected void onCreate(Bundle savedInstanceState) {


super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );

The onCreate() callback method in our Activity is called by the Android framework when our Activity is
launched.

Attributes

Every View and ViewGroup object supports their own variety of XML attributes. Some attributes are specific to
a View object (for example, TextView supports the textSize attribute), but these attributes are also inherited by
any View objects that may extend this class. Some are common to all View objects, because they are inherited
from the root View class (like the id attribute). And, other attributes are considered "layout parameters," which
are attributes that describe certain layout orientations of the View object, as defined by that object's parent
ViewGroup object.
ID
Any View object may have an integer ID associated with it, to uniquely identify the View within the tree. When
the app is compiled, this ID is referenced as an integer, but the ID is typically assigned in the layout XML file as
a string, in the id attribute. This is an XML attribute common to all View objects (defined by the View class) and
you will use it very often. The syntax for an ID, inside an XML tag is:

android:id="@+id/myButton"

The at-symbol (@) at the beginning of the string indicates that the XML parser should parse and expand the rest
of the ID string and identify it as an ID resource. The plus-symbol (+) means that this is a new resource name
that must be created and added to our resources (in the R.java file). There are a number of other ID resources that
are offered by the Android framework. When referencing an Android resource ID, we do not need the plus-
symbol, but must add the android package namespace, like so:

android:id="@android:id/empty"

With the android package namespace in place, we're now referencing an ID from the android.R resources
class, rather than the local resources class.

In order to create views and reference them from the app, a common pattern is to:

1. Define a view/widget in the layout file and assign it a unique ID:

<Button
android:id="@+id/showbtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:textSize="20dp"
android:text="@string/btn_show"

.../>

Then create an instance of the view object and capture it from the layout (typically in the onCreate() method):
Button btn=(Button) findViewById( R.id.mybtnID );

Defining IDs for view objects is important when creating a RelativeLayout. In a relative layout, sibling views
can define their layout relative to another sibling view, which is referenced by the unique ID.
An ID need not be unique throughout the entire tree, but it should be unique within the part of the tree you are
searching (which may often be the entire tree, so it's best to be completely unique when possible).

Note: With Android Studio 3.6 and higher, the view binding feature can replace findViewById() calls and
provides compile-time type safety for code that interacts with views. Consider using view binding instead of
findViewById().

4.2.2 . Layout Parameters

XML layout attributes named layout_something define layout parameters for the View that are appropriate for
the ViewGroup in which it resides.

Every ViewGroup class implements a nested class that extends ViewGroup.LayoutParams. This subclass
contains property types that define the size and position for each child view, as appropriate for the view group.
As you can see in figure 2, the parent view group defines layout parameters for each child view (including the
child view group).

Figure 2. Visualization of a view hierarchy with layout parameters associated with each view

At third level we have different layouts which are subclasses of ViewGroup class and a typical layout defines the
visual structure for an Android user interface and can be created either at run time using View/ViewGroup
objects or we can declare your layout using simple XML file main_layout.xml which is located in the res/layout
folder of our project.

Note that every LayoutParams subclass has its own syntax for setting values. Each child element must define
LayoutParams that are appropriate for its parent, though it may also define different LayoutParams for its own
children.

All view groups include a width and height (layout_width and layout_height), and each view is required to
define them. Many LayoutParams also include optional margins and borders.

You can specify width and height with exact measurements, though probably won't want to do this often. More
often, will use one of these constants to set the width or height:

l wrap_content tells our view to size itself to the dimensions required by its content.
l match_parent tells our view to become as big as its parent view group will allow.
In general, specifying a layout width and height using absolute units such as pixels is not recommended. Instead,
using relative measurements such as density-independent pixel units (dp), wrap_content, or match_parent, is a
better approach, because it helps ensure that the app will display properly across a variety of device screen sizes.

Layout Position

The geometry of a view is that of a rectangle. A view has a location, expressed as a pair of left and top
coordinates, and two dimensions, expressed as a width and a height. The unit for location and dimensions is the
pixel.

It is possible to retrieve the location of a view by invoking the methods getLeft() and getTop(). The former
returns the left, or X, coordinate of the rectangle representing the view. The latter returns the top, or Y, coordinate
of the rectangle representing the view. These methods both return the location of the view relative to its parent.
For instance, when getLeft() returns 20, that means the view is located 20 pixels to the right of the left edge of
its direct parent.

In addition, several convenience methods are offered to avoid unnecessary computations, namely getRight()
and getBottom(). These methods return the coordinates of the right and bottom edges of the rectangle
representing the view. For instance, calling getRight() is similar to the following computation: getLeft() +
getWidth().

Size, Padding and Margins

The size of a view is expressed with a width and a height. A view actually possesses two pairs of width and
height values.

The first pair is known as measured width and measured height. These dimensions define how big a view wants
to be within its parent. The measured dimensions can be obtained by calling getMeasuredWidth() and
getMeasuredHeight().

The second pair is simply known as width and height, or sometimes drawing width and drawing height. These
dimensions define the actual size of the view on screen, at drawing time and after layout. These values may, but
do not have to, be different from the measured width and height. The width and height can be obtained by calling
getWidth() and getHeight().
To measure its dimensions, a view takes into account its padding. The padding is expressed in pixels for the left,
top, right and bottom parts of the view. Padding can be used to offset the content of the view by a specific
number of pixels. For instance, a left padding of 2 will push the view's content by 2 pixels to the right of the left
edge. Padding can be set using the setPadding(int, int, int, int) method and queried by calling
getPaddingLeft(), getPaddingTop(), getPaddingRight() and
getPaddingBottom().

Even though a view can define a padding, it does not provide any support for margins. However, view groups
provide such a support.

4.2.2.1 . Common Layouts


Each subclass of the ViewGroup class provides a unique way to display the views you nest within it. Below are
some of the more common layout types that are built into the Android platform.

Note: Although we can nest one or more layouts within another layout to achieve the UI design, should strive to
keep your layout hierarchy as shallow as possible. The layout draws faster if it has fewer nested layouts (a wide
view hierarchy is better than a deep view hierarchy).

Fig 2
different
layout
managers

A) Rel
ati
ve
Layout

RelativeLayout is a view group that displays child views in relative positions. The position of each view can be
specified as relative to sibling elements (such as to the left-of or below another view) or in positions relative to
the parent RelativeLayout area (such as aligned to the bottom, left or center).
A RelativeLayout is a very powerful utility for designing a user interface because it can eliminate nested view
groups and keep our layout hierarchy flat, which improves performance. If we find ourself using several nested
LinearLayout groups, we may be able to replace them with a single RelativeLayout.

Positioning Views

RelativeLayout lets child views specify their position relative to the parent view or to each other (specified by
ID). So you can align two elements by right border, or make one below another, centered in the screen, centered
left, and so on. By default, all child views are drawn at the top-left of the layout, so we must define the position
of each view using the various layout properties available from RelativeLayout.LayoutParams.

Some of the many layout properties available to views in a RelativeLayout include:

android:layout_alignParentTop : If "true", makes the top edge of this view match the top edge of the parent.
android:layout_centerVertical : If "true", centers this child vertically within its parent.
android:layout_below : Positions the top edge of this view below the view specified with a resource ID.
android:layout_toRightOf : Positions the left edge of this view to the
right of the view specified with a resource ID.
The value for each layout property is either a boolean to enable a
layout position relative to the parent RelativeLayout or an ID that
references another view in the layout against which the view should
be positioned.

Examlpe:

<?xml version="1.0" encoding="utf-8"?>


<RelativeLayout
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"
android:paddingLeft="16dp"
android:paddingTop="16dp"
tools:context=".MainActivity">
<EditText
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter name!" />
<Spinner
android:id="@+id/date"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_below="@id/name"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="@+id/times"/>
<Spinner
android:id="@id/times"
android:layout_width="96dp"
android:layout_height="wrap_content"
android:layout_below="@id/name"
android:layout_alignParentRight="true" />
<Button
android:layout_width="96dp"
android:layout_height="wrap_content"
android:layout_below="@id/times"
android:layout_alignParentRight="true"
android:text="Buttob" />

</RelativeLayout>

B) Liner Layout

LinearLayout is a view group that aligns all children in a single direction, vertically or horizontally. You can
specify the layout direction with the android:orientation attribute.
All children of a LinearLayout are stacked one after the other, so a vertical list will only have one child per
row, no matter how wide they are, and a horizontal list will only be one row high (the height of the tallest child,
plus padding). A LinearLayout respects margins between children and the gravity (right, center, or left
alignment) of each child.

LinearLayout also supports assigning a weight to individual children with the


android:layout_weight attribute. This attribute assigns an "importance" value to a view in terms of how
much space it should occupy on the screen. A larger weight value allows it to expand to fill any remaining space
in the parent view. Child views can specify a weight value, and then any remaining space in the view group is
assigned to children in the proportion of their declared weight. Default weight is zero.

Example:

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout 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"
android:paddingLeft="16dp"
android:paddingTop="16dp"
android:orientation="vertical"
tools:context=".MainActivity">

<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Send to" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="write subject" />
<EditText
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="top"
android:hint="contents" />
<Button
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="Send Email" />

</LinearLayout>

C) Constraint Layout

A ConstraintLayout is a android.view.ViewGroup which allows to position


and size widgets in a flexible way. ConstraintLayout is available as
a support library that we can use on Android systems starting with API
level 9 (Gingerbread).

There are currently various types of constraints that you can use:
l Relative positioning
l Margins
l Centering positioning
l Circular positioning
l Visibility behavior
l Dimension constraints
l Chains
Relative positioning
Relative positioning is one of the basic building blocks of creating layouts in ConstraintLayout. Those
constraints allow us to position a given widget relative to another one. We can constrain a widget on the
horizontal and vertical axis:

l Horizontal Axis: left, right, start and end sides


l Vertical Axis: top, bottom sides and text baseline
The general concept is to constrain a given side of a widget to another side of any other widget.
For example, in order to position button B to the right of button A (Fig. 1):
Fig. 1 - Relative Positioning Example
<Button
android:id="@+id/abtnId"
style="@style/StyleButton"
... />

<Button
android:id="@+id/bbtnid"
android:text="Button B"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toLeftOf="@+id/abtnId" />

This tells the system that we want the left side of button B to be constrained to the right side of button A. Such a
position constraint means that the system will try to have both sides share the same location.

Fig. 2 - Relative Positioning


Constraints
Here is the list of available constraints (Fig. 2):
l layout_constraintLeft_toLeftOf
l layout_constraintLeft_toRightOf
l layout_constraintRight_toLeftOf
l layout_constraintRight_toRightOf
l layout_constraintTop_toTopOf
l layout_constraintTop_toBottomOf
l layout_constraintBottom_toTopOf
l layout_constraintBottom_toBottomOf
l layout_constraintBaseline_toBaselineOf
l layout_constraintStart_toEndOf
l layout_constraintStart_toStartOf
l layout_constraintEnd_toStartOf
l layout_constraintEnd_toEndOf

They all take a reference id to another widget, or the parent (which will reference the parent container, i.e. the
ConstraintLayout):
<Button
android:id="@+id/ButtonBId"
android:layout_height="wrap_content"
android:text="Button A"
...
app:layout_constraintLrft_toLeftOf="parent" />

Margins

Fig. 3 - Relative Positioning Margins


If side margins are set, they will be applied to the corresponding constraints (if they exist) (Fig. 3), enforcing the
margin as a space between the target and the source side. The usual layout margin attributes can be used to this
effect:
l android:layout_marginStart
l android:layout_marginEnd
l android:layout_marginLeft
l android:layout_marginTop
l android:layout_marginRight
l android:layout_marginBottom

Note that a margin can only be positive or equals to zero, and takes a Dimension.

Margins when connected to a GONE widget

When a position constraint target's visibility is View.GONE, you can also indicate a different margin value to be
used using the following attributes:

l layout_goneMarginStart
l layout_goneMarginEnd
l layout_goneMarginLeft
l layout_goneMarginTop
l layout_goneMarginRight
l layout_goneMarginBottom
Centering positioning and bias
A useful aspect of ConstraintLayout is in how it deals with "impossible" constrains. For example, if we
have something like:

<?xml version="1.0" encoding="utf-8"?>


<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".sample">

<Button
android:id="@+id/button"
android:text="Button A"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

Unless the ConstraintLayout happens to have the exact same size as the Button, both constraints cannot
be satisfied at the same time (both sides cannot be where we want them to be).

Fig. 4 - Centering Positioning


What happens in this case is that the constraints act like opposite forces pulling the widget apart equally (Fig. 4);
such that the widget will end up being centered in the parent container. This will apply similarly for vertical
constraints.
Bias
The default when encountering such opposite constraints is to center the widget; but you can tweak the
positioning to favor one side over another using the bias attributes:
l layout_constraintHorizontal_bias
l layout_constraintVertical_bias
Fig. 5 - Centering Positioning with Bias
For example the following will make the left side with a 30% bias instead of the default 50%, such that the left
side will be shorter, with the widget leaning more toward the left side (Fig. 5):

<android.support.constraint.ConstraintLayout ...>
<Button android:id="@+id/button" ...
app:layout_constraintHorizontal_bias="0.3"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent/>
</>

Circular positioning
Now we can constrain a widget center relative to another widget center, at an angle and a distance. This allows
us to position a widget on a circle (see Fig. 6). The following attributes can be used:
l layout_constraintCircle : references another widget id
l layout_constraintCircleRadius : the distance to the other widget center
l layout_constraintCircleAngle : which angle the widget should be at (in degrees, from 0 to
360)

Fig. 6 - Circular Positioning

<Button android:id="@+id/buttonA" ... />


<Button android:id="@+id/buttonB" ...
app:layout_constraintCircle="@+id/buttonA"
app:layout_constraintCircleRadius="100dp"
app:layout_constraintCircleAngle="45" />

Visibility behavior
ConstraintLayout has a specific handling of widgets being marked as View.GONE. GONE widgets, as
usual, are not going to be displayed and are not part of the layout itself (i.e. their actual dimensions will not be
changed if marked as GONE).
But in terms of the layout computations, GONE widgets are still part of it, with an important distinction:

l For the layout pass, their dimension will be considered as zero (basically, they will be resolved to a point)
l If they have constraints to other widgets they will still be respected, but any margins will be as if equals
to zero

Fig. 7 - Visibility Behavior


This specific behavior allows to build layouts where you can temporarily mark widgets as being GONE, without
breaking the layout (Fig. 7), which can be particularly useful when doing simple layout animations.

Note: The margin used will be the margin that B had defined when connecting to A (see Fig. 7 for an example).
In some cases, this might not be the margin you want (e.g. A had a 100dp margin to the side of its container, B
only a 16dp to A, marking A as gone, B will have a margin of 16dp to the container). For this reason, you can
specify an alternate margin value to be used when the connection is to a widget being marked as gone (see the
section above about the gone margin attributes).

Dimensions constraints
Minimum dimensions on ConstraintLayout
You can define minimum and maximum sizes for the ConstraintLayout itself:

l android:minWidth set the minimum width for the layout


l android:minHeight set the minimum height for the layout
l android:maxWidth set the maximum width for the layout
l android:maxHeight set the maximum height for the layout

Those minimum and maximum dimensions will be used by ConstraintLayout when its dimensions are set
to WRAP_CONTENT.
Widgets dimension constraints
The dimension of the widgets can be specified by setting the android:layout_width and
android:layout_height attributes in 3 different ways:
l Using a specific dimension (either a literal value such as 123dp or a Dimension reference)
l Using WRAP_CONTENT, which will ask the widget to compute its own size
l Using 0dp, which is the equivalent of "MATCH_CONSTRAINT"

Fig. 8 - Dimension Constraints


The first two works in a similar fashion as other layouts. The last one will resize the widget in such a way as
matching the constraints that are set (see Fig. 8, (a) is wrap_content, (b) is 0dp). If margins are set, they will be
taken in account in the computation (Fig. 8, (c) with 0dp).

Important: MATCH_PARENT is not recommended for widgets contained in a ConstraintLayout. Similar


behavior can be defined by using MATCH_CONSTRAINT with the corresponding left/right or top/bottom
constraints being set to "parent".

WRAP_CONTENT : enforcing constraints

If a dimension is set to WRAP_CONTENT, in versions before 1.1 they will be treated as a literal dimension --
meaning, constraints will not limit the resulting dimension. While in general this is enough (and faster), in some
situations, you might want to use WRAP_CONTENT, yet keep enforcing constraints to limit the resulting
dimension. In that case, you can add one of the corresponding attribute:

l app:layout_constrainedWidth=”true|false”
l app:layout_constrainedHeight=”true|false”
MATCH_CONSTRAINT dimensions
When a dimension is set to MATCH_CONSTRAINT, the default behavior is to have the resulting size take all the
available space. Several additional modifiers are available:
l layout_constraintWidth_min and layout_constraintHeight_min : will set the
minimum size for this dimension
l layout_constraintWidth_max and layout_constraintHeight_max : will set the
maximum size for this dimension
l layout_constraintWidth_percent and layout_constraintHeight_percent : will set
the size of this dimension as a percentage of the parent
Min and Max
The value indicated for min and max can be either a dimension in Dp, or "wrap", which will use the same value
as what WRAP_CONTENT would do.

Percent dimension
To use percent, we need to set the following:
l The dimension should be set to MATCH_CONSTRAINT (0dp)
l The default should be set to percent app:layout_constraintWidth_default="percent" or
app:layout_constraintHeight_default="percent"
l Then set the layout_constraintWidth_percent or
layout_constraintHeight_percent attributes to a value between 0 and 1

Ratio
We can also define one dimension of a widget as a ratio of the other one. In order to do that, we need to have at
least one constrained dimension be set to 0dp (i.e., MATCH_CONSTRAINT), and set the attribute
layout_constraintDimensionRatio to a given ratio. For example:

<Button android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="1:1" />

This will set the height of the button to be the same as its width.
The ratio can be expressed either as:
l a float value, representing a ratio between width and height
l a ratio in the form "width:height"
We can also use ratio if both dimensions are set to MATCH_CONSTRAINT (0dp). In this case the system sets the
largest dimensions that satisfies all constraints and maintains the aspect ratio specified. To constrain one specific
side based on the dimensions of another, you can pre append W," or H, to constrain the width or height
respectively. For example, If one dimension is constrained by two targets (e.g. width is 0dp and centered on
parent) you can indicate which side should be constrained, by adding the letter W (for constraining the width) or
H (for constraining the height) in front of the ratio, separated by a comma:
<Button android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="H,16:9"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
This will set the height of the button following a 16:9 ratio, while the width of the button will match the
constraints to parent.

Chains
Chains provide group-like behavior in a single axis (horizontally or vertically). The other axis can be constrained
independently.
Creating a chain
A set of widgets are considered a chain if they are linked together via a bi-directional connection (see Fig. 9,
showing a minimal chain, with two widgets).

Fig. 9 - Chain
Chain heads
Chains are controlled by attributes set on the first element of the chain (the "head" of the chain):

Fig. 10 - Chain Head


The head is the left-most widget for horizontal chains, and the top-most widget for vertical chains.
Margins in chains
If margins are specified on connections, they will be taken in account. In the case of spread chains, margins will
be deducted from the allocated space.
Chain Style
When setting the attribute layout_constraintHorizontal_chainStyle or
layout_constraintVertical_chainStyle on the first element of a chain, the behavior of the chain
will change according to the specified style (default is CHAIN_SPREAD).
l CHAIN_SPREAD -- the elements will be spread out (default style)
l Weighted chain -- in CHAIN_SPREAD mode, if some widgets are set to MATCH_CONSTRAINT, they
will split the available space
l CHAIN_SPREAD_INSIDE -- similar, but the endpoints of the chain will not be spread out
l CHAIN_PACKED -- the elements of the chain will be packed together. The horizontal or vertical bias
attribute of the child will then affect the positioning of the packed elements

Fig. 11 - Chains Styles


Weighted chains
The default behavior of a chain is to spread the elements equally in the available space. If one or more elements
are using MATCH_CONSTRAINT, they will use the available empty space (equally divided among themselves).
The attribute layout_constraintHorizontal_weight and
layout_constraintVertical_weight will control how the space will be distributed among the
elements using MATCH_CONSTRAINT. For exemple, on a chain containing two elements using
MATCH_CONSTRAINT, with the first element using a weight of 2 and the second a weight of 1, the space
occupied by the first element will be twice that of the second element.

Margins and chains

When using margins on elements in a chain, the margins are additive.

For example, on a horizontal chain, if one element defines a right margin of 10dp and the next element defines a
left margin of 5dp, the resulting margin between those two elements is 15dp.

An item plus its margins are considered together when calculating leftover space used by chains to position
items. The leftover space does not contain the margins.
4.2.3 . Building Layouts with an Adapter

When the content for your layout is dynamic or not pre-determined, you can use a layout that subclasses
AdapterView to populate the layout with views at runtime. A subclass of the AdapterView class uses an Adapter
to bind data to its layout. The Adapter behaves as a middleman between the data source and the AdapterView
layout—the Adapter retrieves the data (from a source such as an array or a database query) and converts each
entry into a view that can be added into the AdapterView layout.

Common layouts backed by an adapter include:

1.

4.2.4 . Filling an adapter view with data

We can populate an AdapterView such as ListView or GridView by binding the AdapterView instance to an
Adapter, which retrieves data from an external source and creates a View that represents each data entry.

Android provides several subclasses of Adapter that are useful for retrieving different kinds of data and building
views for an AdapterView. The two most common adapters are:

ArrayAdapter
Use this adapter when your data source is an array. By default, ArrayAdapter creates a view for each array item
by calling toString() on each item and placing the contents in a TextView.

For example, if you have an array of strings you want to display in a ListView, initialize a new ArrayAdapter
using a constructor to specify the layout for each string and the string array:

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,


android.R.layout.simple_list_item_1, myStringArray);

The arguments for this constructor are:

l our app Context


l The layout that contains a TextView for each string in the array
l The string array

Then simply call setAdapter() on your ListView:

ListView listView = (ListView) findViewById(R.id.listview);


listView.setAdapter(adapter);

To customize the appearance of each item you can override the toString() method for the objects in your array.
Or, to create a view for each item that's something other than a TextView (for example, if you want an
ImageView for each array item), extend the ArrayAdapter class and override getView() to return the type of view
you want for each item.

SimpleCursorAdapter
Use this adapter when your data comes from a Cursor. When using SimpleCursorAdapter, you must specify a
layout to use for each row in the Cursor and which columns in the Cursor should be inserted into which views of
the layout. For example, if you want to create a list of people's names and phone numbers, you can perform a
query that returns a Cursor containing a row for each person and columns for the names and numbers. You then
create a string array specifying which columns from the Cursor you want in the layout for each result and an
integer array specifying the corresponding views that each column should be placed:

String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME,


ContactsContract.CommonDataKinds.Phone.NUMBER};
int[] toViews = {R.id.display_name, R.id.phone_number};

When you instantiate the SimpleCursorAdapter, pass the layout to use for each result, the Cursor containing the
results, and these two arrays:

SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,


R.layout.person_name_and_number, cursor, fromColumns, toViews, 0);
ListView listView = getListView();
listView.setAdapter(adapter);
The SimpleCursorAdapter then creates a view for each row in the Cursor using the provided layout by inserting
each fromColumns item into the corresponding toViews view.

If, during the course of your app's life, you change the underlying data that is read by your adapter, you should
call notifyDataSetChanged(). This will notify the attached view that the data has been changed and it should
refresh itself.

4.2.5 . Handling click events

You can respond to click events on each item in an AdapterView by implementing the
AdapterView.OnItemClickListener interface. For example:

// Create a message handling object as an anonymous class.


private OnItemClickListener messageClickedHandler = new
OnItemClickListener() {
public void onItemClick(AdapterView parent, View v, int position, long id)
{
// Do something in response to the click
}
};
listView.setOnItemClickListener(messageClickedHandler);

4.3 . Material Design


Material design is a comprehensive guide for visual, motion, and interaction design across platforms and devices.
To use material design in your Android apps, follow the guidelines defined in the material design specification
and use the new components and styles available in the material design support library. This page provides an
overview of the patterns and APIs you should use.

Android provides the following features to help you build material design apps:

l A material design app theme to style all your UI widgets


l Widgets for complex views such as lists and cards
l New APIs for custom shadows and animations
4.3.1 . Material theme and widgets

To take advantage of the material features such as styling for standard UI widgets, and to streamline our app's
style definition, apply a material-based theme to your app.

Fig 3: The left dark themes and the right


light theme

To provide your users a familiar experience, use material's most common UX patterns:

l Promote your UI's main action with a Floating Action Button (FAB).
l Show your brand, navigation, search, and other actions with the App Bar.
l Show and hide your app's navigation with the Navigation Drawer.
l Use one of many other material components for your app layout and navigation, such as collapsing
toolbars, tabs, a bottom nav bar, and more. To see them all, check out the Material Components for
Android catalog

And whenever possible, use predefined material icons. For example, the navigation "menu" button for your
navigation drawer should use the standard "hamburger" icon. You can also import SVG icons from the material
icon library with Android Studio's Vector Asset Studio.

4.3.2 . Elevation shadows and cards

In addition to the X and Y properties, views in Android have a Z property. This new property represents the
elevation of a view, which determines:

l The size of the shadow: views with higher Z values cast bigger shadows.
l The drawing order: views with higher Z values appear on top of other views.
Elevation is often applied when your layout includes a card-based layout, which helps you display important
pieces of information inside cards that provide a material look. You can use the CardView widget to create
cards with a default elevation.

4.3.3 . Animations
The new animation APIs let we create custom animations for touch feedback in UI controls, changes in view
state, and activity transitions.
These APIs let you:
l Respond to touch events in your views with touch feedback animations.

l Hide and show views with circular reveal animations.

l Switch between activities with custom activity transition animations.

l Create more natural animations with curved motion.

l Animate changes in one or more view properties with view state change animations.

l Show animations in state list drawables between view state changes.

Touch feedback animations are built into several standard views, such as buttons. The new APIs let you
customize these animations and add them to your custom views.

4.4 . Styles and Themes


Styles and themes on Android allow to separate the details of our app design from the UI structure and behavior,
similar to stylesheets in web design. A style is a collection of attributes that specify the appearance for a single
View. A style can specify attributes such as font color, font size, background color, and much more.

A theme is a type of style that's applied to an entire app, activity, or view hierarchy not just an individual view.
When we apply our style as a theme, every view in the app or activity applies each style attribute that it supports.
Themes can also apply styles to non-view elements, such as the status bar and window background.

Styles and themes are declared in a style resource file in res/values/, usually named styles.xml.

4.4.1 . Create and apply a style


To create a new style or theme, open your project's res/values/styles.xml file. For each style you want
to create, follow these steps:
1. Add a <style> element with a name that uniquely identifies the style.
2. Add an <item> element for each style attribute you want to define.
The name in each item specifies an attribute we would otherwise use as an XML attribute in our layout. The
value in the <item> element is the value for that attribute.

For example, if define the following style:


<style name="RedColor" parent="TextAppearance.AppCompat">
<!-- Customize our theme here. -->
<item name="android:textColor">#FF01</item>
<item name="android:textSize">100dp</item>
</style>

We can apply the style to a view(EditText view) as follows:


<EditText
android:id="@+id/edittxt"
style="@style/RedColor"
../>

Each attribute specified in the style is applied to that view if the view accepts it. The view simply ignores any
attributes that it does not accept.

Note: Only the element to which you add the style attribute receives those style attributes—any child views do
not apply the styles. If a child views to inherit styles, instead apply the style with the android:theme
attribute.

However, instead of applying a style to individual views, usually apply styles as a theme for the entire app,
activity, or collection of views.

4.4.2 . Extend and customize a style

When creating your own styles, you should always extend an existing style from the framework or support
library so that you maintain compatibility with platform UI styles. To extend a style, specify the style to extend
with the parent attribute. Then override the inherited style attributes and add new ones.

For example, inherit the Android platform's default text appearance and modify it as follows:

<style name="RedColor" parent="@android:style/TextAppearance">


<item name="android:textColor">#FF01</item>
<item name="android:textSize">100dp</item>
</style>

However, should be always inherit our core app styles from the Android Support Library. The styles in the
support library provide compatibility with Android 4.0 (API level 14) and higher by optimizing each style for the
UI attributes available in each version. The support library styles often have a name similar to the style from the
platform, but with AppCompat included.

And also, inherit styles (except those from the platform) by extending a style's name with a dot notation, instead
of using the parent attribute. That is, prefix the name of a style with the name of the style to inherit, separated by
a period. Usually do this only when extending our own styles, not styles from other libraries. For example, the
following style inherits all styles from the RedText style above and then increases the text size:

<style name="RedColor.Large" parent="@android:style/TextAppearance">


<item name="android:textSize">24dp</item>
</style>

Note: If we use the dot notation to extend a style, and also include the parent attribute, then the parent styles
override any styles inheritted through the dot notation.

To find which attributes that declare with an <item> tag, refer to the "XML attributes" table in the various class
references. All views support XML attributes from the base View class, and many views add their own special
attributes. For example, the TextView XML attributes includes the android:inputType attribute that you can apply
to a text view that receives input, such as an EditText widget.

4.4.3 . Apply a style as a theme


You can create a theme the same way you create styles. The difference is how you apply it: instead of applying a
style with the style attribute on a view, you apply a theme with the android:theme attribute on either the
<application> tag or an <activity> tag in the AndroidManifest.xml file.

For example, here's how to apply the Android Support Library's material design "dark" theme to the whole app:

<?xml version="1.0" encoding="utf-8"?>


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.course.mycourseone">
<application
...
android:theme="@style/AppTheme">
...
</application>
</manifest>

And here's how to apply the "light" theme to just one activity:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.course.mycourseone">
<application
...
android:theme="@style/Theme.AppCompat.Light">
...
</application>
</manifest>

Now every view in the app or activity applies the styles defined in the given theme. If a view supports only some
of the attributes declared in the style, then it applies only those attributes and ignores the ones it does not support.

Beginning with Android 5.0 (API level 21) and Android Support Library v22.1, we can also specify the
android:theme attribute to a view in the layout file. This modifies the theme for that view and any child
views, which is useful for altering theme color palettes in a specific portion of the interface. The best way to do
so is to extend these styles from the support library and override some of the attributes.

<?xml version="1.0" encoding="utf-8"?>


<androidx.constraintlayout.widget.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=".MainActivity"
android:theme="@style/Theme.AppCompat.Light">

… />

4.4.4 . Style hierarchy

Android provides a variety of ways to set attributes throughout your Android app. For example, you can set
attributes directly in a layout, you can apply a style to a view, you can apply a theme to a layout, and you can
even set attributes programmatically.

If we have specified the same attributes in multiple places, the list below determines which attributes are
ultimately applied. The list is ordered from highest precedence to lowest:

1. Applying character- or paragraph-level styling via text spans to TextView-derived classes


2. Applying attributes programmatically
3. Applying individual attributes directly to a View
4. Applying a style to a View
5. Default styling
6. Applying a theme to a collection of Views, an activity, or our entire app
7. Applying certain View-specific styling, such as setting a TextAppearance on a TextView

Figure 2. Styling from a span overrides styling from a textAppearance.

If we’re trying to style our app and not seeing the results expect, it's likely that other styling is overriding
changes. For example, if we apply a theme to our app, along with a style to an individual View, the style
attributes would override any matching theme attributes for that View. Note, however, that any theme attributes
that aren't overridden by the style are still used.

4.4.5 . TextAppearance

One limitation with styles is that apply only one style to a View. In a TextView, however, specify a
TextAppearance attribute which functions similarly to a style, as shown in the following example:

<TextView
android:id="@+id/showtxt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
android:text="This text is applied style"
.../>
TextAppearance allows to define text-specific styling while leaving a View’s style available for other uses.
Note, however, that if we define any text attributes directly on the View or in a style, those values would override
the TextAppearance values.

TextAppearance supports a subset of styling attributes that TextView offers. Some common TextView attributes
not included are lineHeight[Multiplier|Extra], lines, breakStrategy, and
hyphenationFrequency. TextAppearance works at the character level and not the paragraph level, so
attributes that affect the entire layout are not supported.

4.4.6 . Customize the default theme


When you create a project with Android Studio, it applies a material design theme to your app by default, as
defined in your project's styles.xml file. This AppTheme style extends a theme from the support library and
includes overrides for color attributes that are used by key UI elements, such as the app bar and the floating
action buttton(if used). So you can quickly customize your app's color design by updating the provided colors.

For example, your styles.xml file should look similar to this:

<style name="CustomThem" parent="Theme.AppCompat.DayNight.DarkActionBar">


<item name="colorPrimary">@color/first</item>
<item name="colorPrimaryDark">@color/second</item>
<item name="colorAccent">@color/third</item>
<item name="android:navigationBarColor">@color/colorAccent</item>

</style>

Notice that the style values are actually references to other Color Resource defined in the project's
res/values/colors.xml file. So that's the file we should edit to change the colors. But before start
changing these colors, preview the colors with the Material Color Tool. This tool helps us pick colors from the
material palette and preview how they'll look in an app.

Once we know our colors, update the values in res/values/colors.xml:

The layout design can implementable based on them based colours, for example as following design is designed
based on them colour(blue).
And then we can override whatever other styles we want. For example, we can change the activity background
color as follows:
<style name="CustomTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize our theme here. -->
<item name="android:windowBackground">@color/colorAccent</item>

</style>

Most attributes are applied to specific types of views, and some apply to all views. However, some theme
attributes listed at R.styleable.Theme apply to the activity window, not the views in the layout. For example,
windowBackground changes the window background and windowEnterTransition defines a transition animation
to use when the activity starts.

The Android Support Library also provides other attributes we can use to customize theme extended from
Theme.AppCompat (such as the colorPrimary attribute shown above).

Note: Attribute names from the support library do not use the android: prefix. That's used only for attributes
from the Android framework.

There are also different themes available from the support library that we might want to extend instead of the
ones shown above. The best place to see the available themes is the library's themes.xml file.

4.4.7 . Add version-specific styles

If a new version of Android adds theme attributes that you want to use, you can add them to your theme while
still being compatible with old versions. All you need is another styles.xml file saved in a values directory that
includes the resource version qualifier.

For example:
res/values/styles.xml # themes for all versions
res/values-v21/styles.xml # themes for API level 21+ only

Because the styles in the values/styles.xml file are available for all versions, your themes in
values-v21/styles.xml can inherit them. As such, you can avoid duplicating styles by beginning with a "base"
theme and then extending it in your version-specific styles.

For example, to declare window transitions for Android 5.0 (API level 21) and higher, you need to use some new
attributes. So your base theme in res/values/styles.xml could look like this:

<style name="CustomTheme" parent="Theme.AppCompat.Light.DarkActionBar">


<!-- Customize your theme here. -->
<item name="buttonStyle">@style/Widget.AppCompat.Button.Borderless</item>
<item name="android:windowBackground">@color/colorAccent</item>
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>

Then add the version-specific styles in res/values-v21/styles.xml as follows:


<style name="CustomTheme" parent="BaseAppTheme">
<item name="android:windowActivityTransitions">true</item>
<item name="android:windowEnterTransition">@android:transition/slide_right </item>
<item name="android:windowExitTransition">@android:transition/slide_left </item>
</style>

Now you can apply AppTheme in your manifest file and the system selects the styles available for each system
version.

4.4.8 . Customize widget styles


Every widget in the framework and support library has a default style. For example, when you style your app
using a theme from the support library, an instance of Button is styled using the Widget.AppCompat.Button
style. If you'd like to apply a different widget style to a button, then you can do so with the style attribute in your
layout file. For example, the following applies the library's borderless button style:

<Button
android:id="@+id/showbtn”
android:textStyle="bold"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
../>

And if you want to apply this style to all buttons, you can declare it in your theme's buttonStyle as follows:

<style name="CustomTheme" parent="Theme.AppCompat.Light.DarkActionBar">


<!-- Customize your theme here. -->
<item name="buttonStyle">@style/Widget.AppCompat.Button.Borderless</item>

To discover all of the alternative widget styles available from the support library, look at the R.style reference
for fields that begin with Widget. (Ignore the styles that begin with Base_Widget.) Remember to replace all
underscores with periods when using the style name in your resources.

Full example for style:

color.xml

<resources>
<color name="colorPrimary">#6200EE</color>
<color name="colorPrimaryDark">#3700B3</color>
<color name="colorAccent">#03DAC5</color>
<color name="first">#FF5722</color>
<color name="second">#64DD17</color>
<color name="third">#0D47A1</color>
</resources>
style.xml

<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="CustomThem" parent="Theme.AppCompat.DayNight.DarkActionBar">
<item name="colorPrimary">@color/first</item>
<item name="colorPrimaryDark">@color/second</item>
<item name="colorAccent">@color/third</item>
<item name="android:navigationBarColor">@color/colorAccent</item>
</style>
<style name="StyleButton">
<item name="android:textSize">24dp</item>
<item name="android:background">@color/colorAccent</item>
<item name="android:textColor">#FFF</item>
<item name="android:padding">12dp</item>
<item name="android:textStyle">bold</item>
</style>
</resources>

mainfast.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.course.samplecode">
<application
...
android:icon="@mipmap/ic_launcher"
android:theme="@style/CustomThem">
<activity android:name=".sample"></activity>
...
</manifest>
4.5 . Add a Floating Action Button
A floating action button (FAB) is a circular button that triggers the primary action in our app's UI. This page
shows you how to add the FAB to your layout, customize some of its appearance, and respond to button taps.

Figure 1. A floating action button

4.5.1 . Add the floating action button to our layout


The following code shows how the FloatingActionButton should appear in the layout file:
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
app:srcCompat="@android:drawable/ic_dialog_email" />

We can configure other FAB properties using either XML attributes or corresponding methods, such as the
following:
l The size of the FAB, using the app:fabSize attribute or the setSize() method.
l The ripple color of the FAB, using the app:rippleColor attribute or the setRippleColor() method.
l The FAB icon, using the android:src attribute or the setImageDrawable() method.

4.5.2 . Respond to button taps


Then apply an View.OnClickListener to handle FAB taps. For example, the following code displays a
Snackbar when the user taps the FAB:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_floating );
Toolbar toolbar = findViewById( R.id.toolbar );
setSupportActionBar( toolbar );

FloatingActionButton fab = findViewById( R.id.fab );


fab.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make( view, "Replace with your own action", Snackbar.LENGTH_LONG )
.setAction( "Action", null ).show();
}
} );
}

. Chapter Five
5. Android Widgets
5.1 . Introduction
Widgets are an essential aspect of home screen customization. We can imagine them as "at-a-glance" views of an
app's most important data and functionality that is accessible right from the user's home screen. Users can move
widgets across their home screen panels, and, if supported, resize them to tailor the amount of information within
a widget to their preference.

5.2 . Widget types


As you begin planning your widget, think about what kind of widget you're trying to build. Widgets typically fall
into one of the following categories:
5.2.1 . Information widgets

Information widgets typically display a few crucial information elements that are important to a user and track
how that information changes over time. Good examples for information widgets are weather widgets, clock
widgets or sports score trackers. Touching information widgets typically launches the associated app and opens a
detail view of the widget information.

5.2.2 . Collection widgets

As the name implies, collection widgets specialize in displaying multitude elements of the same type, such as a
collection of pictures from a gallery app, a collection of articles from a news app or a collection of
emails/messages from a communication app. Collection widgets typically focus on two use cases: browsing the
collection, and opening an element of the collection to its detail view for consumption. Collection widgets can
scroll vertically.

ListView widget GridView widget


5.2.3 . Control widgets

The main purpose of a control widget is to display often used functions that the user can trigger right from the
home screen without having to open the app first. Think of them as remote controls for an app. A typical example
of control widgets are music app widgets that allow the user to play, pause or skip music tracks from outside the
actual music app.

Interacting with control widgets may or may not progress to an associated detail view depending on if the control
widget's function generated a data set, such as in the case of a search widget.

5.2.4 . Hybrid widgets

While all widgets tend to gravitate towards one of the three types described above, many widgets in reality are
hybrids that combine elements of different types.

For the purpose of widget planning, center our widget around one of the base types and add elements of other
types if needed.

A music player widget is primarily a


control widget, but also keeps the user
informed about what track is currently playing. It essentially combines a control widget with elements of an
information widget type.

There are given a lot of android widgets with simplified examples such as Button,EditText,
AutoCompleteTextView,ToggleButton,DatePicker,TimePicker,ProgressBar etc.
5.3 . Android Button
A button consists of text or an icon (or both text and an icon) that communicates what action occurs when the
user touches it.

Key classes are the following:


l Button
l ImageButton

Depending on whether we want a button with text, an icon, or both, we can create the button in our layout in
three ways:

With text, using the Button class:

<Button
android:id="@+id/showbtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_margin="8dp"
android:background="#00BCD4"
android:text="My Button"
android:textStyle="bold"
android:textColor="#FFFFFF"
android:hint="This button is login"

../>

With an icon, using the ImageButton class:


<ImageButton
android:id="@+id/imageButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:contentDescription="The first button image"
android:src="@mipmap/ic_launcher"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/showtxt" />
With text and an icon, using the Button class with the android:drawableLeft attribute when we want to
put the icon in the left or when we want to put the icon to the right we can used android:drawableRight
class and also to Top and Buttom we can used android:drawableTop and android:drawabelBottom
classes respectively:
<Button
android:id="@+id/showbtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:background="#00BCD4"
android:text="My Button"
android:textStyle="bold"
android:textColor="#FFFFFF"
android:drawableLeft="@drawable/ic_launcher_foreground"
android:textColorHint="#2196F3"
../>
5.3.1 . Responding to Click Events
When the user clicks a button, the Button object receives an on-click event. To define the click event handler for
a button, add the android:onClick attribute to the <Button> element in our XML layout. The value for this
attribute must be the name of the method we want to call in response to a click event. The Activity hosting the
layout must then implement the corresponding method.
For example, here's a layout with a button using android:onClick:
<Button
android:id="@+id/showbtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:background="#00BCD4"
android:textSize="20dp"
android:text="Click me"
android:textStyle="bold"
android:textColor="#FFFFFF"
android:hint="This button "
android:onClick="showMe"/>
Within the Activity that hosts this layout, the following method handles the click event:
/** Called when the user touches the button */
public void showMe(View view){
String text= txtedit.getText().toString();
txtshow.setVisibility( View.VISIBLE );
txtshow.setText( "After click me!!! "+ text);
}
The method that declare in the android:onClick() attribute must have a signature exactly as shown above.
Specifically, the method must:
l Be public
l Return void
l Define a View as its only parameter (this will be the View that was clicked)

5.3.2 . Using an OnClickListener

We can also declare the click event handler programmatically rather than in an XML layout. This might be
necessary if we instantiate the Button at runtime or to declare the click behavior in a Fragment subclass.

To declare the event handler programmatically, create an View.OnClickListener object and assign it to the button
by calling setOnClickListener(View.OnClickListener).

For example:

public class MainActivity extends AppCompatActivity {


Button btnshow;
TextView txtshow;
EditText txtedit;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
btnshow=(Button) findViewById( R.id.showbtn );
txtshow =(TextView) findViewById( R.id.showtxt );
txtedit=(EditText) findViewById( R.id.edittxt );
btnshow.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View view) {

String text= txtedit.getText().toString();


txtshow.setVisibility( View.VISIBLE );
txtshow.setText( "After click me!!! "+ text);

}
} );

5.3.3 . Styling Button

The appearance of button (background image and font) may vary from one device to another, because devices
by different manufacturers often have different default styles for input controls.
We can control exactly how our controls are styled using a theme that we apply to our entire application. For
instance, to ensure that all devices running Android 8.0 and higher use the AppThem theme in the app, declare
android:theme="@style/AppTheme" in the manifest's <application> element.

To customize individual buttons with a different background, specify the android:background attribute with a
drawable or color resource. Alternatively, we can apply a style for the button, which works in a manner similar to
HTML styles to define multiple style properties such as the background, font, size, and others.

<Button
....
android:textStyle="bold"
android:textColor="#FFFFFF"
android:background="#00BCD4"
.../>

5.3.4 . Borderless button

One design that can be useful is a "borderless" button. Borderless buttons resemble basic buttons except that they
have no borders or background but still change appearance during different states, such as when clicked.

To create a borderless button, apply the borderlessButtonStyle style to the button. For example:

<Button
...
android:textStyle="bold"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:textColor="#FFFFFF"
../>

5.3.5 . Custom background

Instead of supplying a simple bitmap or color, however, our background should be a state list resource that
changes appearance depending on the button's current state. We can define the state list in an XML file that
defines three different images or colors to use for the different button states.

To create a state list drawable for your button background:

1. Create three bitmaps for the button background that represent the default, pressed, and focused button
states.

To ensure that the images fit buttons of various sizes, create the bitmaps as Nine-patch bitmaps.
2. Place the bitmaps into the res/drawable/ directory of our project. Be sure each bitmap is named properly
to reflect the button state that they each represent, such as. button_default.9.png and
button_pressed.9.png.
3. Create a new XML file in the res/drawable/ directory (name it something like
button_custom.xml). Insert the following XML:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/53-reminder"
android:state_pressed="true" />
<item android:drawable="@drawable/button_focused"
android:state_focused="true" />
<item android:drawable="@drawable/button_default" />
</selector>

l This defines a single drawable resource, which will change its image based on the current state of
the button.
l The first <item> defines the bitmap to use when the button is pressed (activated).
l The second <item> defines the bitmap to use when the button is focused (when the button is
highlighted using the trackball or directional pad).
l The third <item> defines the bitmap to use when the button is in the default state (it's neither
pressed nor focused).
Note: The order of the <item> elements is important. When this drawable is referenced, the <item> elements
are traversed in-order to determine which one is appropriate for the current button state. Because the default
bitmap is last, it is only applied when the conditions android:state_pressed and
android:state_focused have both evaluated as false.

This XML file now represents a single drawable resource and when referenced by a Button for its background,
the image displayed will change based on these three states.
l Then simply apply the drawable XML file as the button background:
<Button
android:id="@+id/showbtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:textSize="20dp"
android:text="@string/btn_show"
android:textColor="#FFFFFF"
android:background="@drawable/custom_button"
../>
5.4 . Checkboxes
Checkboxes allow the user to select one or more options from a set. Typically, you should present each checkbox
option in a vertical list.

To create each checkbox option, create a CheckBox in your layout. Because a set of checkbox options allows the
user to select multiple items, each checkbox is managed separately and you must register a click listener for each
one.

A key class is the following:

l CheckBox

5.4.1 . Responding to Click Events

To define the click event handler for a checkbox, add the android:onClick attribute to the <CheckBox> element
in your XML layout. The value for this attribute must be the name of the method you want to call in response to
a click event. The Activity hosting the layout must then implement the corresponding method.

For example, here are a couple CheckBox objects in a list:

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<CheckBox android:id="@+id/checkbox_meat"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/meat"
android:onClick="onCheckboxClicked"/>
<CheckBox android:id="@+id/checkbox_cheese"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cheese"
android:onClick="onCheckboxClicked"/>
</LinearLayout>

Within the Activity that hosts this layout, the following method handles the click event for both checkboxes:

public void onCheckboxClicked(View view) {


// Is the view now checked?
boolean checked = ((CheckBox) view).isChecked();
// Check which checkbox was clicked
switch(view.getId()) {
case R.id.checkbox_meat:
if (checked)
// Put some meat on the sandwich
else
// Remove the meat
break;
case R.id.checkbox_cheese:
if (checked)
// Cheese me
else
// I'm lactose intolerant
break;
// TODO: Veggie sandwich
}
}

The method you declare in the android:onClick attribute must have a signature exactly as shown above.
Specifically, the method must:

l Be public
l Return void
l Define a View as its only parameter (this will be the View that was clicked)

Tip: If you need to change the checkbox state yourself, use the setChecked(boolean) or toggle() method.

5.5 . Radio Buttons


Radio buttons allow the user to select one option from a set. You should use radio buttons for optional sets that
are mutually exclusive if you think that the user needs to see all available options side-by-side. If it's not
necessary to show all options side-by-side, use a spinner instead.

To create each radio button option, create a RadioButton in your layout. However, because radio buttons are
mutually exclusive, you must group them together inside a RadioGroup. By grouping them together, the system
ensures that only one radio button can be selected at a time.
Key classes are the following:

l RadioButton
l RadioGroup

5.5.1 . Responding to Click Events


When the user selects one of the radio buttons, the corresponding RadioButton object receives an on-click event.
To define the click event handler for a button, add the android:onClick attribute to the <RadioButton> element in
your XML layout. The value for this attribute must be the name of the method you want to call in response to a
click event. The Activity hosting the layout must then implement the corresponding method.

For example, here are a couple RadioButton objects:

<?xml version="1.0" encoding="utf-8"?>


<RadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RadioButton android:id="@+id/radio_pirates"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pirates"
android:onClick="onRadioButtonClicked"/>
<RadioButton android:id="@+id/radio_ninjas"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/ninjas"
android:onClick="onRadioButtonClicked"/>
</RadioGroup>

Note: The RadioGroup is a subclass of LinearLayout that has a vertical orientation by default.
Within the Activity that hosts this layout, the following method handles the click event for both radio
buttons:
public void onRadioButtonClicked(View view) {
// Is the button now checked?
boolean checked = ((RadioButton) view).isChecked();
// Check which radio button was clicked
switch(view.getId()) {
case R.id.radio_pirates:
if (checked)
// Pirates are the best
break;
case R.id.radio_ninjas:
if (checked)
// Ninjas rule
break;
}
}
The method you declare in the android:onClick attribute must have a signature exactly as shown above.
Specifically, the method must:

l Be public
l Return void
l Define a View as its only parameter (this will be the View that was clicked)

Tip: If you need to change the radio button state yourself, use the setChecked(boolean) or toggle() method.

5.6 . Toggle Buttons


A toggle button allows the user to change a setting between two states.

We can add a basic toggle button to your layout with the ToggleButton object. Android 4.0 (API level 14)
introduces another kind of toggle button called a switch that provides a slider control, which you can add with a
Switch object. SwitchCompat is a version of the Switch widget which runs on devices back to API 7.

If you need to change a button's state yourself, you can use the CompoundButton.setChecked() or
CompoundButton.toggle() method.

Switches (in Android 4.0+)


Toggle buttons

Key classes are the following:

l ToggleButton
l Switch
l SwitchCompat
l CompoundButton

5.6.1 . Responding to Button Presses

To detect when the user activates the button or switch, create an CompoundButton.OnCheckedChangeListener
object and assign it to the button by calling setOnCheckedChangeListener(). For example:

ToggleButton toggle = (ToggleButton) findViewById(R.id.togglebutton);


toggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
// The toggle is enabled
} else {
// The toggle is disabled
}
}
});

5.7 . Spinners
Spinners provide a quick way to select one value from a set. In the default state, a spinner shows its currently
selected value. Touching the spinner displays a dropdown menu with all other available values, from which the
user can select a new one.

You can add a spinner to your layout with the Spinner object. You should usually do so in your XML layout
with a <Spinner> element. For example:
<Spinner
android:id="@+id/planets_spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />

To populate the spinner with a list of choices, you then need to specify a SpinnerAdapter in your
Activity or Fragment source code.

Key classes are the following:


l Spinner
l SpinnerAdapter
l AdapterView.OnItemSelectedListener
5.7.1 . Populate the Spinner with User Choices

The choices you provide for the spinner can come from any source, but must be provided through an
SpinnerAdapter, such as an ArrayAdapter if the choices are available in an array or a CursorAdapter if the
choices are available from a database query.

For instance, if the available choices for your spinner are pre-determined, you can provide them with a string
array defined in a string resource file:

<?xml version="1.0" encoding="utf-8"?>


<resources>
<string-array name="planets_array">
<item>Mercury</item>
<item>Venus</item>
<item>Earth</item>
<item>Mars</item>
<item>Jupiter</item>
</string-array>
</resources>

With an array such as this one, we can use the following code in your Activity or Fragment to supply the
spinner with the array using an instance of ArrayAdapter:

Spinner spinner = (Spinner) findViewById(R.id.spinner);


// Create an ArrayAdapter using the string array and a default spinner layout
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
R.array.planets_array, android.R.layout.simple_spinner_item);
// Specify the layout to use when the list of choices appears
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
// Apply the adapter to the spinner
spinner.setAdapter(adapter);

The createFromResource() method allows you to create an ArrayAdapter from the string array. The third
argument for this method is a layout resource that defines how the selected choice appears in the spinner control.
The simple_spinner_item layout is provided by the platform and is the default layout you should use unless you'd
like to define your own layout for the spinner's appearance.

You should then call setDropDownViewResource(int) to specify the layout the adapter should use to display the
list of spinner choices (simple_spinner_dropdown_item is another standard layout defined by the platform).

Call setAdapter() to apply the adapter to your Spinner.


5.7.2 . Responding to User Selections

When the user selects an item from the drop-down, the Spinner object receives an on-item-selected event.

To define the selection event handler for a spinner, implement the AdapterView.OnItemSelectedListener
interface and the corresponding onItemSelected() callback method. For example, here's an implementation of the
interface in an Activity:

public class SpinnerActivity extends Activity implements OnItemSelectedListener {


...
public void onItemSelected(AdapterView<?> parent, View view,
int pos, long id) {
// An item was selected. You can retrieve the selected item using
// parent.getItemAtPosition(pos)
}
public void onNothingSelected(AdapterView<?> parent) {
// Another interface callback
}
}

The AdapterView.OnItemSelectedListener requires the onItemSelected() and


onNothingSelected() callback methods.

Then you need to specify the interface implementation by calling setOnItemSelectedListener():


Spinner spinner = (Spinner) findViewById(R.id.spinner);
spinner.setOnItemSelectedListener(this);

If you implement the AdapterView.OnItemSelectedListener interface with your Activity or


Fragment (such as in the example above), you can pass this as the interface instance.

5.8 . Pickers
Android provides controls for the user to pick a time or pick a date as ready-to-use dialogs. Each picker provides
controls for selecting each part of the time (hour, minute, AM/PM) or date (month, day, year). Using these
pickers helps ensure that your users can pick a time or date that is valid, formatted correctly, and adjusted to the
user's locale.
We recommend that we use DialogFragment to host each time or date picker. The DialogFragment manages the
dialog lifecycle for you and allows to display the pickers in different layout configurations, such as in a basic
dialog on handsets or as an embedded part of the layout on large screens.

Although DialogFragment was first added to the platform in Android 3.0 (API level 11), if our app supports
versions of Android older than 3.0 even as low as Android 1.6 we can use the DialogFragment class that's
available in the support library for backward compatibility.

Note: The code samples below show how to create dialogs for a time picker and date picker using the support
library APIs for DialogFragment. If our app's minSdkVersion is 11 or higher, we can instead use the platform
version of DialogFragment.

Key classes are the following:

l DatePickerDialog
l TimePickerDialog

Also see the Fragments overview.

5.8.1 . Creating a Time Picker

To display a TimePickerDialog using DialogFragment, you need to define a fragment class that extends
DialogFragment and return a TimePickerDialog from the fragment's onCreateDialog() method.

Note: If your app supports versions of Android older than 3.0, be sure you've set up your Android project with
the support library as described in Setting Up a Project to Use a Library.

5.8.2 . Extending DialogFragment for a time picker

To define a DialogFragment for a TimePickerDialog, you must:


l Define the onCreateDialog() method to return an instance of TimePickerDialog
l Implement the TimePickerDialog.OnTimeSetListener interface to receive a callback when the user sets
the time.

Here's an example:

public static class TimePickerFragment extends DialogFragment


implements TimePickerDialog.OnTimeSetListener {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Use the current time as the default values for the picker
final Calendar c = Calendar.getInstance();
int hour = c.get(Calendar.HOUR_OF_DAY);
int minute = c.get(Calendar.MINUTE);
// Create a new instance of TimePickerDialog and return it
return new TimePickerDialog(getActivity(), this, hour, minute,
DateFormat.is24HourFormat(getActivity()));
}
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
// Do something with the time chosen by the user
}
}

Now all you need is an event that adds an instance of this fragment to your activity.

5.8.3 . Showing the time picker

Once you've defined a DialogFragment like the one shown above, you can display the time picker by creating an
instance of the DialogFragment and calling show().

For example, here's a button that, when clicked, calls a method to show the dialog:

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pick_time"
android:onClick="showTimePickerDialog" />

When the user clicks this button, the system calls the following method:
public void showTimePickerDialog(View v) {
DialogFragment newFragment = new TimePickerFragment();
newFragment.show(getSupportFragmentManager(), "timePicker");
}

This method calls show() on a new instance of the DialogFragment defined above. The show() method requires
an instance of FragmentManager and a unique tag name for the fragment.

Caution: If your app supports versions of Android lower than 3.0, be sure that you call
getSupportFragmentManager() to acquire an instance of FragmentManager. Also make sure that your activity
that displays the time picker extends FragmentActivity instead of the standard Activity class.

5.8.4 . Creating a Date picker

Creating a DatePickerDialog is just like creating a TimePickerDialog. The only difference is the dialog you
create for the fragment.

To display a DatePickerDialog using DialogFragment, you need to define a fragment class that extends
DialogFragment and return a DatePickerDialog from the fragment's onCreateDialog() method.

5.8.5 . Extending DialogFragment for a date picker

To define a DialogFragment for a DatePickerDialog, you must:

l Define the onCreateDialog() method to return an instance of DatePickerDialog


l Implement the DatePickerDialog.OnDateSetListener interface to receive a callback when the user sets the
date.

Here's an example:

public static class DatePickerFragment extends DialogFragment


implements DatePickerDialog.OnDateSetListener {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Use the current date as the default date in the picker
final Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH);
int day = c.get(Calendar.DAY_OF_MONTH);
// Create a new instance of DatePickerDialog and return it
return new DatePickerDialog(getActivity(), this, year, month, day);
}
public void onDateSet(DatePicker view, int year, int month, int day) {
// Do something with the date chosen by the user
}
}

See the DatePickerDialog class for information about the constructor arguments. Now all you need is an event
that adds an instance of this fragment to your activity.

5.8.6 . Showing the date picker

Once you've defined a DialogFragment like the one shown above, you can display the date picker by creating an
instance of the DialogFragment and calling show().

For example, here's a button that, when clicked, calls a method to show the dialog:

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pick_date"
android:onClick="showDatePickerDialog" />

When the user clicks this button, the system calls the following method:

public void showDatePickerDialog(View v) {


DialogFragment newFragment = new DatePickerFragment();
newFragment.show(getSupportFragmentManager(), "datePicker");
}

This method calls show() on a new instance of the DialogFragment defined above. The show() method requires
an instance of FragmentManager and a unique tag name for the fragment.

5.8.7 . Using pickers with autofill

Android 8.0 introduces the Autofill Framework, which allows users to save data that can be later used to fill out
forms in different apps. Pickers can be useful in autofill scenarios by providing a UI that lets users change the
value of a field that stores date or time data. For example, in a credit card form, a date picker would allow users
to enter or change the expiration date of their credit card.

Because pickers are dialogs, they aren't displayed in an activity along with other fields. To display the picker data
when the picker isn't visible, you can use another view, such as an EditText, which can display the value when
the picker isn't visible.

An EditText object natively expects autofill data of type AUTOFILL_TYPE_TEXT. In contrast, autofill services
should save the data as AUTOFILL_TYPE_DATE to be able to create an appropriate representation of it. To
solve the inconsistency in types, it's recommended that you create a custom view that inherits from EditText and
implements the methods required to correctly handle values of type AUTOFILL_TYPE_DATE.

You should take the following steps to create a subclass of EditText that can handle values of type
AUTOFILL_TYPE_DATE:

1. Create a class that inherits from EditText.


2. Implement the getAutofillType() method, which should return AUTOFILL_TYPE_DATE.
3. Implement the getAutofillValue() method, which should return an AutofillValue object that represents the
date in milliseconds. To create the return object, use the forDate() method to generate an AutofillValue
object.
4. Implement the autofill() method. This method provides the logic to handle the AutofillValue parameter,
which is of type AUTOFILL_TYPE_DATE. To handle the parameter, create a proper string
representation of it, such as mm/yyyy. Use the string representation to set the text property of your view.
5. Implement functionality that displays a picker when the user wants to edit the date in the custom subclass
of EditText. The view should update the text property with a string representation of the value that the
user selected on the picker.

5.9 . Tooltips
A tooltip is a small descriptive message that appears near a view when users long press the view or hover their
mouse over it. This is useful when your app uses an icon to represent an action or piece of information to save
space in the layout. This page shows you how to add these tooltips on Android 8.0 (API level 26) and higher.

Some scenarios, such as those in productivity apps, require a descriptive method of communicating ideas and
actions. You can use tooltips to display a descriptive message, as shown in figure 1.
Figure 1. Tooltip displayed in an Android app.

Some standard widgets display tooltips based on the content of the title or content description properties. Starting
in Android 8.0, you can specify the text displayed in the tooltip regardless of the value of other properties.

5.9.1 . Setting the tooltip text

You can specify the tooltip text in a View by calling the setTooltipText() method. You can set the tooltipText
property using the corresponding XML attribute or API.

To specify the tooltip text in your XML files, set the android:tooltipText attribute, as shown in the following
example:

<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:tooltipText="Send an email" />

To specify the tooltip text in your code, use the setTooltipText(CharSequence) method, as shown in the following
example:

FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);


fab.setTooltipText("Send an email");

The API also includes a getTooltipText() method that you can use to retrieve the value of the tooltipText
property.

Android displays the value of the tooltipText property when users hover their mouse over the view or long press
the view.
5.10 . Toasts
A toast provides simple feedback about an operation in a small popup. It only fills the amount of space required
for the message and the current activity remains visible and interactive. Toasts automatically disappear after a
timeout.

For example, clicking Send on an email triggers a "Sending message..." toast, as shown in the following screen
capture:

Toasts are not clickable. If user response to a status message is required, consider instead using a Notification.

5.10.1 . The Basics

First, instantiate a Toast object with one of the makeText() methods. This method takes three parameters: the
application Context, the text message, and the duration for the toast. It returns a properly initialized Toast object.
You can display the toast notification with show(), as shown in the following example:

Context context = getApplicationContext();


CharSequence text = "Hello toast!";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();

This example demonstrates everything you need for most toast notifications. You should rarely need anything
else. You may, however, want to position the toast differently or even use your own layout instead of a simple
text message. The following sections describe how you can do these things.
You can also chain your methods and avoid holding on to the Toast object, like this:

Toast.makeText(context, text, duration).show();

5.10.2 . Positioning our Toast

A standard toast notification appears near the bottom of the screen, centered horizontally. You can change this
position with the setGravity(int, int, int) method. This accepts three parameters: a Gravity constant, an x-position
offset, and a y-position offset.

For example, if you decide that the toast should appear in the top-left corner, you can set the gravity like this:

toast.setGravity(Gravity.TOP|Gravity.LEFT, 0, 0);

If you want to nudge the position to the right, increase the value of the second parameter. To nudge it down,
increase the value of the last parameter.

5.10.3 . Creating a custom Toast View

If a simple text message isn't enough, you can create a customized layout for your toast notification. To create a
custom layout, define a View layout, in XML or in your application code, and pass the root View object to the
setView(View) method.

The following snippet contains a customized layout for a toast notification (saved as layout/custom_toast.xml):

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/custom_toast_container"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="8dp"
android:background="#DAAA"
>
<ImageView android:src="@drawable/droid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="8dp"
/>
<TextView android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FFF"
/>
</LinearLayout>

Notice that the ID of the LinearLayout element is "custom_toast_container". You must use this ID and the ID of
the XML layout file "custom_toast" to inflate the layout, as shown here:

LayoutInflater inflater = getLayoutInflater();


View layout = inflater.inflate(R.layout.custom_toast,
(ViewGroup) findViewById(R.id.custom_toast_container));
TextView text = (TextView) layout.findViewById(R.id.text);
text.setText("This is a custom toast");
Toast toast = new Toast(getApplicationContext());
toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
toast.setDuration(Toast.LENGTH_LONG);
toast.setView(layout);
toast.show();

First, retrieve the LayoutInflater with getLayoutInflater() (or getSystemService()), and then inflate the layout
from XML using inflate(int, ViewGroup). The first parameter is the layout resource ID and the second is the root
View. You can use this inflated layout to find more View objects in the layout, so now capture and define the
content for the ImageView and TextView elements. Finally, create a new Toast with Toast(Context) and set some
properties of the toast, such as the gravity and duration. Then call setView(View) and pass it the inflated layout.
You can now display the toast with your custom layout by calling show().

Note: Do not use the public constructor for a Toast unless you are going to define the layout with setView(View).
If you do not have a custom layout to use, you must use makeText(Context, int, int) to create the Toast.
Chapter Six

6. Android Projects
6.1 . Meter to Inches

The first project may implements change meters to inches unites that accepts any values from the user. First
create a new project from android studio names MeterToInche as project name inside a package's.

The first things I am going to do is to add a new image to our resource files. So, we are going to go ahead and
open the resource here, and the right-click drawable and then select show as file which allow us directly access

path to where this folder.


Then
when we
have
Images
in our

directories then drag from our image directories and drop in drawable file directory(or we can copy and past the
images into our drawable folder in android studio.

After load all necessary images into our working drawable directory then the first things that we have do is
adding ImageView into our layout. And also, make sure all constraint both left,right, top and bottom.
Then
save and
run in
order to
see on
our
emulator
and the
output
will
seems
like the

following pictures.

<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.612"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.016"
app:srcCompat="@drawable/meters_inches" />

Now, we going to add plain text that gives name and put in the center. And also, be empty and add hints to it.
Here, make sure that access number and number of decimal only rather string by set the type number and
numberDecimal to the layout.

<EditText
android:id="@+id/meterEditTextId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:ems="10"
android:hint="Enter meters values"
android:inputType="number|numberDecimal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.578"
app:layout_constraintStart_toStartOf="parent"

app:layout_constraintTop_toBottomOf="@+id/imageView"
app:layout_constraintVertical_bias="0.039" />

Then add button to our layout and make sure nicely centered and change text
from button to converted text.

<Button
android:id="@+id/convertedId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:background="@color/colorAccent"
android:text="Converted"
android:textColor="#FFF"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/meterEditTextId"
app:layout_constraintVertical_bias="0.108" />

Lastly , add text view that where going to show the converted values. Here we have initially invisible this
components.

<TextView
android:id="@+id/resultId"
android:layout_width="wrap_content"
android:layout_height="44dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/convertedId"
app:layout_constraintVertical_bias="0.258" />

We have finished the layout, now we are going to implements the java class. To implements the converter we
have to figure out how many inches are there in a meter

That is 1M=39.37011 inches

The default block of MainActivity.java files looks as follows

package com.course.metertoinche;
import androidx.appcompat.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 );
}
}

Then inside this file defined all instances like Button,TextFields and EditText instance inside the class.

public class MainActivity extends AppCompatActivity {


private EditText meterValues;
private Button convertButton;
private TextView showResultTxt;

Then instantiate all instances inside onCreate() mmethods in java class as follows
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
enterMeter=(EditText) findViewById( R.id.meterEditTextId );
convertButton=(Button) findViewById( R.id.convertedId );
showResultTxt=(TextView)findViewById( R.id.resultId );

Then we have add onClick Action Listners, the idea here when we have entering a number in EditText then we’ll
able to convert that number by clicking the button and shows inside another TextViews.

convertButton.setOnClickListener( new View.OnClickListener() {


@Override
public void onClick(View view) {
String meterValue=enterMeter.getText().toString();
double meter=Double.parseDouble( meterValue );
double convetedValues=meter*39.3701;
showResultTxt.setText( meter+" meters ="+ convetedValues+" inches" );
}
} );

And also, we can actually use a string format function that will help us round our decimal point instead of having
a bunch of them we can just round up to two decimal points.

The string format function is String.format( "%.2f",convertdValues). Here, the first parameter is we are going to
convert this into two decimal points. And the next parameter is we have to pass is the actual argument or the
result.

showResultTxt.setText(meterValue + "meters =" +String.format( "%.2f",result) + "inches" );

To prevent empity textfield converte we have used simple if..else condition

convertButton.setOnClickListener( new View.OnClickListener() {


@Override
public void onClick(View view) {
double result=0.0;
double multiplier=39.3701;
if (enterMeter.getText().toString().equals( "" )){
showResultTxt.setText( R.string.error_message );
showResultTxt.setTextColor( Color.RED );
}else {
double meterValue = Double.parseDouble( enterMeter.getText().toString() );
result = meterValue * multiplier;
showResultTxt.setText( meterValue + " meters =" +String.format( "%.2f",result) + " inches" );
}
}
} );

6.2 . Change color randomly

In this application, going to develop an application change different colors when we click the button and we call
the button ‘try me!’. So, go head and create a new project in android studio. In order to develop the apps we have
add the images that we need in our button as background into drawable folders inside android studio.

Firstly, we care about background which means we need to figure out how access our background because in our
project change the background color randomly. So, to access the background firstly we have to set an ID to the
view. Here, we going to set windowsViewID as an id.

<?xml version="1.0" encoding="utf-8"?>


<androidx.constraintlayout.widget.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"
android:id="@+id/windowsViewID"
tools:context=".MainActivity">
The next thing is,we want to add a button in the layout, make sure put the centered and all constraints. And also
gives an ID called tryMeButton, change background into our images that loads before, change text color to white
for more readable to the our background and change the text size to make id a little bit bigger so here go to
textSize from the properly(Attribute) then set 18sp or as we want.

<Button
android:id="@+id/tryMeButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/round_b"
android:text="@string/try_me"
android:textColor="#FFF"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

Now, we have finished the layout for our apps. The next step is implements the internal details in java program.
So, we going to MianActivity.java file. Inside java class firstly we want to declare the View and Button instances
as follows:

private View windowsView;


private Button tryMeButton;

Then, instantiate all instances inside onCreate() methods in the class as follows:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
windowsView=findViewById( R.id.windowsViewID );
tryMeButton=(Button)findViewById( R.id.tryMeButton );
}
In in the first Instantiate no need to cast because windowsView instance is Instantiate View and
everything considers as View in the Layout. But the next Button class should be converted into Button for
instantiate from View initially.

After Instantiate the next step is, implements onclick listener, here we are going to implements our logic that will be called
once we tap on the button as follows:

tryMeButton.setOnClickListener( new View.OnClickListener() {


@Override
public void onClick(View view) {

}
} );

First let us try by Log.d in dubeging. So, there is a class Log class that allow us to see what our apps doing on
consule. The user canot able to see this log but the developers need to be able to see the debug or see things or
test things out in the applications when we are building them. We are going to head here and say Log.d where
Log is a class and d means debug and passing two parameter as follows:

Log.d( "Test","Color changes" );

Now, we going to save and run to check our applications is succesfully build or not. When the following message
seen in the console when we click the button our apps working well.

D/Test: Color changes

But, our aim is changing background colors dynamically. So, we want to randomly generate a number that would
correspond to a certain color because in order to change the background color we have used setBackground
methods and this method accepts Integer values. Hence , user array to store many items that have the same type.
Here, we have declare integer array that holds Integer values and we need name it colors inside java class.

private int[] colors;

Let’s go ahead and create the actual array so we are going to say colors is equal to New int[] it is very interesting
notation for instantiate a new array of Integer and also inserting items into an array. Hence, all items are colors.

colors=new int[]
{Color.GRAY,Color.GREEN,Color.BLUE,Color.BLACK,Color.WHITE,Color.YELLOW
Color.CYAN,Color.MAGENTA,Color.TRANSPARENT,Color.LTGRAY};
After here, they need figure out away to create random numbers so there is a class called Random class that will
help as to randomly choose colors from an array colors. The class created inside onclick() methods because it
happens when we taped the button.

Random random=new Random( );

And now, we are going to go head and create the actual random number at a given time. So, we need to create
integer variable that holds random numbers at a time. Hence, to assign a value to a variable we use random
objects random and invoke into nextInt() methods to start random numbers. In the method pass the length of
colors array because we creating random numbers the range is between 0 and 100 or 0 to 300 or 0 to 5. In our
case we want to make sure each time that we tap the button we get a number that is between 0 and length of
colors array and never go beyond the length of array.

int colorsArrayLength=colors.length;
Random random=new Random( );
int colorsIndex=random.nextInt(colorsArrayLength);

Finally, to access each colors from colors array through the index number and set to the background in order to
change.

windowsView.setBackgroundColor(colors[colorsIndex] );

The full java code look like the following

package com.course.changerandomcolor;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import java.util.Random;
public class MainActivity extends AppCompatActivity {
private View windowsView;
private Button tryMeButton;
private int[] colors;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
colors=new int[]{Color.GRAY,Color.GREEN,Color.BLUE,Color.BLACK, Color.WHITE, +
Color.YELLOW,Color.CYAN,Color.MAGENTA,Color.TRANSPARENT,Color.LTGRAY};
windowsView=findViewById( R.id.windowsViewID );
tryMeButton=(Button)findViewById( R.id.tryMeButton );
tryMeButton.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View view) {
int colorsArrayLength=colors.length;
Random random=new Random( );
int colorsIndex=random.nextInt(colorsArrayLength);
windowsView.setBackgroundColor(colors[colorsIndex] );
}
} );
}}

6.3 . Android Widgets

Widgets in general view like Button,Text view ,Radio button and so on. The next widget we are doing an apps
going to be Radio Button. Now, create a new project and call it RadioButtonApps in Android Studio. So, once
we have open the activity xml to desing the apps and get Radio and RadioGroup from the plate. Radio button's
is just button that allows the user turn it on/off and usually use in RadioGroup because the idea is allow the user
select only one option from a certain group. Since, RadioGroup that will host the Radio buttons up very easily.
So , firstly add Radio button group from the plate to our layout before Radio Button and make sure it in the
middle.

<RadioGroup
android:id="@+id/radioGroupId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.498">
Now, once we have RadioGroup we can add Radio button into our Radio Groups. Hence, puts all radio buttons
inside our Radio group that have the same regularly a group. Note, our Android studio here just give all radio
buttons random names can change that no problem. So, now change Radio buttons name and gives different ID
in Attributes or in text tag in xml. For the name of each Radio button let’s say the first Yes, the next we are going
say may be and the lat say No as option. Notice that radio button allow the selection of one option.

<RadioButton
android:id="@+id/noId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="No" />
<RadioButton
android:id="@+id/maybeId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="May Be" />

Now, we have radio button(yes, maybe and no) options lets us put the textField
which is display which button is click. So, add TextView from plate or write
the code in xml layout file at the top of our radio group. In fact, change a few things to make it a little bit bigger
and change the font. Since, let’s set 24sp Textsize, attending? as text name and give an id to this component.

Now, what are going to do our main activity the java class. Firstly, we want to declare all instances by private
access modifier and first we are going to connect radioGroup and then for radio buttons. Here, the radio group
are parent container for our Radio buttons.
private RadioGroup radioGroup;
private RadioButton radioButton;
private TextView attendTextView;

Now, we have Radio group which contains all of our radio button what do we need to do now is to connect this
radio group to an event listener because the idea is to have user click on the buttons. So what we say invoking to
setOnChekedChangeListner() methods and pass new radio group that actually read group that own check to
listner. Hence, the method they are using here instantiate on checked listener and inside here we have to override
the on checked passes in the group as follows.

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
radioGroup=(RadioGroup)findViewById( R.id.radioGroupId );

radioGroup.setOnCheckedChangeListener( new RadioGroup.OnCheckedChangeListener() {


@Override
public void onCheckedChanged(RadioGroup radioGroup, int i) {

}
} );

Now, just check the ID here contains the ID of each buttons or each radio buttons so that we can handle
everything inside of our own check to change method. Here,we can access to the group and also we have access
to the IDs of each items inside of our Group. So, inside onCheckedChanged() methods we are going to instantiate
the radio button and since we know that we have the IDs inside the methods being passed and find one ID that
would just take care of one button which is not what we want. So, we are going to dynamically pass this
checked ID which this checkedID contain the IDs of each of the selected or clicked radio button.

public void onCheckedChanged(RadioGroup radioGroup, int checkedID) {


radioButton=(RadioButton)findViewById( checkedID );
}
} );

Now, since we have more thane one radio buttons we need to find a way to go through and check which button
has been selected. And the easiest wey is use switch statement that allows us switch through our choice and the
switch statement used IDs of each radio button. And inside the block use case which going to done we have here
radio that get IDs are getting of each button that its being clicked or tapped and then we were checked. And
lastly set to Text View which button is selected.

radioButton=(RadioButton)findViewById( checkedID );

switch (radioButton.getId()){
case R.id.yesID:
attendTextView.append( "Yes!!" );
break;
case R.id.maybeId:
if (radioButton.isChecked()) {
attendTextView.append( "May be!!" );
}
break;
case R.id.noId:
attendTextView.setText( " Nope" );
break;
default:
attendTextView.setText( "plaese select button!!" );
}

The full code for java class look like:

package com.course.radiobuttonapps;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Switch;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private RadioGroup radioGroup;
private RadioButton radioButton;
private TextView attendTextView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
radioGroup=(RadioGroup)findViewById( R.id.radioGroupId );
attendTextView=(TextView)findViewById( R.id.attendtextViewId );
radioGroup.setOnCheckedChangeListener( new
RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup radioGroup, int checkedID) {
radioButton=(RadioButton)findViewById( checkedID );

switch (radioButton.getId()){
case R.id.yesID:
attendTextView.setText( "Attending? Yes!!" );
break;
case R.id.maybeId:
if (radioButton.isChecked()) {
attendTextView.append( "Attending? May be!!" );
}
break;
case R.id.noId:
attendTextView.setText( " Attending? Nope" );
break;
default:
attendTextView.setText( "plaese select button!!" );
}
}
} );
}
}
6.4 . Android SeekBar

Now, we going to discussed about another widget called seekbar a snack bar which means when drag our finger
gets some values. Now, we going to create an applications will essentially allow users to tell us what is their
plane scale of 1 to 10. So firstly, we going to add seekbar from plate in android studio IDE and make sure put in
center. And also, we want to change its property and turns out to seekbar has maximum progress until that we
can set. Here, first change the maximum by tap maximum from property or attribute and set as we want but in
our case we set 10 that our max progress level( android:max="10"). And next, lets a little bit bigger so what we
going to do into the layout and set "fill_parent" in android:layout_width want to emphasize the seek bar as
follows:

android:layout_width="fill_parent"

The full code for seek bar xml layout as follows:


<SeekBar
android:id="@+id/seekBarID"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:max="10"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

Then add two TextView which going to gives some information and put a level when the user select their pain
level from the seek bar. And also, what going to happen is as we move left to right or the vise verse we will
updating the text in the text field. In the second TextField change the text to empty and litle bit bigger like 20sp
text size.

<TextView
android:id="@+id/painlevelID"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/seekBar" />

Next, we are going to be implement our main activity java class. Firstly, we are going to connect our widgets.
private SeekBar seekBar;
private TextView resultPainlevel;

Then instantiate all instances that created/connected above

seekBar=(SeekBar)findViewById( R.id.seekBarID );
resultPainlevel=(TextView)findViewById( R.id.painlevelID );

Then the next thing we need to do attached the seekbar to an event listener because we want to make sure that we
can track and catch all of those event listener as they drags the seek bar left to right as follows:

seekBar.setOnSeekBarChangeListener( new SeekBar.OnSeekBarChangeListener() {


@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {

}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {

}} );

In the above code the first method is onProgressChanged() which passes our seek bar, progress and fromuser
parameters/arguments. And also both onStartTrackingTouch() and onStopTrackingTouch() takes Seekbar
arguments. So, all of these methods they catch the events at different phase as the users go through the process of
dragging the seek bar.

As example, we going to use logs what we see in which what’s happening. So, here write Log class with
debugging methods and pass tag and message string values as we want that describes our works. And copy to all
methods inside the seek bar listener.

Log.d("Seek Bar","on progerss seek bar");

And run the program going to see a certain events in seek listener when our program is build successfully the
following output is display on the console when we drag seek bar. When we touched earlier it says on start
tracking and on stop go back and show everything what progess go on
D/SeekBar: on progeress seek bar

D/SeekBar: on traking touch

D/SeekBar: on start tracking

Now, we are going to show our result from seek bar to text view the
progress that has been made. So, we are going to now replace log debugging by the actual implementation.
Since, set the text that gets from seek bar progress what doing here seek bar is being passed on our
onProgressChange in the first parameter so able to get this object seek bar that instantiate before and getProgess
return a number from seek bar we are drag the progress bar. And also, the next method getMax() returns the
maximum numbers that we sets to our seek bar

public void onProgressChanged(SeekBar seekBar, int i, boolean b) {


resultPainlevel.setText( "Pain level:"+seekBar.getProgress()+"/"+seekBar.getMax() );

Finally, let’s run the apps and make sure that in the beginning our level say zero out of 10 so the users at least
have a way of saying oh this is where our pain level is going to show they just user interface. Here, we going to
set a text to our result text view out of Listener events which will see pain level 0 out of 10 initially and the
moment we go a head start moving in seek bar it changes as follows:

resultPainlevel.setText( "Pain level:"+seekBar.getProgress()+"/"+seekBar.getMax() );

At last, let’s change


colors with different pain level once the user drags the seek bar to 6 or grater we want to changes the whole text
to red color. So, how to achieve this important logic where do we set that? The best place to set this up would be
on stop tracking touch method. Well, this reason why is because we want to make sure that behavior happens
when they stop tracking. When they stop moving or dragging the seek bar get the whole text result or the pain
level to read has to be in our start tracking touch method. Since, use if—else statement and set our condition by
getting the progress then change a color when the condition is true. As we have seen the figure when the progress
6 or greater change into red color.
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
if(seekBar.getProgress()>=6){
resultPainlevel.setTextColor( Color.RED );
}else{
resultPainlevel.setTextColor( Color.BLACK );
}

The full java code looks:

package com.course.seekbar;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.widget.SeekBar;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {


private SeekBar seekBar;
private TextView resultPainlevel;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
seekBar=(SeekBar)findViewById( R.id.seekBarID );
resultPainlevel=(TextView)findViewById( R.id.painlevelID );
resultPainlevel.setText( "Pain level:"+seekBar.getProgress()+"/"+seekBar.getMax() );
seekBar.setOnSeekBarChangeListener( new SeekBar.OnSeekBarChangeListener() {
@Override

public void onProgressChanged(SeekBar seekBar, int i, boolean b) {


resultPainlevel.setTextColor( Color.GRAY );
resultPainlevel.setText( "Pain level:"+seekBar.getProgress()+"/"+seekBar.getMax() );

}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
Log.d("Seek Bar","on stark tracking");

@Override
public void onStopTrackingTouch(SeekBar seekBar) {
if(seekBar.getProgress()>=6){
resultPainlevel.setTextColor( Color.RED );
}else{
resultPainlevel.setTextColor( Color.BLACK );
}

}
} );
}}

6.5 . Android
Toggle Button

The Toggle button allows the user to change setting between two state on and off. Here, let’s going to create an
apps for toggle button so first goes to plate in the layout and find Toggle Button then add to screen design layout.
And also, make sure put in the middle and change the id and names in the property for better design.

<ToggleButton
android:id="@+id/toggleButtonID"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ToggleButton"
android:textColor="@color/textColor"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

Now, we are going to add a text view which used to shows which state is selected by the users which means is on
or off taped by the user.

<TextView
android:id="@+id/showId"
android:text="@string/show_togle"
android:textStyle="bold"
app:layout_constraintTop_toBottomOf="@+id/toggleButtonID"
app:layout_constraintVertical_bias="0.266"

android:visibility="invisible"

... />

Now everything are in place so we going to implements the main activity java class. So, start with create all
instances inside the java class and instantiate them inside onCreate() methods as follows:

public class MainActivity extends AppCompatActivity {


private ToggleButton toggleButton;
private TextView showshideTxt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
toggleButton=(ToggleButton)findViewById( R.id.toggleButtonID );
showshideTxt=(TextView)findViewById( R.id.showId );
}
}

Then first set the visibility for text view initially invisible and change through the toggle button what they wants.
Because we wants to make sure that its when the application opens that first time its going to be invisible. Then,
we going to connect our toggle button to any event listener.

toggleButton.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {


@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
}} );

Now, inside the listener add if—else because we know the state its being sent.

if (isChecked){
//the toggle is enabled
}else{
//the toggle is disabled
}

So, what we want to do when its cheked or not? Well we want to show the text view to our user right now that
have some text and initially not showing because the visibility it is invisible. Here, our idea is how to make
visible when the user taps on state in the toggle button or disabled the text view when the toggle button become
off state. Hence, use showshideTxt.setVisibility( View.VISIBLE ); statements because its a view so we have pass
View class and Visible objects to show a text view is called showshideTxt.

if (isChecked){
showshideTxt.setVisibility( View.VISIBLE );
}else{
showshideTxt.setVisibility( View.INVISIBLE );
}

The full code and the finall output will be

package com.course.toggelbutton;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.TextView;
import android.widget.ToggleButton;

public class MainActivity extends AppCompatActivity {


private ToggleButton toggleButton;
private TextView showshideTxt;
@Override
protected void onCreate(Bundle savedInstanceState) {

super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
toggleButton=(ToggleButton)findViewById( R.id.toggleButtonID );
showshideTxt=(TextView)findViewById( R.id.showId );
toggleButton.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
if (isChecked){
//the toggle is enabled
showshideTxt.setVisibility( View.VISIBLE );
}else{
//the toggle is disabled
showshideTxt.setVisibility( View.INVISIBLE );
}

}
} );

6.6 . Android Check box

Android check box is a


types of widgets that
allows to states right
checked or unchecked
instances when we have
an application when we’re asking the user where they have many options. Now we are going to be a simple
applications that will allows us check who’s our favorite persons in the options. Firstly, create each checkbox
option, find a Check Box from our plate in android studio and add/write to our design layout. And also, change
some properties/attributes like id, name, size … for its and make sure everything aligned properly for better
design. And then give the name and id to each checkbox so we are going to gives for first checkbox let’s give
mom and the second gives father and the last gives brother/sister. The xml layout looks as follow:

<CheckBox
android:id="@+id/momID"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/mom"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.283" />

<CheckBox
android:id="@+id/fatherID"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/father"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.519"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/momID"
app:layout_constraintVertical_bias="0.068" />

<CheckBox
android:id="@+id/brosisID"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/brother_sister"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.594"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/fatherID"
app:layout_constraintVertical_bias="0.106" />

And add another Button and Text view to show whatever users have selected or haven’t selected at least the state
of our checkbox. So, let’s put the button and text view on the bottom of all checkboxs and let’s give showBtnID
and resultID respectively as its id and change the name as follows the following xml layout.

<Button
android:id="@+id/showBtnID"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:background="#00BCD4"
android:textColor="#FFF"
android:textSize="20sp"
android:text="@string/showBtn"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.489"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/brosisID" />

<TextView
android:id="@+id/resultID"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/showBtnID"
app:layout_constraintVertical_bias="0.347" />

Now, our design was set as well so let’s going to back main activity java class for implements when the user
check or not check states. Here, firstly we have to connect all instances and instantiate them in the class and
onCreate() methods respectively.

private CheckBox momcheckbox;


momcheckbox=(CheckBox)findViewById( R.id.momID );
...

Next things, we need to do now is connect show button to an event listener. Because a set of checkbox options
allows the user to select multiple items, each checkbox is managed separately and we must register a click
listener for each one.

showBtn.setOnClickListener( new View.OnClickListener() {


@Override
public void onClick(View view) { }
} );

Then, the idea here is make sure when they select mom,father or brother/sister form the options or all of them
and show the states of each checkbox on our text view. Here, checkbox allows to state check or unchecked so
how do we then get those state the checkbox object has all of those properties that we can tap into it. Since, what
we going to do is we have wonderful class is called StringBuilder which construct a string put a string in a buffer
many strings and then set into text view.

StringBuilder stringBuilder=new StringBuilder( );

And then, by using the StringBuilder object is called stringBuilder adding all states of each checkbox to our string
builder by using append() methods and passing each checkbox text and states as a string as follows:

stringBuilder.append(momcheckbox.getText().toString()+" status is:"+momcheckbox.isChecked()+"\n" );


stringBuilder.append(fathecheckbox.getText().toString()+"status is:"+fathecheckbox.isChecked()+"\n" );
stringBuilder.append(brosischeckbox.getText().toString()+"status is:"+brosischeckbox.isChecked() );

So, now we have a string builder built all of the status of all of our checkboxes and we can show all of these
status to our text view(resulttTxt) as follows:

resulttTxt.setText( stringBuilder )

Now, we have finished everything and the the full java code looks and what will be the output in android
emulator as follows:

package com.course.checkboxapps;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;

import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private CheckBox momcheckbox;
private CheckBox fathecheckbox;
private CheckBox brosischeckbox;
private Button showBtn;
private TextView resulttTxt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
momcheckbox=(CheckBox)findViewById( R.id.momID );
fathecheckbox=(CheckBox)findViewById( R.id.fatherID );
brosischeckbox=(CheckBox)findViewById( R.id.brosisID );

resulttTxt=(TextView)findViewById( R.id.resultID );
showBtn=(Button)findViewById( R.id.showBtnID );
showBtn.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View view) {
StringBuilder stringBuilder=new StringBuilder( );
stringBuilder.append( momcheckbox.getText().toString()+" status is:"+momcheckbox.isChecked()+"\
n" );
stringBuilder.append( fathecheckbox.getText().toString()+" status is:"+fathecheckbox.isChecked()+"\
n" );
stringBuilder.append( brosischeckbox.getText().toString()+" status is:"+brosischeckbox.isChecked()
+"\n" );
resulttTxt.setText( stringBuilder );

}
} );
}
}
6.7 . Android Alert Dialog

The dialog is a small window that prompts the user to make a decision or enter additional information. So one of
the thing that we need to realize here is that dialog does not necessary feel the screen and normally used events
that required to take an action before they can proceed. Since, let’s going to do simple apps that shows dialog. So
the first things going to add button and change some property/attributes like id, size and text name. And the xml
layout as follows:

<Button
android:id="@+id/showDialogID"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#03A9F4"
android:text="@string/dialog_btn"
android:textColor="#FFF"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

After create our button the next thing is going to create the alert dialog class and builder because the builder class
will have all the functionalities that we need to create alert dialog and we going to call this alerDialog.

private AlertDialog.Builder alertDialog;

Then, we instantiate or build up alert dialog when the user clicked or tapped the button. So create event listener
to create the actual Dialog here and instantiate the alartBuilder objects inside the listener events as follows:

alertBuilder=new AlertDialog.Builder(MainActivity.this);

Here, we instantiate the Alert Builder we going to be pass the context which is our main activity because we need
displayed our alert dialog in this context means going to be a part of MainActivity so we’ll have this context will
have a home.
The next things we need to do once when we have instantiated alart dialog we can start our alert dialog so we can
things up. The first things set up the title by setTitle() methods and pass title string. When we have string
resource in string.xml we going to access the string values from string resources is as follows:

//setting up-set title

alartDialog.setTitle( R.string.alert_title ); or
alartDialog.setTitle( getResources().getString( R.string.alert_title ) );

When we want to add an icons to our alert dialog in its title or message we can use as follows:

alertDialog.setIcon( android.R.drawable.alert_light_frame );

After setting the title for alert dialog the second step is setting the message to it as follows:

//setting the message


alertDialog.setMessage( getResources().getString( R.string.alert_message ) );

After setting tiles and message of our alert dialog the next step we are going to do is set cancelable which does
the system that the users must select an option before they can cancel out of that window. So, what we do was
say alert dialog that said cancelable and we have to pass in something true/false. When we set false the user will
not be able to cancel the dialog. Which means they have to choose yes or no in order to remove the dialog from
our application.

alertDialog.setCancelable( false );

The next step after set the cancelable states we going to set the buttons. In order to set buttons we going to set
positive and negative buttons use setPositiveButtons() and setNegativeButtons() methods respectively. And also,
pass in the first argument, a String which is a button name and in the second argument pass event listener when
the user’s click the button what will happen as second argument. Here, where we will put whatever needs to
happen when they yes for positive button as follows:

alertDialog.setPositiveButton( getResources().getString( R.string.alert_yes ), new DialogInterface.OnClickListener()


{
@Override
public void onClick(DialogInterface dialogInterface, int which) {
//Exit our window activity
MainActivity.this.finish();
}
} );

Next, set negative buttons which is No. Here, we going to cancel our dialog only rather than our application
when the user clicked on No buttons in the alert dialog.

alertDialog.setNegativeButton( getResources().getString( R.string.alert_no ), new DialogInterface.OnClickListener()


{
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.cancel();
}
} );

Now, we constructing our alert dialog by setting titles, message inside the dialog and all buttons that appears in
our alert dialog. So, the next step is creating the actual dialog because remember our alert dialog is builder type
that builder will build the dialog.

AlertDialog dialog=alertDialog.create();

Now, we have actually created the dialog which we’ll be using show on the screen by using show() methods of
created dialog.

AlertDialog dialog=alertDialog.create();
dialog.show();

The full main activity java class as follows:

package com.course.alertdialogs;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private AlertDialog.Builder alertDialog;
private Button showAlert;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
showAlert=(Button)findViewById( R.id.showalertBtnID );
showAlert.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View view) {
//show the actual dialog(alert dialog
alertDialog=new AlertDialog.Builder(MainActivity.this);
//setting up-set title
// alartDialog.setTitle( R.string.alert_title );
alertDialog.setTitle( getResources().getString( R.string.alert_title ) );
alertDialog.setIcon( android.R.drawable.ic_btn_speak_now);
//setting the message
alertDialog.setMessage( getResources().getString( R.string.alert_message ) );
//set cancelable
alertDialog.setCancelable( false );
//set button
alertDialog.setPositiveButton( getResources().getString( R.string.alert_yes ), new
DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int which) {
//Exit our window activity
MainActivity.this.finish();
}
} );
//set negative button
alertDialog.setNegativeButton( getResources().getString( R.string.alert_no ), new
DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.cancel();
}
} );
//creating the actual dialog
AlertDialog dialog=alertDialog.create();
dialog.show();
}
} );
}
}

6.8 . Tip Calculator Android


Apps

In this application we want


to do an android application that calculate tips by some
percentage. This apps is going to be useful as it will allow us to calculate that tip amount that we are supposed to
give to our serve at a restaurant. The idea will be that we will have an edit text where they can enter the amount
that they are being charged for the meal and then they will have a slider or seek bar that will allow the user to
slid left to right to get the percentage that they feel or should leave or add to their bill.
To doing this types apps the first thing is start constructing the layouts for our android apps. And also we going
to add all components that we needs to achieved our works. So first add plain text to our layouts and change
some properties/attributes for it like change input type to number and decimal number when we taped on text
field only the keyboard going to show us a number only rather texts that is why we going to change input type.
And the next, we going to add a text view and change size and set text for some information about seek bar.

And also after adding Text view we going to add seek bar for set the tip percentages and buttons in order to
calculate a given tip after takes the amount and tip percentage and also add text view to show us the result that
calculated tip amount with a given percentage. Then let us look xml layouts and seen in our device looks as
follows:

<?xml version="1.0" encoding="utf-8"?>


<androidx.constraintlayout.widget.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=".MainActivity">

<EditText
android:id="@+id/tipAmountId"
android:layout_width="277dp"
android:layout_height="39dp"
android:ems="10"
android:hint="@string/tipamount_hint"
android:inputType="number|numberDecimal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.37"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.168" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/tip_percentage"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.18"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tipAmountId"
app:layout_constraintVertical_bias="0.038" />
<SeekBar
android:id="@+id/percentSeekBarId"
android:layout_width="277dp"
android:layout_height="wrap_content"
android:max="35"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.373"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:layout_constraintVertical_bias="0.051" />
<Button
android:id="@+id/calculatBtnId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#009688"
android:text="@string/cal_button"
android:textColor="#FFFFFF"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/seekBarTextViewId"
app:layout_constraintVertical_bias="0.383" />
<TextView
android:id="@+id/resultTipId"
android:layout_width="113dp"
android:layout_height="36dp"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.442"
app:layout_constraintStart_toStartOf="parent"

app:layout_constraintTop_toBottomOf="@+id/calculatBtnId"
app:layout_constraintVertical_bias="0.132" />
<TextView
android:id="@+id/seekBarTextViewId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="60dp"
android:textColor="#3F51B5"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.04"

app:layout_constraintStart_toEndOf="@+id/percentSeekBarId"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:layout_constraintVertical_bias="0.042" />

</androidx.constraintlayout.widget.ConstraintLayout>

Now, we have constructed user interface pretty much done so that we have that setup we are going to be write a
java code in main activity. And we want to implement onclick listener on MainActivity class as follows:

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

@Override
public void onClick(View view) {

//our listener event


}}

And also, we have create all instance variable such as Edit text, seek bar, button and text view inside the class as
follows:

private EditText enterAmount;


private SeekBar seekBar;
private Button calculateTip;
private TextureView resulteTip,seekBartextView;
Then, instantiate all instance variable inside oncreate() methods as follows:

protected void onCreate(Bundle savedInstanceState) {


super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
enterAmount=(EditText)findViewById( R.id.tipAmountId );
seekBar=(SeekBar)findViewById( R.id.percentageseekBarId );
calculateTip=(Button)findViewById( R.id.calculatBtnId );
resulteTip=(TextView)findViewById( R.id.resultTipId );

seekBartextView=(TextView)findViewById( R.id.textViewseekbarId );
}

Now, let us setup our button to action listener events which registering our calculate button that it has an event
listener attached in this context.

calculateTip.setOnClickListener( this );

Also, we have setup seek bar listener for get the percentage values when we slide left to right the slider or seek
bar and display on Text view is called seekBarText view instance.

seekBar.setOnSeekBarChangeListener( new SeekBar.OnSeekBarChangeListener() {


@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {

}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {

}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {

}
} );

Here, we have different methods when we implements seek bar on change listener. Hence, the first method is
called onProgressChange() method with have three arguments i.e Seek Bar object, integer progress and
fromUser Boolean values. Since, it shows exactly how things are happening right so we can go and fetch the
progress number from the slider. And the next method is called onStartTrackingTouch() that have seek bar
object where can fetch when the tracking touch begins and the last method called onStopTrackingTouch() where
we get when the user has to left/release the finger off our application screen it is the best place to get the final
value that the users have selected. Then implement inside the method, first lets us show percentage when the
users slide on seek bar inside onProgressChange() method as follows:

public void onProgressChanged(SeekBar seekBar, int i, boolean b) {


seekBartextView.setText( String.valueOf( seekBar.getProgress() )+"%" );
}

Now, we’re able to see percentage and can get seek bar progress values. Since, let’s store the seek bar values to a
variable in order to use the values later. So, first declare the variable as instance variable called
seekbarPercentage with integer type to store the percentage that the user are selecting from sliding on seek bar.
Also, assign a value to declared instance variable inside onStopTrackingTouch() methods because this is the final
place that when the users have stopped tracking or the system has stopped tracking the touch which means that
we’ll get the correct percentage. The implementation of the method as follows:

public void onStopTrackingTouch(SeekBar seekBar) {


seekbarPercentage=seekBar.getProgress();
}

And also, create another instance variable which is going to be hold the amount that the users have enterned on
in our edit text and let’s called enteredBill with float type. Also, create a method is called calculate() to perform
a given expression that calculates the tip amount with a given percentage.

public void calculate(){


float result=0.0f;
if (!enterAmount.getText().toString().equals( "" )){
enterBill=Float.parseFloat( enterAmount.getText().toString() );
result=(enterBill*seekbarPercentage)/100;
resulteTip.setText( "your tip will be:"+String.valueOf( result) );
}else{
Toast.makeText( MainActivity.this,"Enter bill amount",Toast.LENGTH_LONG ).show();
}

}
Now, everything are working well but let’s add one thing that will add the tip amount to the bill amount in order
to calculate how much their total amount bill that payed to someone that gives services. So what we can do, sum
up the entered values from edit text and the calculated tip bills together and shows in totalBill text view.

totalBilTxt.setText( "Total bill:"+String.valueOf( enterBill+result )+" birr" );

Then invoke the methods inside on click listener because this method perform when the users clicked or taped on
calculate button.

public void onClick(View view) {


calculate();
}

Wow congratulation now we have simple and working android apps and the full java class and last layout seems
like as follows:

package com.course.tipcalculator;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{


private EditText enterAmount;
private SeekBar seekBar;
private Button calculateTip;
private TextView resulteTip;
private TextView seekBartextView;
private TextView totalBilTxt;
private int seekbarPercentage;
private float enterBill;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
enterAmount=(EditText)findViewById( R.id.tipAmountId );
seekBar=(SeekBar)findViewById( R.id.percentSeekBarId );
calculateTip=(Button)findViewById( R.id.calculatBtnId );
resulteTip=(TextView)findViewById( R.id.resultTipId );
seekBartextView=(TextView)findViewById( R.id.seekBarTextViewId );
totalBilTxt=(TextView)findViewById( R.id.tottalBillTxtViewID );

calculateTip.setOnClickListener( this );

seekBar.setOnSeekBarChangeListener( new SeekBar.OnSeekBarChangeListener() {


@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
seekBartextView.setText( String.valueOf( seekBar.getProgress() )+"%" );
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
seekbarPercentage=seekBar.getProgress();
}
} );
}
@Override
public void onClick(View view) {
calculate();
}
public void calculate(){
float result=0.0f;
if (!enterAmount.getText().toString().equals( "" )){
enterBill=Float.parseFloat( enterAmount.getText().toString() );
result=enterBill*seekbarPercentage/100;
resulteTip.setText( "your tip will be:"+String.valueOf( result)+" birr" );
totalBilTxt.setText( "Total bill:"+String.valueOf( enterBill+result )+" birr" );
}else{
Toast.makeText( MainActivity.this,"Please enter your bill amount",Toast.LENGTH_LONG ).show();
}
}
}

. Chapter
Seven
7. Android Activities
1.1. What is Activity

In case of Android Views, Layouts and View Groups are used to design the user interface, which is the physical
appearance of our App that the user interact with. But what is the mind or soul or conscious of our App? Yes, it is
the Activity. Activity is nothing but a java class in Android which has some pre-defined functions which are
triggered at different App states, which we can override to perform anything we want. Activity class provides us
with empty functions allowing us to be the controller of everything.

Activity In Android:

l Android system initiates its program with in an activities starting with a call onCreate() call-back method.
l There is a sequence of call-back methods that start up an activity.
l There can be more then 1 activity in application.
l Any one of them will be defined as main activity.

An activity is a window representation or a single screen which means when we create a project we have main
activity java class and we have xml layout that user interface the user can interact with. Let use see our main
activity class.

public class MainActivity extends AppCompatActivity{

Here, our MainActivity is a derived class that extends from AppCompatActivity which is a base activity that our
application is compatible with different device activities. Activity can be started by sending an intent to android
system which in turn uses manifest files to start right activity from right app.

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );

Here, after extends an Activity we have onCreate() override methods which is very important method and we
are override onCreate() methods that comes Activity base class for instantiate or set up our activity properly.
And also, we passing Bundle savedInstanceState which what happening here is that this Bundle class hold all of
the states, all of the methods, all of the instances or all of the properties of the particular activity screen which
call saveInstancestate then we have call to our super class on the base class that we derived from and pass our
instance state to the base class.
super.onCreate( savedInstanceState );

So, all of the instance states of our activity are being saved here from main activity which is parent activity. And
then, we have another method is called setContentView which is doing just going back to the layout resources like
our screen xml visual representation layout.

1.2. Activity life cycle


To navigate transitions between stages of the activity lifecycle, the Activity class provides a core set of six
callbacks: onCreate(), onStart(), onResume(), onPause(), onStop(), and onDestroy(). The system invokes each of
these callbacks as an activity enters a new state.

Let’s create each activity states in java program and implements Toast text message which just a small message
that create on our application that just popups and fade out on our android screen. So, use Toast class and invoke
makeText() methods, here pass context, message text and duration as first, second and third parameters
respectively then use show() method that needs to show on our screen. Let’s see the full different state as
follows:

import android.os.Bundle;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
Toast.makeText(this,"Oncreate() invoked" ,Toast.LENGTH_LONG).show();
}
@Override
protected void onStart() {
super.onStart();
Toast.makeText(this,"Onstart() invoked" ,Toast.LENGTH_LONG).show();
}
@Override
protected void onResume() {
super.onResume();
Toast.makeText(this,"onResum() invoked" ,Toast.LENGTH_LONG).show();
}
@Override
protected void onPause() {
super.onPause();
Toast.makeText(this,"Onpause() invoked" ,Toast.LENGTH_LONG).show();
}
@Override
protected void onRestart() {
super.onRestart();
Toast.makeText(this,"OnRestart() invoked" ,Toast.LENGTH_LONG).show();
}
@Override
protected void onStop() {
super.onStop();
Toast.makeText(this,"onstop() invoked" ,Toast.LENGTH_LONG).show();
}
@Override
protected void onDestroy() {
super.onDestroy();
Toast.makeText(this,"onDestroy() invoked" ,Toast.LENGTH_LONG).show();
}
}

Initially, on create method called that why we setup everything here then automatically goes to onStart() methods
everything is ready. And then onResume() method invoked and our app alive on our screen. As the user begins to
leave the activity, the system calls methods to dismantle the activity. In some cases, this dismantlement is only
partial; the activity still resides in memory (such as when the user switches to another app), and can still come
back to the foreground. If the user returns to that activity, the activity resumes from where the user left off. The
system’s likelihood of killing a given process along with the activities in it depends on the state of the activity at
the time.

1.3. Navigate to different activity


Let’s build a simple application that only have two activities and navigate from the first to other activity. Since,
essentially we will be able to navigate to other activities when we clicked or tapped the button on the first
activities. So, we going to create showActivity project that have first activity and second Active in android
project. And also, we going to add button and name as “show next activity” taped or clicked to navigate other
activity. Then, create the second activity and we going to say “second activity” now we have to activities.
The idea is clicked on the button showed the next activity and we should be taken to our second activity. Now we
are going to set up all things in the first activities so we are going to create a private button field and names
gotoNext. Finally setup the buttons action listener as follows:

public void onClick(View view) {


}
} );

And then, we going to implement the intent object which means intent in an android is an action what we need to
be and what is it that the application wants to do. So, our intent here the action that we need is to go from first
activity to second activity. That means we have to instantiate that the class and set everything up for us to
actually go to the next activity that we want go to. Let’s create and instantiate an Intent as follows:
Intent myIntent=new Intent(MainActivity.this,SecondActivity.class );

So, we are creating Intent object and passing two parameters to the constructor, the first parameter is the name of
the activity that we are currently located that is MainActivity and the second is what will be go to which activity
is called SecondActivity class. Finaly, we have to start the activity by passing our intent object is called myIntent
as follows:
Intent myIntent=new Intent(MainActivity.this,SecondActivity.class );
startActivity(myIntent);
or

We can used anonymous Intent object that navgates between activities and pass in startActivity method as
follows.
startActivity( new Intent( MainActivity.this, SecondActivity.class ) );

The full java code seems like:


package com.course.showactivity;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private Button gotoNext;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
gotoNext=(Button) findViewById( R.id.showActivityID );
gotoNext.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent myIntent=new Intent(MainActivity.this,SecondActivity.class );
startActivity( myIntent );
}
} );
}

Now, we can navigate from the first activity to another second activity.

1.4. Passing data between


activities
On this project we going to do
passing some data between different
activities which show how to attach
message from activities. Here, when
we get second activity we’ll be able
to retrieve the message from the first
activity and display it on the second
activity. Now, we have used an
Intent class which has an action is
goes from one activity to another
activity. But we can also attach a
string value or message to our first
activity before we are sending them off second activity.
So we going to implements on the first activity, naturally after create Intent objects add all string values using
putExtra() methods which this method is like HashMap that has key with values data structure. And also, we can
put many different types or same type key with value pairs as we want as follows:

Intent intent=new Intent(MainActivity.this,SecondActivity.class );


intent.putExtra( "Name","Aster Awoke" );
intent.putExtra("sex","Female" );
intent.putExtra( "age",50 );

So, we keep put all attached messages we want to be attached before that intent is sent which means it will
collect all of the message that we attached that we have to put into our intent and will be available in the second
intent at which point we can then parse or get all of that information.

Now, we going to implements on the second activity, we able to extract those messages that we have sent. The
idea here, display the message that we were receiving from our intent in text view automatically. So, we have
first ready our text view for receiving string that sending from our first activity. Then, use Bundle class that
collects all messages that send from first activity as follows:

Bundle extra=getIntent().getExtras();

Here,we are saying that we have the intent we need to go and get the extras that puts the message by putExtras()
methods in the first activity. And then check the whether our extra intent is empty or not and also assign all
recived intent values into a variable. And inorder to retrive the intantes we have to knows about the types of
values/message that sent from other activity which means when the message String type we can get using
getString() method or its integer using getInt() and so on as follows:

if (extras!=null){
String name=extras.getString( "name" );
String sex=extras.getString( "sex" );
int age=extras.getInt( "age" );

} .

Finally, after received all intent message now we can set to our text view in order to display or we can used for
other purpose as we want.

showIntent.setText( "Name:"+name+" \n Sex:"+sex+"\n Age:"+age );


And the full java code, firstly let’s see MainActivity.java or the first activity which attached messages to an
intent.

public class MainActivity extends AppCompatActivity {


private Button gotoNext;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
gotoNext=(Button) findViewById( R.id.showActivityID );
gotoNext.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent=new Intent(MainActivity.this,SecondActivity.class );
intent.putExtra( "name","Aster Awoke" );
intent.putExtra("sex","Female" );
intent.putExtra( "age",50 );

startActivity( intent );
//startActivity( new Intent( MainActivity.this,SecondActivity.class ) );
}
} );
}
}

And, SecondActivity.java or the second activity which is received messages from other intents

public class SecondActivity extends AppCompatActivity {


private TextView showIntent;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_second);

Bundle extras=getIntent().getExtras();
showIntent=(TextView)findViewById( R.id.showIntentID );
if (extras!=null){
String name=extras.getString( "name" );
String sex=extras.getString( "sex" );
int age=extras.getInt( "age" );
showIntent.setText( "Name:"+name+" \n Sex:"+sex+"\n Age:"+String.valueOf( age) );
}else{
showIntent.setText( "we can't sent any values " );
}
}
}

Passing attributes back to first


Activity

Now, we are going to pass a message back to


first activity from the second activity after
modified or other attributes that gets
from the first activity. The first thing is we have another method where we can
override in our first activity or in any activity is called onActivityResult() which does catch everything that is
being sent from second activity.

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult( requestCode, resultCode, data );
}

Here, the first parameter is called requestcode integer type is any code or integer number that we can create and
will specify which activity or which message that we are trying to catch and display. And the second parameter
the resultCode is going to be code or it’s allow us to know what kind of result are we where expecting. The third
parameter is called Intent data is the main one that the intent data of request code. Let’s declare and assign for
request code as follows:

private final int REQUEST_CODE=2;

Hence, got to second ctivity and we going to add button and name as “back to ” taped or clicked to send
massages to back first activity. The idea is clicked on the button sent attributes to the next activity called first
activity. Now we are going to set up all things in the second activities so we are going to create a private button
field and names gobackTo. Finally setup the buttons action listener as follows:

goBackTo.setOnClickListener( new View.OnClickListener() {qs


@Override
public void onClick(View view) {

}
} );

The idea here is when we tapped or clicked on the button in second activity we want to sent messages back to
first activity from the current called second activity. And then, we going to implement the intent object. So, our
intent here the action that we need is to go from second activity back to first activity.
public void onClick(View view) {
Intent returnIntent=getIntent();
returnIntent.putExtra( "returnData","From second activity" );
setResult( RESULT_OK, returnIntent);
finish();
}

Here, there is setResult() methods that we need is the one that has the result code that we can used to the intent
data we will have to pass. So, in the method, the first parameter RESULT_OK is just an internal code that will tell
the system that this result is all good and we can send this and it will be received on the next or previous activity.
And the next parameter is the intent data.
Now, we going back to first activity to be able to retrieve the data that passed from the second activity.
Remember, we are not retrive on onCreate() method rather we retrieve on onActivityresult() methods that why
we have expecting result from our previous or from second activity. We need to make a few change inside of our
onClick() when our first activity here when we start activity because here the magic happen. Here, the
startActivity it starts when we click the button and then we go to the second activity and from there we can go
and retrieve all messages. But we passed the intent just saying start activity and make sure the activity we need to
tell the system to get ready for what comes next which we want to start activity for result. Because, is we just say
startActivity and we will go to that activity go back nothing will be registered in the android system that this
activity is starting for results meaning that we’re starting to hopefully receive result back from the second
activity. Hence, change something that used before as replaced the following:
startActivity( new Intent( MainActivity.this,SecondActivity.class ) );

by
startActivityForResult( intent,REQUEST_CODE );

So that, we know which activity message that we are getting from the is of 2 which gives in request_code. Now
we are saying this activity first activity is registered to for result so it will always expect to get a result.
Then implements onActivityResult() as follows:
if (requestCode==REQUEST_CODE){
if (resultCode==RESULT_OK){

//our retrieved message


}

The first condition is check about the request code which means if the request code is being passed coming back
equal to our request code that we have specified. And the second condition is check if result code is OK which
means exactly what we are passing in the second activity.

Now everything are ok then retrieve our message. Here, the data that we see being passed from our own activity
result which will have all of intent information that we are getting from the second activity get that getStringExtra

and passed returnData which is the key that declared in second activity. Finaly, let’s display on Toast.

protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {


super.onActivityResult( requestCode, resultCode, data );
if (requestCode==REQUEST_CODE){
if (resultCode==RESULT_OK){
String result=data.getStringExtra("returnData");
Toast.makeText( this,"our result"+result,Toast.LENGTH_LONG ).show();
}
}
}
}

Now, we will be showing the results from second activity message in first activity(in main activity) and able to
exchanging information from first activity and second activity.
The full code, first activity
public class MainActivity extends AppCompatActivity {
private Button gotoNext;
private final int REQUEST_CODE=2;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
gotoNext=(Button) findViewById( R.id.showActivityID );
gotoNext.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent=new Intent(MainActivity.this,SecondActivity.class );
intent.putExtra( "name","Aster Awoke" );
intent.putExtra("sex","Female" );
intent.putExtra( "age",50 );
// startActivity( new Intent( MainActivity.this,SecondActivity.class ) );
startActivityForResult( intent,REQUEST_CODE );
}
} ); }
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult( requestCode, resultCode, data );
if (requestCode==REQUEST_CODE) {
if (resultCode == RESULT_OK) {
String result = data.getStringExtra( "returnData" );
Toast.makeText( this, "our result" + result, Toast.LENGTH_LONG ).show();
}
}
}

And SecondActivity.java
public class SecondActivity extends AppCompatActivity {
private TextView showIntent;
private Button goBackTo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_second);
Bundle extras=getIntent().getExtras();
showIntent=(TextView)findViewById( R.id.showIntentID );
goBackTo=(Button)findViewById( R.id.backtobtnID );
if (extras!=null){
String name=extras.getString( "name" );
String sex=extras.getString( "sex" );
int age=extras.getInt( "age" );
showIntent.setText( "Name:"+name+" \n Sex:"+sex+"\n Age:"+String.valueOf( age) );
}else{
showIntent.setText( "we can't sent any values " );
}
goBackTo.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent returnIntent=getIntent();
returnIntent.putExtra( "returnData","From second activity" );
setResult( RESULT_OK, returnIntent);
finish();
}
} );
}

}
1.1. Pet Bio apps
In this application, we
will able to develop a
bio for our pats to be
pass and to be a dog
and a cat. So the idea is to have two pictures on the first screen with a dog and a cat. And if we click on the
pictures we’ll take to the second screen where it will show a picture of that cat or dog and also a little bit
description or Bible about that pictures(cats/dog). This apps is enhanced the idea of transition data from one
activity to others. So let’s design the layout that the user directly interact. Here,let’s change the background to
make beautiful design. And then, add images to our layout and we have already added to images cat and dog
images inside our drawable. Inorder to insert image in our apps we have used image viewer from plate in android
studio so we going to add two image view at top and buttom of our layout for adding cat and dog images to our
apps.
When we build our interface, then we go back to
our main and setup our views as follows:

private ImageView catView,dogView;

...
catView=(ImageView)findViewById( R.id.catImageViewId );
dogView=(ImageView)findViewById( R.id.dogImageViewId );

Then attach action listener to our images that is cat image and dog image. Because, buttons are a types of views
that means it inherits from view and view is just a screen where we can tap or click so we can add action listener
to any views. Now, we going to add toast inorder to check which images are clicked and display on small
popups.

catView.setOnClickListener( new View.OnClickListener() {

@Override
public void onClick(View view) {
Toast.makeText( MainActivity.this,"cat image touched",Toast.LENGTH_LONG ).show();
} } );
dogView.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText( MainActivity.this,"Dog image touched",Toast.LENGTH_LONG ).show();
}
} );
But the above code is redundant because when we have more than one views to attach action listener it would be
really nice to just have only on onClick() method that will attach to all of others views that well setting action
listener. Hence, how to do is first implements View.OnClickListener interface to our class and when we need
implements certain methods like onClick() methods that comes with OnClickListener.

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

@Override
public void onClick(View view) {

Now, we have to register all cat view and dog view and pass our context like Mainactivity.this as follows:

catView.setOnClickListener( this );
dogView.setOnClickListener( this );

Here, the view are activated or registered to our class or the click listener event and we have pass the activity or
the context means now we can control whatever happens to the views inside of onClick() methods.

Now inside, onclick() methods, we need to find which button is tapped or clicked by the users which means
differentiate which button is clicked and we can used switch statement. In this statement use View.getId() as
conditions which means any view that get id and in case we have use R.id.viewId for access each views as
follows:

@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.catImageViewId:
Toast.makeText( MainActivity.this,"Cat image is touched",Toast.LENGTH_LONG ).show();
break;
case R.id.dogImageViewId:
Toast.makeText( MainActivity.this,"Dog image is touched",Toast.LENGTH_LONG ).show();
break;
}
}
Then, implement the actual logic when we clicked the images got to the second activity that displayed the images
and some Bio about a specific image what we tapped or clicked. Since, we have to animals cat and dogs we
should create two activities for each animals but we don’t need create two activities because that would be a wast
of our resources. So, what do we need to do to think more dynamically just create one activity that will decide
whether we’ve clicked on cat or dog and then displayed the appropriate messages or information about we
tapped.

So now create another activity and going to be BioActivity as name. And in this new activity add image view at
top and in the bottom add some text that displays our Bio information about our animals. Then, initially let’s add
darker transparent as background for our images and change id petBioImageId. And also, we have add two text
view at the bottom of our activity in order to display name and Bio information respectively about animals.

Now, go to BioActivity.java class to setup


image view and text view which means creating
an instance of image view and text view and instantiate them.

private ImageView petImage;


private TextView petName;
private TextView petBio;

petImage=(ImageView)findViewById( R.id.petBioImageId );
petName=(TextView)findViewById( R.id.nameId );
petBio=(TextView)findViewById( R.id.bioInfoId );
Now, we have finished on the second activity called BioActivity so we came back to Main activity we need to
create an intent so that it takes us to our second activity which is the BioActivity. So, first we are going to do
Intent in each case in switch statement. Then, add something like image, name and bio informations what we
tapped in putExtra() method.

switch (view.getId()){
case R.id.catImageViewId:
Intent catIntent=new Intent( MainActivity.this,BioActivity.class );
catIntent.putExtra( "name","Kenubish" );
catIntent.putExtra( "bio","Kenubish cat is very interesting cat..." );
startActivity( catIntent );
break;
case R.id.dogImageViewId:
Intent dogIntent=new Intent( MainActivity.this,BioActivity.class );
dogIntent.putExtra( "name","Boby" );
dogIntent.putExtra( "bio","Boby dog is very interesting dog ..." );
startActivity( dogIntent );
break;
}

However, we still need to be able to fetch all information like name and bio information in our BioActivity. So,
we going to create a Bundle instance which holds the information that comes from main activity and for retrive
we have used getIntent() followd getExtras() methods. Then, use conditional statements for checking if our intent
have some information or haven't. Our bundle objects called extras and instantiate it before use the object.

private Bundle extras;

..

extras=getIntent().getExtras();
if (extras!=null){
String type=extras.getString( "type" );
String name=extras.getString( "name" );
String bio=extras.getString( "bio" );
setup( type,name,bio );
}
Hence, let’s create a method called setup() that have two arguments name and bio string type and invoke inside if
condition in the above block code. The implementation of the method, make sure that our image view has the
correct image and also our text view has the correct name and bio for a specific animals.

public void setup(String type, String name,String bio){


//our setup here

Now, use some condition for checking which animal or which item or the given information is for cat or dog that
sent from main activity.

public void setup(String type,String name,String bio){


if (type.equals( "cat" )){

}else if (type.equals( "dog" )){

}
}

Then, inside each condition in the above block code sets the appropriate image in the image view which means
when the user click on cat then the system able to set cat image to image view else set dog image to it as we
tapped. So, for doing this we going to use the following method.

petImage.setImageDrawable( );

Finally, sets Bio and names for each animals as follows:

public void setup(String type,String name,String bio){


if (type.equals( "cat" )){
petImage.setImageDrawable(getResources().getDrawable( R.drawable.icon_lg_cat));
petName.setText( name );
petBio.setText( bio );

}else if (type.equals( "dog" )){


petImage.setImageDrawable( getResources().getDrawable( R.drawable.icon_lg_dog) );
petName.setText( name );
petBio.setText( bio );
}
}

The full java code for MainActivity and BioActivity as follows: the first one is MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener {


private ImageView catView,dogView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
catView=(ImageView)findViewById( R.id.catImageViewId );
dogView=(ImageView)findViewById( R.id.dogImageViewId );
catView.setOnClickListener( this );
dogView.setOnClickListener( this );
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.catImageViewId:
Intent catIntent=new Intent( MainActivity.this,BioActivity.class );
catIntent.putExtra( "type","cat" );
catIntent.putExtra( "name","Kenubish" );
catIntent.putExtra( "bio","Kenubish cat is very interesting cat..." );
startActivity( catIntent );
break;
case R.id.dogImageViewId:
Intent dogIntent=new Intent( MainActivity.this,BioActivity.class );
dogIntent.putExtra( "type","dog" );
dogIntent.putExtra( "name","Boby" );
dogIntent.putExtra( "bio","Boby dog is very interesting dog ..." );
startActivity( dogIntent );
break;
}
}
}

And BioActivity.java

public class BioActivity extends AppCompatActivity {


private ImageView petImage;
private TextView petName;
private TextView petBio;
private Bundle extras;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_bio );
petImage=(ImageView)findViewById( R.id.petBioImageId );
petName=(TextView)findViewById( R.id.nameId );
petBio=(TextView)findViewById( R.id.bioInfoId );
extras=getIntent().getExtras();
if (extras!=null){
String type=extras.getString( "type" );
String name=extras.getString( "name" );
String bio=extras.getString( "bio" );
setup( type,name,bio );
} }
public void setup(String type,String name,String bio){
if (type.equals( "cat" )){
petImage.setImageDrawable(getResources().getDrawable( R.drawable.icon_lg_cat));
petName.setText( name );
petBio.setText( bio );
}else if (type.equals( "dog" )){
petImage.setImageDrawable( getResources().getDrawable( R.drawable.icon_lg_dog) );
petName.setText( name );
petBio.setText( bio );
}
}}
.
.
.
.
.

.Chapter Eight
2. Recycler View
2.1. Introduction
In this chapter we will discus about new concept is called recycler view concepts which will be able to display a
lot of information on a single screen. And the information that display on screen has to be organized in a row or
as in a list form get in android.

The RecyclerView widget is a more advanced and flexible version of ListView. In the RecyclerView model,
several different components work together to display our data. The overall container for our user interface is a
RecyclerView object that we add to our layout. The RecyclerView fills itself with views provided by a layout
manager that we going to provide. We can use one of standard layout managers (such as LinearLayoutManager
or GridLayoutManager), or implement our own.

The views in the list are represented by view holder objects. These objects are instances of a class we define by
extending RecyclerView.ViewHolder. Each view holder is in charge of displaying a single item with a view. For
example, if our list shows music collection, each view holder might represent a single album. The RecyclerView
creates only as many view holders as are needed to display the on-screen portion of the dynamic content, plus a
few extra. As the user scrolls through the list, the RecyclerView takes the off-screen views and rebinds them to
the data which is scrolling onto the screen.

The view holder objects are managed by an


adapter, which we’ll create by extending RecyclerView.Adapter. The adapter creates view holders as needed.
The adapter also binds the view holders to their data. It does this by assigning the view holder to a position, and
calling the adapter's onBindViewHolder() method. That method uses the view holder's position to determine
what the contents should be, based on its list position.

This RecyclerView model does a lot of optimization work so we don't have to:

l When the list is first populated, it creates and binds some view holders on either side of the list. For
example, if the view is displaying list positions 0 through 9, the RecyclerView creates and binds those
view holders, and might also create and bind the view holder for position 10. That way, if the user scrolls
the list, the next element is ready to display.
l As the user scrolls the list, the RecyclerView creates new view holders as necessary. It also saves the
view holders which have scrolled off-screen, so they can be reused. If the user switches the direction they
were scrolling, the view holders which were scrolled off the screen can be brought right back. On the
other hand, if the user keeps scrolling in the same direction, the view holders which have been off-screen
the longest can be re-bound to new data. The view holder does not need to be created or have its view
inflated; instead, the app just updates the view's contents to match the new item it was bound to.
l When the displayed items change, you can notify the adapter by calling an appropriate
RecyclerView.Adapter.notify…() method. The adapter's built-in code then rebinds just the affected items.

Add the support library


To access the RecyclerView widget, we need to add the v7 Support Libraries to our project as follows:

1. Open the build.gradle file for your app module.


2. Add the support library to the dependencies section.

dependencies {
implementation 'com.android.support:recyclerview-v7:28.0.0'
}

Note: With Android Studio 3.6 and higher, the view binding feature can replace findViewById() calls and
provides compile-time type safety for code that interacts with views. Consider using view binding instead of
findViewById().

2.2. Create our Recycler view


Now, we going to create small apps that shows recycler view concepts. So,the first thing that we want to do is
add recycler view to our xml layout.

Now, all in recycler view to work we need to feed it data but before given data we need to make sure that we
have an adapter because the recycler view by itself is useless. The recycler view is just a tamplate that we can
use to connect it to an adapter. So, adapter is the interface between the data which would be the information we
want show on screen. Hence, we have three pieces that are very important for all of our works to create recycler
view apps which are recycler view, data and adapter.
Now, the next thing is we need to do is to customize each list view or each row that we want to show. So to do
that create a separate xml file and we’re going to call list_row that will be then inflated to create an actual view.

Here, let’s add a card view to our Linear layout because it just a card looking item that will hold data inside of
our list view or in our case recycler view. So, in order to add card view the first thing is search card view in the
plate and add to our list_row xml layout. And also we going to add Relative layout inside card view. So, we can
see the component tree as follows :

So, inside our linear layout here we’re going to add some text views.

<Te xtView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
/>

The last one in the above block called android:layout_weight="1" well tell the android system how to
distribute the allocated view for the text. The full xml code for list_row layout looks like as follows:

<?xml version="1.0" encoding="utf-8"?>


<RelativeLayout
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">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.043" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Title"
android:textStyle="bold"
android:textSize="20sp"
android:layout_weight="1"
android:paddingTop="12dp"
android:paddingLeft="12dp"
android:paddingBottom="2dp"
/>
<TextView
android:id="@+id/description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Description"
android:layout_weight="1"
android:paddingTop="6dp"
android:paddingLeft="6dp"
android:paddingBottom="5dp"
/>
</LinearLayout>
</androidx.cardview.widget.CardView>
</RelativeLayout>

Then, add an adapter because it is the bridge between the recycler view and the data that we are going to be
feeding into our recycler view. For implementing this we need to use a programming pattern called MVC(Model
View Controller). The idea is when we building an application in fact the whole android paradigms is built up on
MVC concepts. Hence, we have our views the user can see or interact and we have our model what the data part
of things and then we have the controller give the classes that actually control what is supposed to be done. So,
for put all java code in the same java file is bad habits when we develop advanced applications.

So, what we going to do is create another package's inside our apps and name this Adapter where all of our
Adapter are going to go here. And also, we going to create another packages called Util for Utility class and add
Model package for model class.

Now, we’re going to do create an adapter because will allow us to connect the view with list of rows which will
be displaying the data in our case Title and description. We can next step is adding a list adapter.

Add a list adapter inside our Adapter package

To feed all our data to the list, we must extend the RecyclerView.Adapter class. This object creates views
for items, and replaces the content of some of the views with new data items when the original item is no longer
visible.

Now, create an adapter class called MyAdapter and extends RecyclerView.Adapter<>. Here the angle bracket
what we are going to pass when we going to say MyAdapter that ViewHolder.

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {


}

Here, our class MyAdapter takes all the functionalities because it extends or inherit from Recycler view adapter.
So, there are classes and methods that waits us to work with from our recycler view and then we’re going to pass
myAdapter data view holder which is our myAdapter view holder constructor which create next. So, here we
have implements the method as follows:
package Adapter;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return null;
}
@Override
public void onBindViewHolder(@NonNull MyAdapter.ViewHolder holder, int position) {

}
@Override
public int getItemCount() {
return 0;
}

The layout manager calls the adapter's onCreateViewHolder() method. That method needs to construct a
RecyclerView.ViewHolder and set the view it uses to display its contents. The type of the ViewHolder
must match the type declared in the Adapter class signature. Typically, it would set the view by inflating an XML
layout file. Because the view holder is not yet assigned to any particular data, the method does not actually set
the view's contents.

The layout manager then binds the view holder to its data. It does this by calling the adapter's
onBindViewHolder() method, and passing the view holder's position in the RecyclerView. The
onBindViewHolder() method needs to fetch the appropriate data, and use it to fill in the view holder's
layout. For example, if the RecyclerView is displaying a list of names, the method might find the appropriate
name in the list, and fill in the view holder's widget.

So,we are going to create Context and ListItem instances then create a constructor which we’re going to pass
Context and list of items that we want to feed to our recycler view. And also, we need to do here is setup our
context and a list item.

private Context context;


private List<ListItem> listitems;
public MyAdapter(Context context, List listitem){
this.context=context;
this.listitems=listitem;
}

Then, going to implements inside our Model class that reperesents our list items. So,here create a class called
ListItem inside our model package/folder.
package Model;
public class ListItem {
}

Inside here, add instance variable and constructor because we need to get the list item is representing each item
that we are going to show in recycler view essentially the title and description.

package Model;
public class ListItem {
private String name;
private String description;
public ListItem( String name,String description){
this.name=name;
this.description=description;

public String getName() {


return name;
}
public String getDescription() {
return description;
}
public void setName(String name) {
this.name = name;
}

public void setDescription(String description) {


this.description = description;
}
}

Now, go back to our adapter class called MyAdapter and import our model class as import Model.ListItem; in

MyAdapter.java. And also create the inner class that will implements ViewHolder.

public class ViewHolder {


}

Here,what this ViewHolder class will holds all of the items that will have in our list_row so we’re going to able
fetch that the text view name and description and that’s where we are going to be able to do and sent all of those
views that they are able to be shown. Since, we have extends RecyclerView.ViewHolder class to inherit the
properties of it because it has to go and get all of the functionalities of the actual RecyclerView base class.
public class ViewHolder extends RecyclerView.ViewHolder{
public ViewHolder(@NonNull View itemView) {
super( itemView );
}
}

The layout manager calls the adapter's onCreateViewHolder() method. That method needs to construct a
RecyclerView.ViewHolder and set the view it uses to display its contents. The type of the ViewHolder
must match the type declared in the Adapter class signature. Typically, it would set the view by inflating an XML
layout file. Because the view holder is not yet assigned to any particular data, the method does not actually set
the view's contents. So inside this method we going to implements as follows:

public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {


View view= LayoutInflater.from( parent.getContext() )
.inflate( R.layout.list_row ,parent,false);
return new ViewHolder( view );
}

Here, we have the view called list_row which holds the entire view and return new object of viewholder type
which contain all of that we need. Since, we have a view is being passed on through our ViewHolder.
Then, we need to bind the ViewHolder with our Adapter so that then we can show inside of our Recycler View
but before we’re going to do inside let’s fix our ViewHolder which create a few fields like TextField.
public class ViewHolder extends RecyclerView.ViewHolder{
public TextView name;
public TextView description;
public ViewHolder(@NonNull View itemView) {
super( itemView );
name=(TextView)itemView.findViewById( R.id.title );
description=(TextView)itemView.findViewById( R.id.description );
}
}

Here, in the statement “name=(TextView)itemView.findViewById( R.id.title )”, we have used itemView for
instantiate each text view fields because we have to attach the view that we are working.
The last method in Adapter class called getItemCount() we need to return the size of our list view or list item. So
what we’re going to do here get the size of list item because in order to get the count of our list items.
public int getItemCount() {
return listitems.size();
}
The layout manager then binds the view holder to its data. It does this by calling the adapter's
onBindViewHolder() method, and passing the view holder's position in the RecyclerView. The
onBindViewHolder() method needs to fetch the appropriate data, and use it to fill in the view holder's
layout. For example, if the RecyclerView is displaying a list of names and description the method might find
the appropriate name and description in the list, and fill in the view holder's widget.

public void onBindViewHolder(@NonNull MyAdapter.ViewHolder holder, int position) {


ListItem item=listitems.get( position );
holder.name.setText(item.getName());
holder.description.setText( item.getDescription());

If the list needs an update, call a notification method on the RecyclerView.Adapter object, such as
notifyItemChanged(). The layout manager then rebinds any affected view holders, allowing their data to
be updated.

Finally, go to our main activity and create instantiate our adapter and start putting together our recycler view.

public class MainActivity extends AppCompatActivity {


private RecyclerView recyclerView;
private RecyclerView.Adapter adapter;
private List<ListItem> listItems;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
recyclerView=(RecyclerView)findViewById( R.id.recyclerViewID );
recyclerView.setHasFixedSize( true );
recyclerView.setLayoutManager( new LinearLayoutManager( this ));
}
}

Here, we said recyclerView.setHasFixedSize( true ), because we want to every item has a fixed size. And also, set
layout manager to our recycler view in our case pass Linear layout objects in Layout manager.

recyclerView.setLayoutManager( new LinearLayoutManager( this ));


Then, and then we going to create a list item which is array list type that to holds all lists and we have to feed
our list here objects because this is a list object we’re going to used to add into our adapter as follows.

listItems=new ArrayList<>( );
for (int i=0;i<9;i++){
ListItem item=new ListItem(
"Item"+(i+1),
"Description" );

listItems.add( item );

adapter=new MyAdapter( this,listItems );

Here, the last statement in the above code is set an adapter to our recycler view which has all of the code, all of
the data and all of visuals and everything combind. And let’s see what seems in a device.But it have space
between the list items in the left images it probably, on list_row so change a few things like
layout_height="wrap_content" instead of layout_height="match_parent". The right picture is after change
layout height in relative layout inside list_row xml and it is the correct.

However, we don’t see the actual card


margin so we need to put layout margin in cardView
inside list_row and we’re going to give
compact shadow android:
layout_margin= "@dimen/

cardview_compat_inset_shadow". No

w we can actually see our list items as a card view


opposed to what we have been seeing.

.
The only left is implement in Util package, the idea here is that we’re able to separate everything in MVC
programming pattern. It used for when we want to add another text view in the layout how to add easily without
affected others. Let’s add another TextView on list_row layout and add this text view to recycler view. Hence,
firstly go to the model and add new String instance and generate getter and setter for this instance called rating
instance.

private String rateing;

...

public void setRateing(String rateing) {


this.rateing = rateing;
}

public String getRateing() {


return rateing;
}

And also, go to ViewHolder in our Adapter and add our new field called rating

holder.rating.setText( item.getRateing() );

...
public TextView rating;
public ViewHolder(@NonNull View itemView) {
super( itemView );

...
rating=(TextView)itemView.findViewById( R.id.ratingID );
}

Then, we have to add the new fields in MainActivity and pass to ItemList
constructor.

for (int i=0;i<9;i++){


ListItem item=new ListItem(
"Item"+(i+1),
"Description", "Excelent!" );
listItems.add( item );
}

Add Action Listener to each row

Now, let’s attach an event listener for an list items but how to add an event listener to our recycler view? Yes,
first go to our adapter and implements OnClickListner on our inner ViewHolder class and then implement
onClick() abstract method inside our class. And also, we have to registered an item view because when the user
tapped on the view triggers to something which have three text views(title,description and rating).

public ViewHolder(View itemView) {


super( itemView );
itemView.setOnClickListener( this );

...
}

Now, we have able to got to our onClick() method to setting things up. Here, if we tapped or clicked on either of
those items of the rows we need to make sure the position on which item has been clicked. So, we have to get the
correct position of an item or get position of row clicked by getAdapterPosion() methods.

public void onClick(View view) {


int position=getAdapterPosition();
}

Now we can get the list item which row is tapped or clicked.

int position=getAdapterPosition();
ListItem item=listitems.get( position );

Here, the item object holds an item from listitems at a specific position so we know exactly which item we’re
clicked or tapped as well. Hence,we’re going to add Toast for show the effects when we tapped to a certain row
in recycler view.

public void onClick(View view) {


int position=getAdapterPosition();
ListItem item=listitems.get( position );
Toast.makeText( context, item.getName()+" is clicked", Toast.LENGTH_SHORT ).show();}
Tap row and show in another activity's

We’ll do when we clicked or tapped a specific row then able to show some information about what we clicked or
tapped in another activity. So, what we need to do is first create a new activity called DetailsActivity which will
receive the item from the previous activity. And also, in the layout we have put different fields depends on how
many fields have a single row that will tape.

Now, goto Adapter called MyAdapter class and setting up


the intent and other components. Firstly, let’s as create an
intent to navigate between two activities and pass context already we have, the second parameter is the activity
that is the destination activity in our case DetailActivity. Then, after create an intent we’re going to add some
information like name, description and rating in a given row that will displayed on detail activity then finally we
have use startActivity() methods which start our intent to activity.

public void onClick(View view) {


int position=getAdapterPosition();
ListItem item=listitems.get( position );

Intent intent=new Intent( context, DetailActivity.class );


intent.putExtra( "name",item.getName() );
intent.putExtra( "description",item.getDescription() );
intent.putExtra( "rating",item.getRating() );

context.startActivity( intent );
}

But here, for start an activity we have used context because we implements inside Adapters so here haven’t any
activity that is why used context before the method is called startActivity(intent) because context does it start
activity.
Then, we go back to detail activity for retrieve the information that passed from recycler view in order to
displayed on detailed activity. So first create all instances that will used in our works and then instantiate all of
created instances.

private TextView name,description,rating;

...

name=(TextView)findViewById( R.id.detailNameId );
description=(TextView)findViewById( R.id.detialDescriptionId );
rating=(TextView)findViewById( R.id.detailRatingId );

Then, we have retrieve information by Bundle objects which will holds all item information that put in our
intent.

extras=getIntent().getExtras();
if (extras!=null){
name.setText( extras.getString( "name" ) );
description.setText( extras.getString( "description" ) );
rating.setText( extras.getString( "rating" ) );
}

The full code for each class as follows:

ListItem.java

package Model;
public class ListItem {
private String name;
private String description;
private String rating;
public ListItem( String name,String description,String rating){
this.name=name;
this.description=description;
this.rating=rating;
}
public void setName(String name) {
this.name = name;
}
public void setDescription(String description) {
this.description = description;
}
public void setRating(String rating) {
this.rating = rating;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public String getRating() {
return rating;
}
}

MyAdapter.java

package Adapter;
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.course.recyclerviewapps.DetailActivity;
import com.course.recyclerviewapps.MainActivity;
import com.course.recyclerviewapps.R;
import org.w3c.dom.Text;
import java.util.List;
import Model.ListItem;

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {


private Context context;
private List<ListItem> listitems;

public MyAdapter(Context context, List listitem){


this.context=context;
this.listitems=listitem;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view= LayoutInflater.from( parent.getContext() )
.inflate( R.layout.list_row ,parent,false);
return new ViewHolder( view );
}

@Override
public void onBindViewHolder(@NonNull MyAdapter.ViewHolder holder, int position) {
ListItem item=listitems.get( position );
holder.name.setText(item.getName());
holder.description.setText( item.getDescription());
holder.rating.setText( item.getRating() );
}

@Override
public int getItemCount() {
return listitems.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
public TextView name;
public TextView description;
public TextView rating;
public ViewHolder(@NonNull View itemView) {
super( itemView );
itemView.setOnClickListener( this );

name=(TextView)itemView.findViewById( R.id.title );
description=(TextView)itemView.findViewById( R.id.description );
rating=(TextView)itemView.findViewById( R.id.ratingID );
}
@Override
public void onClick(View view) {
int position=getAdapterPosition();
ListItem item=listitems.get( position );

Intent intent=new Intent( context, DetailActivity.class );


intent.putExtra( "name",item.getName() );
intent.putExtra( "description",item.getDescription() );
intent.putExtra( "rating",item.getRating() );

context.startActivity( intent );
}
}
}

MainActivity.java

package com.course.recyclerviewapps;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.widget.Adapter;
import java.util.ArrayList;
import java.util.List;
import Model.ListItem;
import Adapter.MyAdapter;

public class MainActivity extends AppCompatActivity {


private RecyclerView recyclerView;
private RecyclerView.Adapter adapter;
private List<ListItem> listItems;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
recyclerView=(RecyclerView)findViewById( R.id.recyclerViewID );
recyclerView.setHasFixedSize( true );
recyclerView.setLayoutManager( new LinearLayoutManager( this ));
listItems=new ArrayList<>( );
for (int i=0;i<9;i++){
ListItem item=new ListItem(
"Item"+(i+1),
"Description", "Excelent!" );
listItems.add( item );
}
adapter=new MyAdapter( this,listItems );
recyclerView.setAdapter( adapter );
}
}

And lastly DetailActivity.java

package com.course.recyclerviewapps;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class DetailActivity extends AppCompatActivity {


private TextView name,description,rating;
private Bundle extras;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_detail );
name=(TextView)findViewById( R.id.detailNameId );
description=(TextView)findViewById( R.id.detialDescriptionId );
rating=(TextView)findViewById( R.id.detailRatingId );
extras=getIntent().getExtras();
if (extras!=null){
name.setText( extras.getString( "name" ) );
description.setText( extras.getString( "description" ) );
rating.setText( extras.getString( "rating" ) );
}
}
}
. Chapter Nine
.Android Media player
1.1. Media player Overview

The Android multimedia framework includes support for playing variety of common media types, so that we can
easily integrate audio, video and images into our applications. We can play audio or video from media files
stored in your application's resources (raw resources), from standalone files in the file system, or from a data
stream arriving over a network connection, all using MediaPlayer APIs.

Note: You can play back the audio data only to the standard output device. Currently, that is the mobile device
speaker or a Bluetooth headset. You cannot play sound files in the conversation audio during a call.

1.1.1 . The basics


The following classes are used to play sound and video in the Android framework:

MediaPlayer
This class is the primary API for playing sound and video.
AudioManager
This class manages audio sources and audio output on a device.

1.1.2 . Manifest declarations


Before starting development on your application using MediaPlayer, make sure your manifest has the appropriate
declarations to allow use of related features.

l Internet Permission - If you are using MediaPlayer to stream network-based content, your application
must request network access.

<uses-permission android:name="android.permission.INTERNET" />

Wake Lock Permission - If your player application needs to keep the screen from dimming or the processor
from sleeping, or uses the MediaPlayer.setScreenOnWhilePlaying() or MediaPlayer.setWakeMode() methods,
you must request this permission.

<uses-permission android:name="android.permission.WAKE_LOCK" />


1.1.3 . Using MediaPlayer
One of the most important components of the media framework is the MediaPlayer class. An object of this class
can fetch, decode, and play both audio and video with minimal setup. It supports several different media sources
such as:

l Local resources
l Internal URIs, such as one you might obtain from a Content Resolver
l External URLs (streaming)

Here is an example of how to play audio that's available as a local raw resource (saved in your application's
res/raw/ directory):

Java

MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.sound_file_1);


mediaPlayer.start(); // no need to call prepare(); create() does that for you

In this case, a "raw" resource is a file that the system does not try to parse in any particular way. However, the
content of this resource should not be raw audio. It should be a properly encoded and formatted media file in one
of the supported formats.

And here is how you might play from a URI available locally in the system (that you obtained through Playing
from a remote URL via HTTP streaming looks like this:

Java

String url = "http://........"; // your URL here


MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(url);
mediaPlayer.prepare(); // might take long! (for buffering, etc)
mediaPlayer.start();

Note: If you're passing a URL to stream an online media file, the file must be capable of progressive download.

Caution: You must either catch or pass IllegalArgumentException and IOException when using
setDataSource(), because the file you are referencing might not exist.
Apart from the start and pause method, there are other methods provided by this class for better dealing with
audio/video files. These methods are listed below:

Sr.N
Method & description
o
isPlaying()
1
This method just returns true/false indicating the song is playing or not

seekTo(position)
2
This method takes an integer, and move song to that particular position millisecond

getCurrentPosition()
3
This method returns the current position of song in milliseconds

getDuration()
4
This method returns the total time duration of song in milliseconds

reset()
5
This method resets the media player

release()
6
This method releases any resource attached with MediaPlayer object

setVolume(float leftVolume, float rightVolume)


7
This method sets the up down volume for this player

setDataSource(FileDescriptor fd)
8
This method sets the data source of audio/video file

selectTrack(int index)

9 This method takes an integer, and select the track from the list on that particular
index

getTrackInfo()
10
This method returns an array of track information
1.1. Create a simple apps that playing mp3
The android application will playing mp3 music. So, the first thing is create a new project and we going to call
MediaPlayerApps as a name. Then we are going to create a new folder called raw inside res/ in android studio
which we need for put our media files like mp3 file and add sample media mp3 files(e5.mp3) to our new created
directory/folder called raw.

The ides here, is create a simple apps that has a button and when we tapped a button the sound/music will play or
pause when it play before. So, now go to design mode the add a button and change some property.

<?xml version="1.0" encoding="utf-8"?>


<androidx.constraintlayout.widget.ConstraintLayout >

<Button
android:id="@+id/playButtonId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#86B0EF"
android:text="@string/play_button"
android:textColor="#BF360C"
android:textSize="24sp"
android:padding="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

Now, we go back main activity java class and create an instances of media player and button the instantiate them.
In order start playing media such as mp3,video files we need to have a class called MediaPlayer that’s why we
want to create an instance and instantiate the class MediaPlayer.
private MediaPlayer mediaPlayer;
private Button playButton;

...

mediaPlayer=new MediaPlayer();
mediaPlayer=MediaPlayer.create( getApplicationContext(),R.raw.e5 );
playButton=(Button)findViewById( R.id.playButtonId );

Here, we have create mediaPlayer instance/object of MediaPlayer class and instantiate inside onCreate()
methods. Then, create media play which takes the context or the path where our file is found/put. The below
block code, our instance/object holds our context and our media files(e5.mp3) files that found in raw folder and
accessed through R or resource.

mediaPlayer=MediaPlayer.create( getApplicationContext(),R.raw.e5 );

Then, when we implements the apps to trigger that tapped by button we have add action listener to our button.
And in our action events implement that will do to start playing our mp3 music/sound. So, first we going to
check if the mp3 player is already playing or not by using the method is called isPlating() it return Boolean.

playButton.setOnClickListener( new View.OnClickListener() {


@Override
public void onClick(View view) {
if (mediaPlayer.isPlaying()){
//stop and start again

} }} );

Hence, when the music is already play and we tapped/clicked the button the music will be pause unless the music
start playing. So, we need to create to methods called pauseMusic() and startMusic() for implements start and
pause state.

public void startMusic(){


if (mediaPlayer!=null){
mediaPlayer.start();
playButton.setText( "Pause" );
}
}
public void pauseMusic(){
if (mediaPlayer!=null){
mediaPlayer.pause();
playButton.setText( "Play" );
}

Since, when we tapped or clicked on the button and the music is already on playing state or it’s playing then to
invoke or call into pauseMusic() method which pause the music and change the button text to play for allowing
other start/play again unless to invoke to startMusic() method which means in the current the music is not
playing so we tapped the button start to play and change the button pause.

public void onClick(View view) {


if (mediaPlayer.isPlaying()){
pauseMusic();
}else {
startMusic();
}
}

Now we going to setup a setOnCompilationListener because our media player has the capability for us to set a
listener which that listen to what’s going on with our media player. It allows us to do certain things that we may
want to do as the application or as the music or mp3 plays.

mediaPlayer.setOnCompletionListener( new MediaPlayer.OnCompletionListener() {


@Override
public void onCompletion(MediaPlayer mediaPlayer) {

//
}
} );

Here, onCompletion() methods we passed mediaplayer objects of MediaPlayer class which we can access. Then,
inside the method we going to get the duration of our music or sound through getDuration() methods and assign
to duration integer type. Inside the method also, we going to show toast message just as a moment finished the
music or our mp3. But all time are measured in millisecond in android application or programming. So, in order
get a second unit we have to divide by 1000.
mediaPlayer.setOnCompletionListener( new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
int duration=mediaPlayer.getDuration();
String mDuration=String.valueOf( duration/1000 );
Toast.makeText( MainActivity.this,"Duration:"+mDuration,Toast.LENGTH_LONG ).show();
}
} );

However, our media player apps takes memory so after finished must be getting back a memory system. Since,
we going to override a method called destroy() method which used for clean up after finished or stopped our
player once the application is about to destroy we are going to back to the activity lifecycle.

@Override
protected void onDestroy() {
if (mediaPlayer!=null && mediaPlayer.isPlaying()){
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer=null;
}
super.onDestroy();
}

Here, if the object is still alive and if media player is still playing then we are going to say media player stop then
our media player release the resource back to our android for kill media player object on destroy. Because
imagine run the application the moment we get out of this application and we tap on the back button and the
application goes through all the life cycle and get on destroy it’s not destroy which means we’re not releasing all
of the memory back that we took out of our system. And also, each time we open we’re creating a new media
player which means we’ll get to a point where all have a lot of media player now in memory and that’s not good.

Add seek bar in Media Player

Now, we’re going to add seek bar to our media player apps allow to seek to a certain part of music. So, we’re
going to have seek bar if users start to slide left to right or right to left and the music while playing it will start
playing from where they have seek to gain.
Then, we’re go back to main activity class file then create an instance and instatiate the Seekbar class and also
we’re set the maximum property of our seek bar that get from the duration of our mp3 music. Then set

OnSeekBarChangeListener which allow us to have a way in which we can actually track the progress change, on
strat tracking touch and on stop tracking change .

private SeekBar seekBar;

….
seekBar=(SeekBar)findViewById( R.id.mSeekbarId );
seekBar.setOnSeekBarChangeListener( new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {

}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {

}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
} );

Now, we’re doing on onProgressChanged first check if our touch is coming from the user or not and then set our
media player in seek to the position when we have tapped or slide in our seek bar. when the user taps or start
sliding and let it go.
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
mediaPlayer.seekTo( progress );
}
}

Congratulations, we are finished simple media player apps now let’s see our layout and the Main Activity class
as follows:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/playButtonId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#86B0EF"
android:text="@string/play_button"
android:textColor="#BF360C"
android:textSize="24sp"
android:padding="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<SeekBar
android:id="@+id/mSeekbarId"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toTopOf="@+id/playButtonId"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.495"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.682" />

</androidx.constraintlayout.widget.ConstraintLayout>

And also, the Main Activity seem like as follows:


package com.course.mediaplayerapps;

import android.media.MediaPlayer;
import android.widget.Button;
import android.widget.SeekBar;

public class MainActivity extends AppCompatActivity {


private MediaPlayer mediaPlayer;
private Button playButton;
private SeekBar seekBar;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
mediaPlayer=new MediaPlayer();
mediaPlayer=MediaPlayer.create( getApplicationContext(),R.raw.e5 );
mediaPlayer.setOnCompletionListener( new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
int duration=mediaPlayer.getDuration();
String mDuration=String.valueOf( duration );
Toast.makeText( MainActivity.this,"duration:"+mDuration,Toast.LENGTH_LONG ).show();
}
} );

playButton=(Button)findViewById( R.id.playButtonId );
playButton.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mediaPlayer.isPlaying()){
pauseMusic();
}else {
startMusic();
}
}
} );

seekBar=(SeekBar)findViewById( R.id.mSeekbarId );
seekBar.setMax( mediaPlayer.getDuration() );
seekBar.setOnSeekBarChangeListener( new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
mediaPlayer.seekTo( progress );
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) { }

@Override
public void onStopTrackingTouch(SeekBar seekBar) { }
} );
}
public void startMusic(){
if (mediaPlayer!=null){
mediaPlayer.start();
playButton.setText( "Pause" );
}
}
public void pauseMusic(){
if (mediaPlayer!=null){
mediaPlayer.pause();
playButton.setText( "Play" );
}
}

@Override
protected void onDestroy() {
if (mediaPlayer!=null && mediaPlayer.isPlaying()){
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer=null;
}
super.onDestroy();
}
}

1.1. Creating music box apps


In this application we will develop a simple music box which have speaker images, seek bar that shows current
duration during the music is playing and next, pause/play and previous button to control the music. Hence, the
apps allow us to control the music during play which means we can pause and play and also we can start at
different duration via seek bar. And also, the apps show us the current duration of music and deduct from the
total duration.

So, we going to create new project and setting the layouts which means adding image view to our layout and also
add seek bar, text view and buttons. The first thing in the layout, we’re going to add image view on the top of our
view and change some property of image view as we want like change the actual width and name change
background, change the rectangle to oval shapes and so on. Let’s change the image view to oval shape, first
create drawable resource file inside drawable called oval and then have to specify what kind of shape(line, oval
or rectangle).

<?xml version="1.0" encoding="utf-8"?>


<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid
android:width="3dp"
android:dashWidth="4dp"
android:color="@color/colorAccent" />
</shape>

Here, that we’re creating a shape that will be inflated or used as a background inside of our image view. And the
solid tag in the above xml file means when we want the whole image to be solid. And go back to activity layout
add the following:

<ImageView
android:id="@+id/imageView"
---
app:srcCompat="@drawable/oval" />

Hover, we need use png images instead of oval shape


color so we’re going to change app:srcCompat to our image file.

app:srcCompat="@drawable/audiospeaker"
Now, we’re going to add a little line below our speaker images. Since, we create another xml file called divider
inside our drawable and set rectangle shape with a certain color. Our divider.xml as follows:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="@color/colorPrimary"/>
</shape>

Now, in our main activity add image view which we made a divider for different section to be smart music box,

<ImageView
android:id="@+id/imageView2"

...
app:layout_constraintTop_toBottomOf="@+id/imageView"
app:srcCompat="@drawable/divider" />

Then we going to add text view for show us the title and author of music or give to us some additional
information about the music that we want to play. So, we need two text view for title and author of the music.
Then, we’re going to add seek bar for allow sliding from left to right or right to left the music duration with two
text view that will be shows the actual music duration and the deducted duration in playing music.

<SeekBar
android:id="@+id/seekBarId"
style="@android:style/Widget.DeviceDefault.SeekBar"

...
app:layout_constraintTop_toBottomOf="@+id/authorId"
app:layout_constraintVertical_bias="0.183" />

<TextView
android:id="@+id/leftDurationId"
...
app:layout_constraintEnd_toStartOf="@+id/seekBarId"
app:layout_constraintTop_toBottomOf="@+id/authorId"
app:layout_constraintVertical_bias="0.191" />
<TextView
android:id="@+id/rightDurationId"
...
app:layout_constraintStart_toEndOf="@+id/seekBarId"
app:layout_constraintTop_toBottomOf="@+id/authorId"
app:layout_constraintVertical_bias="0.191" />

Then, now we’re going to add next, play/pause and previous button in the bottom of our layout. So, first add
Table raw view for holding the three buttons. And make sure wrap content both the width and height And then
we’re add all three buttons to our table rows.

Here, we have three button now we’re going


to do change the button background which we
can get the android library an icons. So, we want to use previous, play and next android icons in the buttons.

<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="15dp"
android:layout_marginTop="40dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.495"
app:layout_constraintStart_toStartOf="parent"
android:background="@color/media_background"
app:layout_constraintTop_toBottomOf="@+id/seekBarId">

<Button
android:id="@+id/previusBtnId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:drawable/ic_media_previous"/>

<Button
android:id="@+id/playBtnId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:drawable/ic_media_play"/>

<Button
android:id="@+id/nextBtnId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:drawable/ic_media_next"/>
</TableRow>

Now, we have finished our user interface


design so we are going to implements in the
main activity class. The first thing we want to
do is create all instance such as buttons, text
fields, seekbars and media player and
instantiate them which are our user interface fields.

private MediaPlayer mediaPlayer;


private ImageView artistImage;
private SeekBar seekBar;
private TextView leftTime,rightTime;
private Button pervMusic,playMusic,nextMusic;

Then, we want to create a method called setupUI() for setting all user interface specifically on this methods to
make easy and more understandable then invoke inside our onCreate() methods. And also, we are instantiate our
media player which ready for play music in this method.
public void setupUI(){

mediaPlayer=new MediaPlayer();
mediaPlayer=MediaPlayer.create( getApplicationContext(),R.raw.libe_sew_yiwedal );
artistImage=(ImageView)findViewById( R.id.imageView );
seekBar=(SeekBar)findViewById( R.id.seekBarId );
leftTime=(TextView)findViewById( R.id.leftDurationId );
rightTime=(TextView)findViewById( R.id.rightDurationId );
prevMusic=(Button)findViewById( R.id.previusBtnId );
playMusic=(Button)findViewById( R.id.playBtnId );
nextMusic=(Button)findViewById( R.id.nextBtnId );

Now, we are going to implements action listener in our class for doing some triggered that allows us to tapped or
clicked for perform another task.

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

@Override
public void onClick(View view) {

//do the something


}
}

Let’s registered our buttons for action listener and use switch statement to use different on clicked event. And
also we have passed all of the view which set up on click listener in switch statement. Then use case for
implement related to different action events on the views.

prevMusic.setOnClickListener( this );
playMusic.setOnClickListener( this);
nextMusic.setOnClickListener( this );

switch (view.getId()){
case R.id.previusBtnId:
break;
case R.id.playBtnId:
break;
case R.id.nextBtnId:
break;
}

Now, we are going to create two method called startMusic() and pauseMusic() methods which used for starting
the media player or music and pause the music respectively. Since,inside the method first check if our media
player is null or not if not null then perform an activity which means start or pause the music.

public void stratMusic(){


if (mediaPlayer!=null){
mediaPlayer.start();
playMusic.setBackgroundResource( android.R.drawable.ic_media_pause );
}
}
public void pauseMusic(){
if (mediaPlayer!=null){
mediaPlayer.pause();
playMusic.setBackgroundResource( android.R.drawable.ic_media_play );
}
}

So now, we will able to check if the media player is playing which is the music already play then invoke to
pauseStrat() when the user tapes the play button else the music is not play state then invoke to startMusic() in
order to start the music.

case R.id.playBtnId:
if (mediaPlayer.isPlaying()){
pauseMusic();
}else {
startMusic();
}
break;

Here, we have done to playing music and also able to pause the music when it already plating. But now we going
to do sliding the seek bar for sliding the music as we want. Now, we have Seek bar objects so set media player
duration to seek bar maximum then set on change listener to the object inside onCrreate() methods.

protected void onCreate(Bundle savedInstanceState) {


super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
setupUI();

seekBar.setMax( mediaPlayer.getDuration() );

seekBar.setOnSeekBarChangeListener( new SeekBar.OnSeekBarChangeListener() {


@Override

public void onProgressChanged(SeekBar seekBar, int i, boolean b){ }


@Override
public void onStartTrackingTouch(SeekBar seekBar) { }
@Override
public void onStopTrackingTouch(SeekBar seekBar) { }
} );
}

Since, we have all overide methods such as onProgressChanged(), onStartTrackingTouch() and

onStopTrackingTouch() of seek bar listener.So firstly implemtents on progress change which if the progress comes
from the user then seek our media player.

public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {


if (fromUser){
mediaPlayer.seekTo( progress );
}}

Then, set the left and right time when the music playing or the seek bar is sliding from left to right or right to left
inside of our own progress change method. Since, set text to left text view and pass instantiate a new class called
simple date format because we want to make sure that our time is in minute and second. Now, we can get the
current position of our media player and duration of our music/mp3 and set to an integer type variable.

int currentPosition=mediaPlayer.getCurrentPosition();
int duration=mediaPlayer.getDuration();

But, the current position and duration of our media player haven’t in the correct format as we want which means
they returns in milliseconds instead minute second format(mm:ss). So there is class called SimpleDateFormat
and contractor of it that allow to accept a string pattern that specify minutes and second. However, this pattern
performs API 24 and higher android API.

SimpleDateFormat simpleDateFormat=new SimpleDateFormat( "mm:ss" );


Now, we have an object of SimpleDataFormat to holds our minutes and second pattern then we can use it. Then,
sets to our text fields and we’re going to pass our data format objects and instantiate a Date class.

int currentPosition=mediaPlayer.getCurrentPosition();
int duration=mediaPlayer.getDuration();
SimpleDateFormat simpleDateFormat=new SimpleDateFormat( "mm:ss" );
leftTime.setText( simpleDateFormat.format( new Date( currentPosition ) ) );

rightTime.setText( simpleDateFormat.format( new Date( duration-currentPosition ) ) );

So, what’s happening here converting the current position and duration time into date format in order to set the
left and right time text view. Which means what ever is coming in millisecond it’s going to be translated to date
format.

Finally, we going to add another functionality which is we want to able to as the music we slide/move the seek
bar along. So, we can actually emulate the real music player. Hence, what we going to do is create a new method
called updateThead() and inside it we going to implement the thread which wants automatically sliding the seek
bar through each seconds or move left to right during the music is playing.

Hence, the tread means when an application component starts and the application does not have no any other
component running the android system start a new Linux process for that application with a single thread of
execution. So, by default all components of the same application run in the same process and thread which we
call in main thread. Now if an application component starts and there already exist the process where an
application because another component from the application exist then the component is started with that process
and uses the same thread of execution. Hence, we can arrange for different components in our location to run in
separate process and we can create adirional threads for any process.

Therefore, the android system allow us to create different threads or different lanes in which we can create
different processes to run on them. So, now we’re going to create a new thread to update our seek bar as well as
other things inside our application.

public void updateThread(){


thread=new Thread( ){
@Override
public void run() {
super.run();
}
};

thread.start();
}

Now, write our code inside override run() methods and add try..catch because of we have to able to catch any
error happens. Here,inside of try..catch we want to make sure that all of this is run while a certain conditions is
being. Hence, media player is not null and it’s still playing so we’re going to put a while loop. And then inside it
we’re going to implement to sleep for 50 milliseconds so the thread that sleep and takes a run-able action using
sleep() and runOnUiThread() respectively.

try {
while (mediaPlayer!=null && mediaPlayer.isPlaying()) {
Thread.sleep( 50 );
runOnUiThread( new Runnable() {
@Override
public void run() {

//our action
}
} );
}
}catch (Exception e){
e.printStackTrace();
}

Now, we’re going to update our left text field, right text field and our seek bar automatically. So, as music plays
we going to see our seek bar moving along synchronized with our left time and right time which the rest of the
time to play. So, we’re going to create some variables that holds the current media player position and the
duration of our media player and then set seek bar maximum to the new duration and set the progress of our seek
bar to new position. Finally, set the new current position of media player to left time and the new duration to our
right time text fields then invoke the updateThread() method when we want to play the music called in our
startMusic() method.

public void startMusic(){


...
updateThread();
...
}

runOnUiThread( new Runnable() {


@Override
public void run() {
int newPosition=mediaPlayer.getCurrentPosition();
int newMax=mediaPlayer.getDuration();
seekBar.setMax( newMax );
seekBar.setProgress( newPosition );

if (newMax-newPosition<100){
playMusic.setBackgroundResource( android.R.drawable.ic_media_play );

}
}
} );

Now, we going to implement when the user tapped or clicked previous or next button then what happen. So we
going to create two methods called backMusic() and nextMusic() for previous and next button respectively.
Then, invoking inside previous button tapped and next button tapped in on click listener events.

public void backMusic(){


if (mediaPlayer.isPlaying()){
mediaPlayer.seekTo( mediaPlayer.getDuration() );
}
}
public void nextMusic(){
if (mediaPlayer.isPlaying()){
mediaPlayer.seekTo( 0 );
}
}

Let’s see the full code as follows:

main activity.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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=".MainActivity">

<ImageView
android:id="@+id/imageView"
android:layout_width="242dp"
android:layout_height="199dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.139"
app:srcCompat="@drawable/audiospeaker" />
<ImageView
android:id="@+id/imageView2"
android:layout_width="363dp"
android:layout_height="10dp"
android:layout_marginTop="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView"
app:layout_constraintVertical_bias="0.0"
app:srcCompat="@drawable/divider" />

<TextView
android:id="@+id/titleMusicId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/title"
android:textColor="#E65100"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView2"
app:layout_constraintVertical_bias="0.138" />
<TextView
android:id="@+id/authorId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/author"
android:textColor="#0D47A1"
android:textSize="18sp"
android:textStyle="italic"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/titleMusicId"
app:layout_constraintVertical_bias="0.034" />
<SeekBar
android:id="@+id/seekBarId"
style="@android:style/Widget.DeviceDefault.SeekBar"
android:layout_width="284dp"
android:layout_height="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.496"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/authorId"
app:layout_constraintVertical_bias="0.183" />

<TextView
android:id="@+id/leftDurationId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0:00"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/seekBarId"
app:layout_constraintTop_toBottomOf="@+id/authorId"
app:layout_constraintVertical_bias="0.191" />
<TextView
android:id="@+id/rightDurationId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="10:12"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/seekBarId"
app:layout_constraintTop_toBottomOf="@+id/authorId"
app:layout_constraintVertical_bias="0.191" />

<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="15dp"
android:layout_marginTop="40dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.495"
app:layout_constraintStart_toStartOf="parent"
android:background="@color/media_background"
app:layout_constraintTop_toBottomOf="@+id/seekBarId">

<Button
android:id="@+id/previusBtnId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:drawable/ic_media_previous"/>

<Button
android:id="@+id/playBtnId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:drawable/ic_media_play"/>

<Button
android:id="@+id/nextBtnId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:drawable/ic_media_next"/>
</TableRow>
</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity.java

package com.course.musicboxapps;
import androidx.appcompat.app.AppCompatActivity;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import java.io.InterruptedIOException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {


private MediaPlayer mediaPlayer;
private ImageView artistImage;
private SeekBar seekBar;
private TextView leftTime,rightTime;
private Button prevMusic,playMusic,nextMusic;
private Thread thread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
setupUI();
seekBar.setMax( mediaPlayer.getDuration() );
seekBar.setOnSeekBarChangeListener( new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser){
mediaPlayer.seekTo( progress );
}
int currentPosition=mediaPlayer.getCurrentPosition();
int duration=mediaPlayer.getDuration();
SimpleDateFormat simpleDateFormat=new SimpleDateFormat( "mm:ss" );
leftTime.setText( simpleDateFormat.format( new Date( currentPosition ) ) );
rightTime.setText( simpleDateFormat.format( new Date( duration-currentPosition ) ) );
}

@Override
public void onStartTrackingTouch(SeekBar seekBar) { }
@Override
public void onStopTrackingTouch(SeekBar seekBar) { }
} );
}
public void setupUI(){
mediaPlayer=new MediaPlayer();
mediaPlayer=MediaPlayer.create( getApplicationContext(),R.raw.libe_sew_yiwedal );

artistImage=(ImageView)findViewById( R.id.imageView );
seekBar=(SeekBar)findViewById( R.id.seekBarId );
leftTime=(TextView)findViewById( R.id.leftDurationId );
rightTime=(TextView)findViewById( R.id.rightDurationId );
prevMusic=(Button)findViewById( R.id.previusBtnId );
playMusic=(Button)findViewById( R.id.playBtnId );
nextMusic=(Button)findViewById( R.id.nextBtnId );

prevMusic.setOnClickListener( this );
playMusic.setOnClickListener( this);
nextMusic.setOnClickListener( this );
}

@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.previusBtnId:
backMusic();
break;
case R.id.playBtnId:
if (mediaPlayer.isPlaying()){
pauseMusic();
}else {
startMusic();
}
break;
case R.id.nextBtnId:
nextMusic();
break;
}
}
public void startMusic(){
if (mediaPlayer!=null){
mediaPlayer.start();
updateThread();
playMusic.setBackgroundResource( android.R.drawable.ic_media_pause );
}
}
public void pauseMusic(){
if (mediaPlayer!=null){
mediaPlayer.pause();
playMusic.setBackgroundResource( android.R.drawable.ic_media_play );
}
}
public void updateThread(){
thread=new Thread( ){
@Override
public void run() {
super.run();
try {
while (mediaPlayer!=null && mediaPlayer.isPlaying()) {
Thread.sleep( 50 );
runOnUiThread( new Runnable() {
@Override
public void run() {
int newPosition=mediaPlayer.getCurrentPosition();
int newMax=mediaPlayer.getDuration();
seekBar.setMax( newMax );
seekBar.setProgress( newPosition );
leftTime.setText( new java.text.SimpleDateFormat("mm:ss").format( new Date( newPosition )
) );
rightTime.setText( new SimpleDateFormat("mm:ss").format( new Date( newMax-
newPosition ) ) );
if (newMax-newPosition<100){
playMusic.setBackgroundResource( android.R.drawable.ic_media_play );
}
}
} );
}
}catch (Exception e){
e.printStackTrace();
}
}
};
thread.start();
}

public void backMusic(){


if (mediaPlayer.isPlaying()){
mediaPlayer.seekTo( 0);
}
}
public void nextMusic(){
if (mediaPlayer.isPlaying()){
mediaPlayer.seekTo( mediaPlayer.getDuration()-1000 );
playMusic.setBackgroundResource( android.R.drawable.ic_media_play );
}
}
@Override
protected void onDestroy() {
super.onDestroy();
mediaPlayer.stop();
mediaPlayer.release();
}
}
.Chapter 10

1. Storage in Android shared preferences, Internal Storage and


SQLite Database

1.1. Introduction
Mobile apps need to store and retrieve small amount of data in files. On the Android platform, these files can be
saved either on the device’s internal memory or on an external storage media, such as a Secure Device (SD) card.
By default, all files stored in the internal storage are private to the app whereas files stored in the external storage
are accessible to all apps/users.
Android enables users to customize apps according to their needs. For example, a user can choose the
background image for an app. This background remains unchanged while the app is running. However when the
app is closed, the background changes back to the previous image. Shared preferences help us make persistent
changes in apps. Preferences allow users to personalize and specify settings for apps, such as font size, colors,
and background images.

The Android platform provides two types of preferences: activity-level preferences and app-level preferences.
Activity-level preferences are associated with a specific activity and only one preference for an activity is
allowed. App-level preferences are associated with an entire app. An app can have any number of app-level
preferences. These preferences are visible in the app’s context and are stored using primitive data types in the
form of key-value pairs. This data persists across user sessions even if the app is killed.

1.1.1 . Creating Shared Preferences

Android provides the android.content.SharedPreferences interface, which provides a framework that allows
us to save and retrieve persistent key-value pairs of built-in data types. The data types supported by the
SharedPreferences interface are:

l boolean
l float
l int
l long
l String

Shared preferences can be retrieved by using any of the following methods:

l getSharedPreferences(): This method is used for app-level preferences. It is used if your app uses multiple
preferences files identified by their name. This method takes two parameters, the first parameter refers to
the file name and the second parameter refers to the operating mode. The operating mode,
MODE_PRIVATE, MODE_WORLD_READABLE, or MODE_WORLD_WRITEABLE, specifies the
access permission for the preferences. For example:

SharedPreferences pref = getSharedPreferences (PREF_FILENAME,


MODE_WORLD_READABLE);

l getPreferences(): This method is used for activity-level preferences. It is used when only one preferences
file is required for your activity. Because this would be the only preferences file for the activity, you do
not supply a file name. If the specified shared preferences file exists, then it is opened; otherwise, it is
created. For example:

SharedPreferences pref = getPreferences(MODE_PRIVATE);

Now, we store data or information even if when we get out of our application the data or information are
persisted or saved when we come back to our android apps. There are different level for saved data/information
in android application. The first one is shared preference class which allow us to save/store primitive data key-
value pairs. There is also internal storage to store more private data on the device memory. The other one is
external storage to store public data on the shared external storage like SD card. And also we have more
organized way of storing data called SQLite database storage for more structured data in private storing data in a
database. And there is other options to store data on the web with own network server which can create a server
somewhere on the internet and then we can connect with our application. So, every time user’s can store
data/information externally through network connection.
So we going to start with shared preference class which allow us to save a small bits of data that we can use in
our application even after we have go out of our application next time when we come back the information is
saved and we can in record be used. For example when we want to develop a game application and save the last
highest score of users they’re playing/pause the game saved on their memory location.
Since, firstly let’s start in main activity which we going to save/store the data in our shared preference that
accepts from edit text when the we tapped the button then we will get out of the application come back and also
will show that information in the plain text that we saved before. So, we have create edit text, button and text
view in the proper design as we want.

Then, let’s create an instance of Edit text, button and textfield then instantiate them. So,the idea to use shared
preference class to save whatever we are getting from our edit text. Here, create Shared preference instance
called myPrefs and a static variable with string type that is the name of our preference file because a shared
preference followed its created internally android created an xml file which stores all the information for us.

private SharedPreferences myPrefs;


private static final String PREFS_NAME="myPrefesfile";

Here, the static variable called myPrefsfile we gives xml file name which store/saved all our information and we
can retrieve as we want.
Now, we’re going to instantiate our preference with getSharedPreference() methods and passed the first
parameter is string value which is the name of the xml file that we are creating, the next parameter is the mode in
our case pass zero(0) because we want this to be accessible.
public void onClick(View view) {
myPrefs=getSharedPreferences( PREFS_NAME,0 );
}

Then, we need to create an editor that will allow us to start adding items into our preference class object. So what
we do is as follows:
public void onClick(View view) {
myPrefs=getSharedPreferences( PREFS_NAME,0 );
SharedPreferences.Editor editor=myPrefs.edit();
}
Here, the object editor is our interface will allow us then start adding items into our shared preference. And then
we can put any types of key-value pairs to our share preference. Then, what we do is commit our editor by
invoking commit() method which save/store all things we have added to our editor.

public void onClick(View view) {


myPrefs=getSharedPreferences( PREFS_NAME,0 );
SharedPreferences.Editor editor=myPrefs.edit();
editor.putString( "message",enterMessage.getText().toString() );
editor.commit();
}

Now, how to get the data/information back. So, we’re going to create an instance Shared Preference class. Then
check if our preference object's contain the key values we have putted/stored in shared preference and when our
object contains any key values then get a values from shared preference that stored before and we can update our
text fields in order to show in user interface.

SharedPreferences shprefs=getSharedPreferences( PREFS_NAME,0 );


if (shprefs.contains( "message" )){
String message=shprefs.getString( "message","not found" );
resultText.setText( message );
}

The full code of the small apps main acitivty xml or the user interfaces
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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=".MainActivity">

<EditText
android:id="@+id/enterText"
android:layout_width="313dp"
android:layout_height="65dp"
android:ems="10"
android:hint="@string/enter_text"
android:inputType="textPersonName"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.175" />

<Button
android:id="@+id/saveBtnId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#01579B"
android:paddingHorizontal="16dp"
android:paddingVertical="16dp"
android:text="@string/btn_name"
android:textColor="#FFF"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/enterText"
app:layout_constraintVertical_bias="0.127" />

<TextView
android:id="@+id/resultTxtId"
android:layout_width="331dp"
android:layout_height="28dp"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/saveBtnId"
app:layout_constraintVertical_bias="0.523" />
</androidx.constraintlayout.widget.ConstraintLayout>

And the main activity java class file


package com.course.sharedpreferenceapps;

import androidx.appcompat.app.AppCompatActivity;
import android.content.SharedPreferences;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {


private EditText enterMessage;
private Button saveButton;
private TextView resultText;

private SharedPreferences myPrefs;


private static final String PREFS_NAME="myPrefesfile";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
enterMessage=(EditText)findViewById( R.id.enterText );
saveButton=(Button)findViewById( R.id.saveBtnId );
resultText=(TextView)findViewById( R.id.resultTxtId );

saveButton.setOnClickListener( new View.OnClickListener() {


@Override
public void onClick(View view) {
myPrefs=getSharedPreferences( PREFS_NAME,0 );
SharedPreferences.Editor editor=myPrefs.edit();
editor.putString( "message",enterMessage.getText().toString() );
editor.commit();
} } );
SharedPreferences shprefs=getSharedPreferences( PREFS_NAME,0 );
if (shprefs.contains( "message" )){
String message=shprefs.getString( "message","not found" );
resultText.setText("message:"+ message );
}
}
}
1.1. Write/read text file
Under this project we’re going to create an android apps that will write a file into our internal storage the will
read from that file. Now, create a text file and saved on our device so first design our user interface or xml files
which means we want to add multiline text and button for accepting any text file from users then saved to our
device when they taped on button.

<EditText
android:id="@+id/enterTextId"
android:layout_width="371dp"
android:layout_height="219dp"
android:gravity="start|top"
android:hint="@string/enter_text"
android:inputType="textMultiLine"
android:textAlignment="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.13" />

<Button
android:id="@+id/saveBtnId"
android:text="@string/save_btn"

… />
When we have finished our user interface then next we’re going to create two methods called writeToFile() and
readFromfile() for write the text from our multi-line text field and read the data that already saved respectively.
In order to implement writeToFile() method we used the OutputStream class because all the data we feed into
our stream writer it comes in as a bits or stream of bits get small piece of information. So, there is a process that
we need to follow in order to transform the bits into string or the string into bits. And also, when we do in file we
have to add exception handling.

public void writeToFile(String message){


try{
OutputStreamWriter outputStreamWriter=new OutputStreamWriter(openFileOutput( "myfile.txt"
,Context.MODE_PRIVATE) );
outputStreamWriter.write( message );
outputStreamWriter.close();
}catch (Exception e) {
e.printStackTrace();
}

Here, we have passed the string which is the file name that we want to write into and the second parameter is the
mode which is specify sharing the data that we are writing with other application then we can open the file and
write into opened file. And finally, we have to close because stream of bits a lot of memory being used so for
release back after finished our work we have to closed our opened file.

The next method we need work on is readFromFile() which is we need to be able to read a text from a file that
saved before and return a string. Inside this method, first create a string variable called result that holds a text
from a file that we read. So, we need to create an input stream allow us to go to fetch our texts from the file but
but the text put in bit format so we’ll be able to take that in create a string which will then return as a result and
display on the screen.
public String readFromFile(){
String result="";
try{
InputStream inputStream = openFileInput( "myfile.txt" );
if (inputStream!=null){
InputStreamReader inputStreamReader=new InputStreamReader( inputStream );
BufferedReader bufferedReader=new BufferedReader( inputStreamReader )
String tempText="";
StringBuilder stringBuilder=new StringBuilder( );
while ((tempText=bufferedReader.readLine())!=null){
stringBuilder.append( tempText );
}
inputStream.close();
result=stringBuilder.toString();
}
}catch (Exception e){
e.printStackTrace();
}
return result;
}

Here, the inputstream reader reads the information from the file because still its in a stream of bits. And the
second one called BufferReader which is a class that will create a bucket/buffer where we’re going to put all of
the bit and then we’ll be able to read those bit in a better and faster way. Then, we’re going to instantiate another
class called StringBuilder because now we are ready to start getting text from BuffereReader which takes in our
input stream reader. And then we able to get the actual string and build all of those bits into characters,
characters into string so that we can shows it to our users.
Then invoke the our methods which means, when we tapped the save buttons then our apps check if the text null
or not, when our edit text have some text value then save to our text file. So, we have action listener and
invoking writeToFile() method here.

saveBtn.setOnClickListener( new View.OnClickListener() {


@Override
public void onClick(View view) {
if (!enterText.getText().equals( "" )){
String ourText=enterText.getText().toString();
writeToFile( ourText );
}else{
Toast.makeText( MainActivity.this,"Please enter",Toast.LENGTH_LONG ).show();
}
}} );

And also invoking readFromFile() methods which invoke when our application loads so we have invoke the
method inside onCreate() methods.

if (readFromFile()!=null){
enterText.setText( readFromFile() );
}

The full java class code as follows:


import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class MainActivity extends AppCompatActivity {


private EditText enterText;
private Button saveBtn;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );

enterText=(EditText)findViewById( R.id.enterTextId );
saveBtn=(Button)findViewById( R.id.saveBtnId );
saveBtn.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View view) {
if (!enterText.getText().equals( "" )){
String ourText=enterText.getText().toString();
writeToFile( ourText );
}else{
Toast.makeText( MainActivity.this,"Please ",Toast.LENGTH_LONG ).show();
}

}
} );

try {
if (readFromFile()!=null){
enterText.setText( readFromFile() );
}
}catch (Exception e){
e.printStackTrace();
}
}
public void writeToFile(String text){
try{
OutputStreamWriter outputStreamWriter=new OutputStreamWriter(openFileOutput( "myfile.txt"
,Context.MODE_PRIVATE) );
outputStreamWriter.write( text );
Toast.makeText( MainActivity.this,"The text write succesfully on the file",Toast.LENGTH_LONG ).show();
outputStreamWriter.close();
}catch (Exception e) {
e.printStackTrace();
}
}
public String readFromFile(){
String result="";
try{
InputStream inputStream = openFileInput( "myfile.txt" );
if (inputStream!=null){
InputStreamReader inputStreamReader=new InputStreamReader( inputStream );
BufferedReader bufferedReader=new BufferedReader( inputStreamReader )
String tempText="";
StringBuilder stringBuilder=new StringBuilder( );
while ((tempText=bufferedReader.readLine())!=null){
stringBuilder.append( tempText );
}
inputStream.close();
result=stringBuilder.toString();
}
}catch (Exception e){
e.printStackTrace();
}
return result;
}
}
1.1. Stored data in SQLite
Saving/store data to a database is ideal for repeating or structured data, such as contact information. The APIs
we’ll need to use a database on Android are available in the android.database.sqlite package.

Caution: Although these APIs are powerful, they are fairly low-level and require a great deal of time and effort
to use:

l There is no compile-time verification of raw SQL queries. As our data graph changes, we need to update
the affected SQL queries manually. This process can be time consuming and error prone.
l We need to use lots of boilerplate code to convert between SQL queries and data objects.

For these reasons, highly recommended using the Room Persistence Library as an abstraction layer for
accessing information in our app's SQLite databases.

1.1.1 . Define a schema and contract


One of the main principles of SQL databases is the schema: a formal declaration of how the database is
organized. The schema is reflected in the SQL statements that you use to create your database. We may find it
helpful to create a companion class, known as a contract class, which explicitly specifies the layout of our
schema in a systematic and self-documenting way.

A contract class is a container for constants that define names for URIs, tables, and columns. The contract class
allows to use the same constants across all the other classes in the same package. This lets we change a column
name in one place and have it propagate throughout our code.

A good way to organize a contract class is to put definitions that are global to our whole database in the root
level of the class. Then create an inner class for each table. Each inner class enumerates the corresponding table's
columns.
Note: By implementing the BaseColumns interface, your inner class can inherit a primary key field called
_ID that some Android classes such as CursorAdapter expect it to have. It's not required, but this can help
your database work harmoniously with the Android framework.

1.2. Create a simple contact manager-SQLite


We are going to build a contact manager application which mainly data driven in the sense that we won’t have
many user interface to interact with but we mainly focused coding parts of android applications. So, we want to
create a database and inside of it we’ll have one table called contact table and this contact table will have some
records such as contact name and phone number.

Now let’s create Data package, Model package and Util package inside our application. We are going to create a
model class called Contact under our Model . And also inside the class create different instance variable such as
id integer type, name and phoneNumber String type for stored contact information of a person. Then create
different constructor which means first create empty constructor or default constructor, the second constructor
have three parameter id, name and phone and the third constructor have two name and phone number
parameterize constructor. But each three constructor have different signature normally in programming this types
of paradigms called Constructor overloading. Then , after creating our constructor the next thing we’re going to
create setter and getter for our instance variable. Our Contact class inside Model package's looks as follows:

package Model;
public class Contact {

private int id;


private String name;
private String phoneNumber;

public Contact() {
}
public Contact(String name, String phoneNumber) {
this.name = name;
this.phoneNumber = phoneNumber;
}
public Contact(int id, String name, String phoneNumber) {
this.id = id;
this.name = name;
this.phoneNumber = phoneNumber;
}
public int getId() {
return id;
}

public void setId(int id) {


this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}

The next thing, we’re going to do is create a database handler class. So, create a database there are a lot of
properties/methods that we can attached to it which are create, write to the database and update or delete. But
also have other classes that we need to instantiate. Hence, create a new class called DatabaseHandler inside Data
package which will handle all of the functionalities that will need to our database. Since, this database handler
has to extends SQLite open handler class which comes with Android. Then create constructor and implements
certain methods of our base class in derived class.

package Data;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DatabaseHandler extends SQLiteOpenHelper {
public DatabaseHandler(@Nullable Context context, @Nullable String name, @Nullable
SQLiteDatabase.CursorFactory factory, int version) {
super( context, name, factory, version );
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) { }
}

Now, we’re going to create Util class which has static instances inside our Utils package and we want to add
some static variables that will reference them on our database handler. Hence, first sets all database version,
database name and table name then sets our columns name in our table. Hence, all instance should be public
because we want to access those instance in another class.
package Utils;
public class Util {

public static final int DATABASE_VERSION=1;


public static final String DATABASE_NAME="contactDB";
public static final String TABLE_NAME="contacts";

public static final String KEY_ID="id";


public static final String KEY_NAME="name";
public static final String KEY_PHONE="phoneNumber";
}

Then, now we’re going to start create our database and start adding an item to our tables. So, go to database
handler class which extends SQLite open helper and it override onCreate() and onUpgrade() methods. And also
we have a constructor when we extend or inherit from our SQLite open helper class interface class which will
allow us to construct our database handler. Our constructor looks as follow:
public DatabaseHandler(Context context) {
super( context, Util.DATABASE_NAME, null,Util.DATABASE_VERSION );
}

The next thing we need to create the actual tables inside onCreate() methods which we are passing our database
object so we can access it. But database has its own scripting languages that different from other language like
java in order to delete or update or writing to it. Since, write the actual sql query command to create a table and
assign to a string. Then , we need to do creating the table through execSQL().

public void onCreate(SQLiteDatabase sqLiteDatabase) {


String create_table="CREATE TABLE "+Util.TABLE_NAME +"("
+Util.KEY_ID +" INTEGER PRIMARY KEY," + Util.KEY_NAME+" TEXT," + Util.KEY_PHONE+" TEXT"
+ ")";
sqLiteDatabase.execSQL( create_table );
}

The next method that override called onUpgrade() when we want to upgrade our database. For example we we
want to delete a tables from the database we have implements inside this method. Since, we’re going to
drop/delete the table if the table already create and then create again by invoking onCreate() method after deleted
the tables.
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
sqLiteDatabase.execSQL( "DROP TABLE IF EXISTS "+Util.TABLE_NAME );
onCreate(sqLiteDatabase);
}

Now, we’re going to create a certain CRUD(create, update and delete) basic operations which means they are
the basic operations that we need to operate on our database and table. So first we’re going to do add contact to
the table. So, create addContact() method, inside here first we need to instantiate a database which make sure our
database has all the functionalities and all the properties needed to write to our database. Next, we’re going to
use content values which is another data abstraction that we can use like Hash map so we can add key-value
pairs object. Then inserting all of items in table and finally close our database.

public void addContact(Contact contact){


SQLiteDatabase db=this.getWritableDatabase();
ContentValues value=new ContentValues( );
value.put( Util.KEY_NAME,contact.getName() );
value.put( Util.KEY_PHONE,contact.getPhoneNumber() );

db.insert(Util.TABLE_NAME,null,value );
db.close();
}
Now, we want to get the values from the database. So here we’re going to create a method called getContct()
with the Contact type. Now, we make sure that we are able to get the readable database by instantiate SQLite
database SQLiteDatabase db=this.getReadableDatabase(). Next, we create cursor which is an object/class that
allows us to go through or iterate through our database and get data information. Then create Contact objects
then we are passing what ever the cursor starting from index at 0 up to the last columns when the cursor are not
null. Then we can return our contact objects that we need to retrieve contact from tables.
public Contact getContact(int id){
SQLiteDatabase db=this.getReadableDatabase();
Cursor cursor= db.query( Util.TABLE_NAME,new String[]
{Util.KEY_ID,Util.KEY_NAME,Util.KEY_PHONE},Util.KEY_ID+"=?", new String[]
{String.valueOf( id )},null,null,null,null);
if (cursor!=null)
cursor.moveToFirst();
Contact contact=new Contact (Integer.parseInt(cursor.getString(0) ),cursor.getString(1),cursor.getString(2) );
return contact;
}

So now we are constructing a query that will allow us to get all of information presetting to an item with id that
we are passing in our contact printer. In the statement of query() methods the first parameter is pass the table
context and the second paramater pass array of String which we are going to be retrieving, and in the third
parameter is the key or the condition because we want get one contact as a certain condition. Then passing array
string which is our id for a condition and the rest of the parameter set null.
Next, we are going to create get all contacts by the list of contact. So, we’re going to create a List of contact
method called getAllContact() method which gets all contacts from the table/database. Then inside the method
instantiate the database then create an array list of contacts contain contact/contact object then next to is select
all contacts which means write select sql query command. Then we can use cursor object to get all contact
information from the given table. Next to execute our query we need to loop through our contacts so we have a
cursor which has all of our contacts which our cursor object has entire items that will keep going until the last
item is found. Then inside our loops create a Contact object then set the values to our setter methods which found
in our Contact class inorder to add contact list. Finally, return our contact list in the function.
public List<Contact> getAllContact() {
SQLiteDatabase db = this.getReadableDatabase();
List<Contact> contactList = new ArrayList<>();
String selectAll = "select * from " + Util.TABLE_NAME;
Cursor cursor = db.rawQuery( selectAll, null );
if (cursor.moveToFirst()) {
do {
Contact contact = new Contact();
contact.setId( Integer.parseInt( cursor.getString( 0 ) ) );
contact.setName( cursor.getString( 1 ) );
contact.setPhoneNumber( cursor.getString( 2 ) );
//then add our contact object to array list
contactList.add( contact );
} while (cursor.moveToNext());
}
return contactList;
}

Then, next we’re going to continue to add more operation on Database handler class like updating and deleting
some records on the database/table. So, let’s create a method called updateContact() and it inside our database
handler class for implementing our update statements and it returns integer values. So, first we need instantiate
our database then create a Contentvalues object and update any values in a certain condition.
//update an item from contacts
public int updateContact(Contact contact){
SQLiteDatabase db=this.getWritableDatabase();
ContentValues value=new ContentValues( );
value.put( Util.KEY_NAME,contact.getName() );
value.put( Util.KEY_PHONE,contact.getPhoneNumber() );
int result=db.update( Util.TABLE_NAME,value,Util.KEY_ID+" =?",new String[]
{String.valueOf( contact.getId() )} );

return result;
}

Now, let’s as perform a delete operation which deletes a specific rows in contact tables. So, first create
deleteContact() methods inside Database handler class and we need to pass an contact object. Then inside here
instantiate the database then invoke delete() method using SsQLite database class objects that instantiated and we
passed our table name and the condition which means at which position we want to delete a row of
table/database.
public int deleteUpdate(Contact contact){
SQLiteDatabase db =this.getWritableDatabase();
int result=db.delete( Util.TABLE_NAME,Util.KEY_ID+" =?", new String[]{String.valueOf( contact.getId() )} );
return result;
}
Then the last one we want to get the number of contacts that we have in our contact lists. So, first we’re going to
create getCount() methods in Database handler class which give us number of items we have in our database.
public int getContactsCount(){
SQLiteDatabase db=this.getReadableDatabase();
String query= "SELECT * FROM "+Util.TABLE_NAME;
Cursor cursor=db.rawQuery( query,null );
cursor.close();
int result=cursor.getCount();
return result;
}

Now, we are going back to main activity class and inside of our Main activity we want to instantiate our
DatabaseHandler class that we created and passing context(this). Then insert contacts by invoking to
addContact() methods by database handler object and passed an items as we want.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
DatabaseHandler db = new DatabaseHandler( this );
Log.d( "Insert", "Data inserting..." );
db.addContact( new Contact( "Yohana", "+251912160207" ) );
db.addContact( new Contact( "Tigest", "0912925867" ) );
db.addContact( new Contact( "Kelemu", "0912160106" ) );
}

Next to it we’re going to retrieve a person contact such as a specific person name and phone number. We used
getContact() method and passed an id of a record and assigned to an object of Contact class that holds all
information of a specific person’s contact.
Log.d( "one contact","select one contact" );

Contact contact=db.getContact( 1 );

Log.d( "One contacrt","Id:"+contact.getId()+" Name:"+contact.getName()+" Phone


Number:"+contact.getPhoneNumber() );

Now we want to retrieve all our contacts by invoking getAllContacts() using Database handler class object then
set to contact lists. Here, we’re going to create Contact list object and holds all information that returns from
getAllContact() method then iterate through each contact list for retrieve all the records in a given table/database
that inserted before.
Log.d( "Reading", "Reading all contacts..." );
List<Contact> contactList = db.getAllContact();
for (Contact c : contactList) {
String log = "ID:" + c.getId() + " Name:" + c.getName() + " Phone Number:" + c.getPhoneNumber();
Log.d( "All our contacts:", log );
}

Now, we going to update a contacts which means let’s us update a specific person name or phone number or both
name and phone number. So, first create a Contact objects and invoking to getUpdate() Database holder class and
passing an object of contact class and it returns an integer values so we want to assign to integer variable. Then
set a new values that we want to change in a table/database.
//update some information
Log.d( "Updating","Update a specic person contacts..." );
Contact oneContact=db.getContact( 3 );
oneContact.setName( "Abocher" );
oneContact.setPhoneNumber( "0920514538" );
int result=db.updateContact( oneContact );
Log.d( "updated","our updated"+String.valueOf( result )+" Name:"+oneContact.getName()+" Phone
Number:"+oneContact.getPhoneNumber() );

Now, delete a specific rows in a table which means let’s delete one contact that we won’t in our contact lists.

int delres=db.deleteUpdate( oneContact );


Log.d( "Deleted",String.valueOf( delres )+"deleted.." );

Finally, let’s us get the number of contacts that we have in our contact lists as follows:
//get the number of contacts that we have
int numContact=db.getContactsCount();
Log.d( "Number count","Number of Contacts:"+String.valueOf( numContact ) );

Now let’ see the full code for each class such as Model, DatabaseHandler, Util class and MainActivity class.
First see Util.class
package Utils;

public class Util {


public static final int DATABASE_VERSION=1;
public static final String DATABASE_NAME="contactDB";
public static final String TABLE_NAME="contacts";

public static final String KEY_ID="id";


public static final String KEY_NAME="name";
public static final String KEY_PHONE="phoneNumber";
}

Then let’s see the our Contact.java class as follows:


package Model;

public class Contact {

private int id;


private String name;
private String phoneNumber;

public Contact() {
}
public Contact(String name, String phoneNumber) {
this.name = name;
this.phoneNumber = phoneNumber;
}
public Contact(int id, String name, String phoneNumber) {
this.id = id;
this.name = name;
this.phoneNumber = phoneNumber;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}

And then let’s see our DatabaseHandeler.java class as follows:


package Data;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.view.View;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import Model.Contact;
import Utils.Util;

public class DatabaseHandler extends SQLiteOpenHelper {

public DatabaseHandler(Context context) {


super( context, Util.DATABASE_NAME, null, Util.DATABASE_VERSION );
}

@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
String create_table = "CREATE TABLE " + Util.TABLE_NAME + "("
+ Util.KEY_ID + " INTEGER PRIMARY KEY," + Util.KEY_NAME + " TEXT," + Util.KEY_PHONE + "
TEXT"
+ ")";
sqLiteDatabase.execSQL( create_table );
}

@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
sqLiteDatabase.execSQL( "DROP TABLE IF EXISTS " + Util.TABLE_NAME );

onCreate( sqLiteDatabase );
}

public void addContact(Contact contact) {


SQLiteDatabase db = this.getWritableDatabase();
ContentValues value = new ContentValues();
value.put( Util.KEY_NAME, contact.getName() );
value.put( Util.KEY_PHONE, contact.getPhoneNumber() );

db.insert( Util.TABLE_NAME, null, value );


db.close();
}

public Contact getContact(int id) {


SQLiteDatabase db = this.getReadableDatabase();

Cursor cursor = db.query( Util.TABLE_NAME, new String[]{Util.KEY_ID, Util.KEY_NAME, Util.KEY_PHONE},


Util.KEY_ID + "=?", new String[]{String.valueOf( id )}, null, null, null, null );
if (cursor != null)
cursor.moveToFirst();
Contact contact = new Contact( Integer.parseInt( cursor.getString( 0 ) ), cursor.getString( 1 ), cursor.getString(
2 ) );
return contact;
}

public List<Contact> getAllContact() {


SQLiteDatabase db = this.getReadableDatabase();
List<Contact> contactList = new ArrayList<>();
String selectAll = "select * from " + Util.TABLE_NAME;
Cursor cursor = db.rawQuery( selectAll, null );
if (cursor.moveToFirst()) {
do {
Contact contact = new Contact();
contact.setId( Integer.parseInt( cursor.getString( 0 ) ) );
contact.setName( cursor.getString( 1 ) );
contact.setPhoneNumber( cursor.getString( 2 ) );
//then add our contact object to array list
contactList.add( contact );

} while (cursor.moveToNext());
}
return contactList;
}

//update an item from contacts


public int updateContact(Contact contact){
SQLiteDatabase db=this.getWritableDatabase();
ContentValues value=new ContentValues( );
value.put( Util.KEY_NAME,contact.getName() );
value.put( Util.KEY_PHONE,contact.getPhoneNumber() );
int result=db.update( Util.TABLE_NAME,value,Util.KEY_ID+" =?",new String[]
{String.valueOf( contact.getId() )} );

return result;
}
public int deleteContact(Contact contact){
SQLiteDatabase db =this.getWritableDatabase();
int result=db.delete( Util.TABLE_NAME,Util.KEY_ID+" =?",new String[]{String.valueOf( contact.getId() )} );
return result;
}

public int getContactsCount(){


SQLiteDatabase db=this.getReadableDatabase();
String query= "SELECT * FROM "+Util.TABLE_NAME;
Cursor cursor=db.rawQuery( query,null );
int result=cursor.getCount();
return result;
}
}

Finally, let’s see the main activity class as follows:


package com.course.contactmanagerapps;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import java.util.List;
import Data.DatabaseHandler;
import Model.Contact;

public class MainActivity extends AppCompatActivity {


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
DatabaseHandler db = new DatabaseHandler( this );

Log.d( "Insert", "Data inserting..." );


db.addContact( new Contact( "Yohana", "+251912160207" ) );
db.addContact( new Contact( "Tigest", "0912925867" ) );
db.addContact( new Contact( "Kelemu", "0912160106" ) );

Log.d( "one contact","select one contact" );


Contact contact=db.getContact( 1 );
Log.d( "One contacrt","Id:"+contact.getId()+" Name:"+contact.getName()+" Phone
Number:"+contact.getPhoneNumber() );

Log.d( "Reading", "Reading all contacts..." );


List<Contact> contactList = db.getAllContact();
for (Contact c : contactList) {
String log = "ID:" + c.getId() + " Name:" + c.getName() + " Phone Number:" + c.getPhoneNumber();
Log.d( "All our contacts:", log );
}

//update some information


Log.d( "Updating","Update a specic person contacts..." );
Contact oneContact=db.getContact( 4 );
oneContact.setName( "Abocher" );
oneContact.setPhoneNumber( "0920514538" );
int result=db.updateContact( oneContact );
Log.d( "updated","our updated"+String.valueOf( result )+" Name:"+oneContact.getName()+" Phone
Number:"+oneContact.getPhoneNumber() );

//get the number of contacts that we have


int numContact=db.getContactsCount();
Log.d( "Numbercount","Number of Contacts:"+String.valueOf( numContact ) );
//delete a row from a table
Log.d( "delete","deleting an item..." );
Contact contact1=db.getContact( 9 );
int delres=db.deleteContact( contact1 );
Log.d( "Deleted",String.valueOf( delres )+"rows deleted.." );
}
}

.Chapter Eleven
1. Grocery List Apps
In this, app we will build in the Grocery list apps which add an item to the apps when we open the apps the first
time, and also have an item list when we added an item and when we tapped on an item shows the details of a
list. And in this apps we can delete or update an items using some icons.

Since, create a new project with Basic activity instead of Empty activity because we need the floating buttons
apps. The floating button action allows us if we were to run an application which the buttons relay on. In the
floating button’s we have include tag in main_activity layout xml file that includes the layout content main
which means we could create another content on our xml view .
Now, in order to organize our application let’s create another packages to put our application files more better
ways. So, create Activities package firstly on our application which holds all of our activities class that we have.
And also, create Model, Data, UI and Utils package or folder to more organize our applications. When we have
those folder/package we going to start our UI layout. So, we are going to open our content main xml file from
our resource and we we’re going to put the float action to middle because this button is actually inside of content
activity. Then , change the layout gravity to center and the icons which means the default icon is email but we
want to change into add/plus sing icon. Then add text to give aditional information about what will expect from
users. Here, we want to say Add first item as information about when we tapped the button what we will do.

<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="@dimen/fab_margin"
app:srcCompat="@android:drawable/ic_input_add" />
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/add_item"
android:textSize="20sp"
/>

Then, to create a dialog file which when we tapped on add button then something will pop up and alert dialog
which will have two field and button that we can enter item to it. Since, create a new layout in our resource and
name it called popup.xml then inside it create our the our User Interface as follows:
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="14dp"
android:layout_margin="10dp">
<TextView
android:id="@+id/addGtocerytxtId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:textSize="23dp"
android:textStyle="bold"
android:text="@string/add_grocery"/>
<EditText
android:id="@+id/enterGroceryId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/addGtocerytxtId"
android:hint="@string/enter_item"
android:layout_marginTop="10dp"
/>
<EditText
android:id="@+id/enterQuantityId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textStyle="italic"
android:hint="@string/enter_quantity"
android:layout_below="@+id/enterGroceryId"
android:layout_marginTop="10dp"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/save_btn"
android:textStyle="bold"
android:background="@color/backroudButtn"
android:layout_below="@+id/enterQuantityId"
android:textColor="@color/textColor"
android:textSize="24sp"
android:layout_marginTop="20dp"/>
</RelativeLayout>
</androidx.cardview.widget.CardView>
</androidx.appcompat.widget.LinearLayoutCompat>
Now, we’re go back to main activity class and set up our dialog alert. So first create a private method called
createpopupdialogue() which able to show our popup.xml layout that we created above. And instantiate our
dialog builder and alert dialog inside our method.
private void createDialogpopup(){
alertBuilder=new AlertDialog.Builder( this );
View view=getLayoutInflater().inflate( R.layout.popup ,null);

groceryItem=(EditText)view.findViewById( R.id.enterGrocer yId );

quantity=(EditText)view.findViewById( R.id.enterQuantityId );
save=(Button)view.findViewById( R.id.saveBtnId );
alertBuilder.setView( view );
dialog=alertBuilder.create();
dialog.show();
}

Now, we’re going to create a Grocery class inside our Model package which allows us to create a grocery object
which means its is the blue print of a grocery item. So,here we defined id, name, quantity and added date as a
fields inside the class Grocery. Then create constructors that have different signature which means the first
constructor is empty constructor/default the second constructor has all fields and the last constructor has name,
quantity and added date parameters. Then, set getter and setter of the fields that we have.
package com.course.mygroceryapps.Model;

public class Grocery {


public int id;
public String name;
public String quantity;
public String addDate;

public Grocery() {
}
public Grocery(String name, String quantity, String addDate) {
this.name = name;
this.quantity = quantity;
this.addDate = addDate;
}
public Grocery(int id, String name, String quantity, String addDate) {
this.id = id;
this.name = name;
this.quantity = quantity;
this.addDate = addDate;
}

public int getId() {


return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getQuantity() {
return quantity;
}
public void setQuantity(String quantity) {
this.quantity = quantity;
}
public String getAddDate() {
return addDate;
}
public void setAddDate(String addDate) {
this.addDate = addDate;
}
}

Now, we’re going to create a database that will hold our Grocery entries. So, first create a constant class inside
Util package which holds all constants variable like database version, database name, table name and columns of
a table that we need to create our database.
package com.course.mygroceryapps.Utils;
public class Costants {
public static final int DB_VERSION=1;
public static final String DB_NAME="groceryDB";
public static final String TABLE_NAME="grocery";

public static final String KEY_ID="id";


public static final String KEY_NAME="grocery_name";
public static final String KEY_QTY="quantity";
public static final String ADD_DATE="addedDate";
}

Then, create DatabaseHandler class in data package which is extends/inherits from SQLiteOpenHelper
interface/class since we are extends an interface that we need to implement different methods like onCreate() and
onUpgrade() methods. And also create a constructor which will pass our database name and version to super
class that we inherited.
private Context context;
public DatabaseHandeler(Context context) {
super( context, Costants.DB_NAME, null, Costants.DB_VERSION );
this.context=context;
}

Here, we have passed our contex, our database name , factory as null and our database version to super class and
also we have set our context inside of our constructor. Then we’re going to go on create method which we’re
passing our database objects so it allow us to do things with our database. Since, we can create our table by
writing SQLite query statements. First write our SQLite query for creating a table and assign to a variable then
executed using our SQLiteDatabase class and pass our variable.
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
String CREATE_TABLE="CREATE TABLE "+Costants.TABLE_NAME+ "("
+ Costants.KEY_ID +" INTEGER PRIMARY KEY, "
+ Costants.KEY_NAME +" text,"
+ Costants.KEY_QTY +" TEXT ,"
+ Costants.ADD_DATE +" LONG );";
sqLiteDatabase.execSQL( CREATE_TABLE );
}

Let’s implement the other method called onUpgrade() methods when our table is already existing then we want
to delet/drop the existing table and replaced by our upgraded table as follows:
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
sqLiteDatabase.execSQL( "DROP TABLE IF EXISTS "+Costants.TABLE_NAME );
onCreate( sqLiteDatabase );
}

Now, we have a table/ a database so the next things that we want to do is CRUD(create, read, update or delete)
database operations. So, we’re going to create different methods for different operations which means
addgrocery(), updateGrocery(), getGerocery(), getAllGrocery(), deletGrocery() and countGrocery() methods fo
adding an item, updating grocery items, get a specific item from the list, get all grocery items, delete a specific
item from the list and get the total number we have in our database respectively.
//Add an item to our database
public int addGrocery(Grocery grocery){
return 0;
}
//Get a grocery item
public Grocery getGrocery(int id){
return null;
}
//Get all grocery lists
public List<Grocery> getAllGrocery(){
return null;
}
//update our database/table item
public int updateGrocery(Grocery grocery){
return 0;
}
//delete an item from our database/table
public int deleteGRocery(int id){
return 0;
}
//get the total number of our items
public int coundGrocery(){
return 0;
}

Hence, when we have the skeleton of our CRUD operations the we can implements each methods. So, let us start
from the first method called addGrocery() which add an item to our database. Firstlly, make our database
writable by instantiate SQLite database class and then create content values which allow us key-value pairs to
add an item to our table/database then put an items to our content values. Then excute the SQLite command
which insert any record to our table/database called insert().
//Add an item to our database
public void addGrocery(Grocery grocery){
SQLiteDatabase db=this.getWritableDatabase();
ContentValues values=new ContentValues( );
values.put( Costants.KEY_NAME, grocery.getName() );
values.put( Costants.KEY_QTY,grocery.getQuantity() );
values.put( Costants.ADD_DATE, java.lang.System.currentTimeMillis() );
long result= db.insert( Costants.TABLE_NAME,null,values );
}

Then, we’re going to implement the second method called getGrocery() method which will returns a specific
Grocery items. So, to implement the method first we have instantiate our database which allow us to execute any
SQLite database queries. And then, we want to create a cursor that we want to iterate through our database/table
inorder to retrieve an item from the table/database.
//Get a grocery item
public Grocery getGrocery(int id){
SQLiteDatabase db=this.getWritableDatabase();
Cursor cursor=db.rawQuery( "select * from "+Costants.TABLE_NAME,null );
Grocery grocery=new Grocery( );
grocery.setId( Integer.parseInt( cursor.getString( cursor.getColumnIndex( Costants.KEY_ID ) ) ) );

grocery.setName( cursor.getString( cursor.getColumnIndex( Costants.KEY_NAME ) ) );


grocery.setQuantity( cursor.getString( cursor.getColumnIndex( Costants.KEY_QTY ) ) );

DateFormat dateFormat=DateFormat.getDateInstance();
String formatedDate=dateFormat.format( new Date( cursor.getLong( cursor.getColumnIndex( Costants.ADD_DATE
) ) ).getTime() );
grocery.setAddDate( formatedDate );

return grocery;
}

The third method we’re going to implement is retrieve all grocery item lists from our database/table. So, inside
this method we have instantiate our database and then create array list that holds different grocery items. Then
we have create a cursor that holds the executable query result and iterate through our database/table item lists.
After assign the our result set to cursor check if our cursor move to first if it is true use do--while loop for
iterating until the cursor reach on the last lists.
//Get all grocery lists
public List<Grocery> getAllGrocery(){
SQLiteDatabase db=this.getReadableDatabase();
List<Grocery> groceryList=new ArrayList<>( );
Cursor cursor=db.query( Costants.TABLE_NAME,new String[]{Costants.KEY_NAME, Costants.KEY_QTY,
Costants.ADD_DATE},null,null,null,null,Costants.ADD_DATE+" DESC" );
if (cursor.moveToFirst()){
do {
Grocery grocery=new Grocery( );
grocery.setId( Integer.parseInt(cursor.getString(cursor.getColumnIndex(Costants.KEY_ID ))));
grocery.setName(cursor.getString(cursor.getColumnIndex( Costants.KEY_NAME ) ) );
grocery.setQuantity(cursor.getString(cursor.getColumnIndex(Costants.KEY_QTY)) );

DateFormat dateFormat=DateFormat.getDateInstance();
String formatedDate=dateFormat.format( new
Date( cursor.getLong( cursor.getColumnIndex( Costants.ADD_DATE ) ) ).getTime() );
grocery.setAddDate( formatedDate );

groceryList.add( grocery );
}while (cursor.moveToNext());
}
return groceryList;
}

Then, now we’re going to implement the updateGrocery() methods which return an integer value and we passed
an actual Grocery object. So, here we have instantiate our database and then create Content values which holds
our values that get from user. Then we have execute update() query command and it return an integer values.
//update our database/table item
public int updateGrocery(Grocery grocery){
SQLiteDatabase db=this.getWritableDatabase();

ContentValues values=new ContentValues( );


values.put( Costants.KEY_NAME, grocery.getName() );
values.put( Costants.KEY_QTY,grocery.getQuantity() );
values.put( Costants.ADD_DATE, java.lang.System.currentTimeMillis() );

int result=db.update( Costants.TABLE_NAME,values,Costants.KEY_ID +" =?", new String[]


{String.valueOf( grocery.getId() )} );
return result;
}
Then at the fifth method called deleteGrocery() we want to implement delete an item from table/database. So,
here we’re going to write SQLite query commands in order to delete an item from the lists of grocery after
instantiate the our database and it return an integer value.
//delete an item from our database/table
public int deleteGRocery(int id){
SQLiteDatabase db=this.getWritableDatabase();
int result=db.delete( Costants.TABLE_NAME,Costants.KEY_ID +" =?",new String[]{String.valueOf( id )} );
return result;
}

The final method called countGrocery() which will return an integer value which is the total number of our
grocery items that found in our table/database. So, here first instantiate our database and then execute the
command and assign to new Cursor object. Then invoke getCount() method which returns the number of item
that have in our grocery table/database and it returns an integer value.
//get the total number of our items
public int coundGrocery(){
SQLiteDatabase db=this.getReadableDatabase();
String query="SELECT * FROM "+ Costants.TABLE_NAME;
Cursor cursor=db.rawQuery( query,null );
int totalItems=cursor.getCount();

return totalItems;
}

Then create a list activity which allow us to see all of the groceries items. Now, inside our content list layout
we’re going to add recycler view.
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerViewID"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0" />
So, we have content list which will hold all of the groceries items once they are being displayed. And while, So
to do that create a separate xml file and we’re going to call list_row that will be then inflated to create an actual
view.

Here, let’s add a card view to our Linear layout because it just a card
looking item that will hold data inside of our list view or in our case recycler view. And also we going to add
Relative layout inside card view. So, we can see the component tree as follows :

Here, inside our list row we have add text views for grocery name,
quantity and grocery added date and table raw for edit and delete icon
button.

Now, we have finished our DatabaseHandler


class then now we are ready to create
recycler view adapter packages. So, create RecyclerViewAdapter class and extends RecyclerView.Adapter<>
inside our UI package. Here the angle bracket what we are going to pass when we going to say
RecyclerVuewAdapter that ViewHolder.

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {


}
Here, our class RecyclerViewAdapter takes all the functionalities because it extends or inherit from Recycler view
adapter. So, there are classes and methods that waits us to work with from our recycler view and then we’re
going to pass RecyclerViewAdapter data view holder which is our RecyclerViewAdapter view holder constructor.
package com.course.mygroceryapps.UI;

...
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return null;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) { }
@Override
public int getItemCount() { return 0; }
public class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super( itemView );
}
}
}

Here, we have the skeleton of our recycler view adapter class which allow us to connect to our list row and data
grocery model. Now, create a context filed which allow us to pass the context of our adapter and grocery list
field. Then a constructor which have context and grocery list parameterize constructor and assign our fileds.
private Context context;
private List<Grocery> groceryList;

public RecyclerViewAdapter(Context context, List<Grocery> groceryList) {


this.context = context;
this.groceryList = groceryList;
}

Then, let’s implement on onCreate(), first create a view that inflated from a context which attached our list
layouts. So now our list row ready to be set and ready to pass our view as a view holder.
public ViewHolder onCreateViewHolder( ViewGroup parent, int viewType) {
View view= LayoutInflater.from( parent.getContext() )
.inflate( R.layout.list_row,parent,false );
return new ViewHolder( view );
}

Now, let’s go to getItemCount(), which will return the grocery items list.
@Override
public int getItemCount() {
return groceryList.size();
}

Then, let’s implement on our inner class called our ViewHolder class. So, first implements onClickLitsener
interface for allow us an action event. And create all instance fields which means all our text view and buttons.
Then we have passed a context on our constructor and setting up our widgets inside it. Then register our button
to action listener and use switch statement inside onClick() event method to implements different action events
like edit grocery item and delete grocery item. And also, when we click/tapped on the whole card view then it
triggers to next windows. Hence, we have set onClickListener on our view. The implementation of our view
seem like as follows:

public ViewHolder(View itemView,Context ctx) {


super( itemView );
context=ctx;
groceryItemName=(TextView)itemView.findViewById( R.id.groceryNameTxtId );
groceryQty=(TextView)itemView.findViewById( R.id.quantityTxtID );
addedDate=(TextView)itemView.findViewById( R.id.addedDateTxtID );
editgrocery=(Button)itemView.findViewById( R.id.editGroceryID );
deleteGrocery=(Button)itemView.findViewById( R.id.deletGroceryID );
editgrocery.setOnClickListener( this );
deleteGrocery.setOnClickListener( this );
itemView.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View view) {

} );

@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.editGroceryID:
break;
case R.id.deletGroceryID:
break;
}
}
}

Now, we’re going to implement onBindViewHolder() which is where everything is bind together because we
have view holder which has an actual view then bind it in this method. So, the first thing what we going to do is
create Grocery object and set the current position of object. Then set text to each view at a certain position.
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Grocery grocery=groceryList.get( position );
holder.groceryItemName.setText( grocery.getName() );
holder.groceryQty.setText( grocery.getQuantity() );
holder.addedDate.setText( grocery.getAddDate() );
}

Now,we have an recycler view adapter, so let’s adding grocery item to our database/table. Since, we’re go back
to main activity and then instantiate our Database handler class which means we can use it everywhere we want.
...
private DatabaseHandeler db;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
db=new DatabaseHandeler( this );

}

Then, implement inside the action events which means the event when we tapped/clicked on save button. So,
first create a method called saveGroceryToDB() which to get data from our views which means getting the data
from enter grocery and quantity Edit text fields and invoke it from onclick event method.
saveButton.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View view) {
if (!groceryItem.getText().toString().equals( "" ) && !quantity.getText().toString().equals( "" ))
saveGroceryToDB( view );
}
} );

To implement our saveGroceryToDB() method, first create Grocery object then create a string variables that will
hold get grocery item name and quantity from our view then set our grocery objects which holds grocery name
and quantity. Then, save/stored into our database/tables because our grocery object holds a data that we need to
be stored or inserted into database/table.
public void saveGroceryToDB(View view){
Grocery grocery=new Grocery( );
String itemName=groceryItem.getText().toString();
String amount=quantity.getText().toString();
grocery.setName( itemName );
grocery.setQuantity( amount );
//save to database
db.addGrocery( grocery );
Snackbar.make( view,"Grocery Item stored into table",Snackbar.LENGTH_LONG ).show();
}

Now, we’re going to do once the item is added then show the groceries item in another windows which display
the item name,quantity and added date of grocery information. So, we start seeing the item they will been add a
little delay when the snack bar shows up and says grocery item adding... and waits some seconds and take the
users to the second screen. Hence, we’re going to use Handler class and use the method postDelay() and passing
Runnable object's and inside of there run an object will have run() method and we need add how long will delay
in millisecond. And then it have override methods called run() and inside this method first dismiss our dialog and
then start the new activity called ListActivity.
Snackbar.make( view,"Grocery Item adding...",Snackbar.LENGTH_LONG ).show();
new Handler( ).postDelayed( new Runnable() {
@Override
public void run() {
dialog.dismiss();
startActivity( new Intent( MainActivity.this,ListActivity.class ));
}
}, 1000 );

Now, we able to add an item to our database then next thing what we’re going to do is display an item on
recycler view that stored on our database. So, we go back our list activity class and implement on it which first
create RecyclerView, RecyclerViewAdapter and Grocery list and database handler instances. Then instantiate all
of our instance classes inside onCreate() method and make sure that all the items are fixed correctly say
recyclerView.setHasFixedSize( true ). Next, we’re going to get groceries items from database using our database
handler object and invoking to getAllGrocery() methods which returns all groceries items from database then
assign to our grociery list objects groceryList=db.getAllGrocery(). Since,our groceryLists holds all of our
groceries from our database so now we’re going to do put into our views/recycler views and used for loop to
iterate through our lists. Then we can instantiate our recycler view adapter and pass our context and our list items
that holds all groceries items and add our recycler view adapter to our recycler view.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_list );
...
recyclerView=(RecyclerView)findViewById( R.id.recyclerViewID );
recyclerView.setHasFixedSize( true );
recyclerView.setLayoutManager( new LinearLayoutManager( this ) );

db= new DatabaseHandeler( this );


groceryList=new ArrayList<>( );
listItem=new ArrayList<>( );

groceryList=db.getAllGrocery();
for (Grocery c: groceryList){
Grocery grocery=new Grocery( );
grocery.setId( c.getId() );
grocery.setName( c.getName() );
grocery.setQuantity( "Qty: "+ c.getQuantity() );
grocery.setAddDate(" Added on: "+ c.getAddDate() );

listItem.add( grocery );
}
recyclerViewAdapter=new RecyclerViewAdapter( this,listItem );
recyclerView.setAdapter( recyclerViewAdapter );
recyclerViewAdapter.notifyDataSetChanged();
}

Now, we’re going to make implementation when we tapped on groceries then go to the next activity which will
be the details activity. So, what going to do now create another new empty activity called DetialsActivity which
will display all the detail of grocery item that we taped/clicked on it. But when we go to detail activity we’re also
going to take a pass on the properties or the items of grocery object which able to get grocery name, quantity
and added date that will display on the screen. Hence, first we need to get the position of our item int

position=getAdapterPosition() Because all items in recycler view have its own positions which allows which items
was clicked/tapped. Since, create Grocery objects which holds the grocery item. Then create an intent which
navigate from current activity to Details Activity and attached id, name, quantity and added date for an item
attributes. Then start an activity because we are not inside an activity when we implementes inside
RecyclerViewAdapter class. So, we can get start activity method through our context and pass our intent.
view.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View view) {
int position=getAdapterPosition();
Grocery grocery=groceryList.get( position );
Intent intent=new Intent( context, DetailsActivity.class );
intent.putExtra( "id",grocery.getId() );
intent.putExtra( "name",grocery.getName() );
intent.putExtra( "quantity",grocery.getQuantity() );
intent.putExtra( "addDate",grocery.getAddDate() );
context.startActivity( intent );
}
} );

Now,when we clicke/tapped anywhere we’re going to be taken to our DetailsActivity. So let’s start putt the user
interface on DetailsActivity so here add card view and inside it add relative layout then where we can put item
name, quantity, added date and an icons for edit and delete operations.

Now, we’re going to populated our details


activity form our list activity so go back to
DetailActivity class and then create fields or instance variable for our view/text view. Then we need to get all
information that sent from recycler views. So, first create a Bundle object to retrieve all extra information which
sent from other activity.
protected void onCreate(Bundle savedInstanceState) {
...
itemName=(TextView)findViewById( R.id.itemNameDetId );
qunatity=(TextView)findViewById( R.id.qunatityDetId );
addedDate=(TextView)findViewById( R.id.addedDateDetId );

bundle=getIntent().getExtras();
if (bundle!=null) {
itemName.setText( bundle.getString( "name" ) );
qunatity.setText( bundle.getString( "quantity" ) );
addedDate.setText( bundle.getString( "addedDate" ) );
groceryId = bundle.getInt( "id" );
}

}
Now, we are able to go from one activity to another activity called detail activity. So, next we’re going to do
directly got to our recycler view when we have a grocery item in our database. So, create byPassActivity()
method and inside it start an activity and pass our intent directly goes to list activity and then invoke finish()
method which that when we can not back to main activity through back button.
protected void onCreate(Bundle savedInstanceState) {

...
byPassActivity(); }
public void byPassActivity(){
if (db.coundGrocery()>0){
startActivity( new Intent( MainActivity.this,ListActivity.class ) );
finish(); }
}

Edit and delete a grocery operations.

You might also like