unit 5
unit 5
UNIT-5
Events Database and Connectivity
5.1 Handling UI Events
Events are the actions performed by the user to interact with the application, e.g. pressing a button or
touching the screen. The events are managed by the Android framework in the FIFO manner i.e. First In –
First Out. Handling such actions or events by performing the desired task is called Event Handling. Android
provides a huge set of 2D-drawing APIs that allow you to create graphics.
Overview of the input event management
Event Listeners: It is an interface in the View class. It contains a single callback method. Once the
view to which the listener is associated is triggered due to user interaction, the callback methods are
called.
Event Handlers: It is responsible for dealing with the event that the event listeners registered for
and performing the desired action for that respective event.
Event Listeners Registration: Event Registration is the process in which an Event Handler gets
associated with an Event Listener so that this handler is called when the respective Event Listener
fires the event.
Touch Mode: When using an app with physical keys it becomes necessary to give focus to buttons
on which the user wants to act but if the device is touch-enabled and the user interacts with the
interface by touching it, then it is no longer necessary to highlight items or give focus to particular
View. In such cases, the device enters touch mode and in such scenarios, only those views for which
the isFocusableInTouchMode() is true will be focusable, e.g. plain text widget.
For, if a button is pressed then this action or event gets registered by the event listener and then the task to
be performed by that button press is handled by the event handler, it can be anything like changing the color
of the text on a button press or changing the text itself, etc.
Event Listeners and their respective event handlers
1. OnClickListener(): This method is called when the user clicks, touches, or focuses on any view
(widget) like Button, ImageButton, Image, etc. The event handler used for this is onClick().
2. OnLongClickListener(): This method is called when the user presses and holds a particular widget
for one or more seconds. The event handler used for this is onLongClick().
3. OnMenuItemClickListener(): This method is called when the user selects a menu item. The event
handler used for this is onMenuItemClick().
4. OnMenuItemClickListener(): This method is called when the user selects a menu item. The event
handler used for this is onMenuItemClick().
There are various other event listeners available which can be used for different requirements and can be found
in the official documentation.
Mobile Computing and App Development
Example:
Step1: Create a New Project in Android Studio
Step2: Working with the activity_main.xml file
<?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"
tools:context=".MainActivity">
<ImageView
android:id="@+id/image_view_1"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="ContentDescription"
android:background="@color/black"/>
</RelativeLayout>
Step3: Working with the MainActivity.kt file
package com.latihan.darmanto.radiobutton
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.RadioButton
import android.widget.TextView
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
fun onRadioButtonClicked(view: View) {
var textView: TextView = findViewById(R.id.textView)
Mobile Computing and App Development
if (view is RadioButton) {
// Is the button now checked?
val checked = view.isChecked
// Check which radio button was clicked
when (view.getId()) {
R.id.radio_pirates ->
if (checked) {
// Pirates are the best
textView.setText("Pirates")
}
R.id.radio_ninjas ->
if (checked) {
// Ninjas rule
textView.setText("Ninjas")
}
}
}
}
}
<!--Creating a ListView-->
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="#000000"
android:dividerHeight="3dp"
android:padding="5dp" />
Mobile Computing and App Development
</RelativeLayout>
Create another XML file (named list_row_items) and create UI for each row of the ListView:
Below is the code for the list_row_items.xml file.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--Creating a ImageView-->
<ImageView
android:id="@+id/imageView"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_margin="10dp"
android:scaleType="fitCenter"
android:src="@drawable/ic_launcher_background" />
<!--Creating a TextView-->
<TextView
android:id="@+id/textView"
Mobile Computing and App Development
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:layout_marginRight="20dp"
android:layout_toRightOf="@+id/imageView"
android:gravity="center"
android:padding="5dp"
android:text="Text View"
android:textColor="#808080"
android:textSize="40sp"
android:textStyle="bold|italic" />
</RelativeLayout>
filesystem. getCacheDir() returns the absolute path to the filesystem’s application-specific cache
directory.
When Should Internal Storage Be Used?
The internal storage can be used when you need some confidential data for your application. Another
thing to keep in mind is that if your app is storing data that may be utilized by other apps, you should
avoid using internal storage since when you remove the app, all of your data will be gone, and other
apps will never have access to that data. For instance, if your app is downloading a PDF or storing an
image or video that might be used by other apps, you shouldn’t use internal storage.
2. External Hard Drives: Most Android devices have relatively low internal storage. As a result, we
keep our data on an external storage device. These storage units are accessible to everyone, which
means they can be accessed by all of your device’s applications. You can also access the storage by
connecting your mobile device to a computer. You must obtain the READ EXTERNAL STORAGE
permission from the user to gain access to the external storage. As a result, any application with this
permission has access to your app’s data.
When is it appropriate to use external storage?
You can use external storage if the data that your application stores can be used by other
applications. Additionally, if the file stored by your application is huge, such as a video, you can save
it to external storage. You can use external storage to keep the data even after uninstalling the
application.
3. Using the Shared Preferences: You can use the shared preferences if you only have a small amount
of data to keep and don’t want to use the internal storage. Shared Preferences are used to store data in
a key-value format, which means you’ll have one key and the associated data or value will be stored
depending on that key. The data saved in the shared preferences will remain with the application until
you delete it from your phone. All shared preferences will be deleted from the device if you uninstall
the application.
When Should Shared Preferences Be Used?
You can utilize the shared preference in your application when the data you want to store is relatively
little. It’s not a good idea to save more than 100 kilobytes of data in shared preferences. In addition,
if you wish to keep tiny and private data, you can use Android’s shared preferences.
4. Using Android Database: Databases are collections of data that are organized and saved for future
use. Using a Database Management System, you can store any type of data in your database. All you
have to do is establish the database and use one query to perform all of the operations, such as
insertion, deletion, and searching. The query will be passed to the database, which will return the
desired output. In Android, an SQLite database is an example of a database.
When Should you utilize a database?
Mobile Computing and App Development
A database is useful when you need to keep track of structured data. A database can hold any type of
information. So, if your data is large and you want to retrieve it quickly, you can use a database and
store it in a structured style.
5.4 Using Internal and External Storage
External Storage: Android External Storage is the memory space in which we perform read and write
operations. Files in the external storage are stored in /sd card or /storage folder etc. The files that are saved in
the external storage are readable and can be modified by the user.
Before accessing the file in external storage in our application, we should check the availability of the external
storage in our device.
Example: In this example, we will write the data to a file inside the external storage and read the same file
content from the same external storage.
Step1: Create activity_main.xml
<?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"
tools:context="example.javatpoint.com.kotlinexternalstoragereadwrite.MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/textView2"
android:layout_alignParentTop="true"
android:layout_alignStart="@+id/textView2"
android:layout_marginTop="68dp"
android:text="File Name"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Medium"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.027"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.065" />
Mobile Computing and App Development
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/editTextData"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginBottom="36dp"
android:layout_marginLeft="50dp"
android:layout_marginStart="50dp"
android:text="File Data"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Medium"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.027"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:layout_constraintVertical_bias="0.167" />
<EditText
android:id="@+id/editTextFile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/editTextData"
android:layout_alignStart="@+id/editTextData"
android:layout_alignTop="@+id/textView"
android:ems="10"
android:inputType="none" />
<EditText
android:id="@+id/editTextData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
Mobile Computing and App Development
android:layout_below="@+id/editTextFile"
android:layout_marginEnd="37dp"
android:layout_marginRight="37dp"
android:layout_marginTop="30dp"
android:ems="10"
android:inputType="none"
android:lines="5" />
<Button
android:id="@+id/button_save"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="68dp"
android:layout_toLeftOf="@+id/editTextData"
android:layout_toStartOf="@+id/editTextData"
android:text="Save" />
<Button
android:id="@+id/button_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/button_save"
android:layout_alignEnd="@+id/editTextData"
android:layout_alignRight="@+id/editTextData"
android:layout_marginEnd="43dp"
android:layout_marginRight="43dp"
android:text="View" />
</RelativeLayout>
Step2: Create MainActivity.kt
package example.javatpoint.com.kotlinexternalstoragereadwrite
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.view.View
Mobile Computing and App Development
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import android.os.Environment
import java.io.*
saveButton.setOnClickListener(View.OnClickListener {
myExternalFile = File(getExternalFilesDir(filepath), fileName.text.toString())
Mobile Computing and App Development
try {
val fileOutPutStream = FileOutputStream(myExternalFile)
fileOutPutStream.write(fileData.text.toString().toByteArray())
fileOutPutStream.close()
} catch (e: IOException) {
e.printStackTrace()
}
Toast.makeText(applicationContext,"data save",Toast.LENGTH_SHORT).show()
})
viewButton.setOnClickListener(View.OnClickListener {
myExternalFile = File(getExternalFilesDir(filepath), fileName.text.toString())
if (!isExternalStorageAvailable || isExternalStorageReadOnly) {
saveButton.isEnabled = false
}
}
}
Step3: Create AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
Mobile Computing and App Development
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="example.javatpoint.com.kotlinexternalstoragereadwrite">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<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" />
</manifest>
OutPut:
Mobile Computing and App Development
SQLite is another data storage available in Android where we can store data in the user’s device and can use
it any time when required.
What is SQLite Database?
SQLite Database is an open-source database provided in Android which is used to store data inside the user’s
device in the form of a Text file. We can perform so many operations on this data such as adding new data,
updating, reading, and deleting this data. SQLite is an offline database that is locally stored in the user’s device
and we do not have to create any connection to connect to this database.
How Data is Being Stored in the SQLite Database?
Data is stored in the SQLite database in the form of tables. When we stored this data in our SQLite database
it is arranged in the form of tables that are similar to that of an excel sheet. Below is the representation of our
SQLite database which we are storing in our SQLite database.
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_margin="20sp"
android:text="Age\n\n"
android:textSize="22sp"
android:padding="10sp"
android:textColor="#000000"/>
</LinearLayout>
</LinearLayout>
Step4: Creating a new class for SQLite operations
package com.release.database
import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_main.*
}
}
Content providers let you centralize content in one place and have many different applications access it as
needed. A content provider behaves very much like a database where you can query it, edit its content, as
well as add or delete content using insert(), update(), delete(), and query() methods. In most cases this data is
stored in an SQLite database.
A content provider is implemented as a subclass of the ContentProvider class and must implement a standard
set of APIs that enable other applications to perform transactions
Create Content Provider
This involves several simple steps to create your content provider.
First of all you need to create a Content Provider class that extends the ContentProviderbaseclass.
Second, you need to define your content provider URI address which will be used to access the
content.
Next you will need to create your database to keep the content. Usually, Android uses SQLite
database and the framework needs to override the onCreate() method which will use the SQLite
Open Helper method to create or open the provider's database. When your application is launched,
the onCreate() handler of each of its Content Providers is called on the main application thread.
Next you will have to implement Content Provider queries to perform different database-specific
operations.
Mobile Computing and App Development
Finally register your Content Provider in your activity file using <provider> tag.
Here is the list of methods that you need to override in the Content Provider class to have your Content
Provider working –
ContentProvider
onCreate() This method is called when the provider is started.
query() This method receives a request from a client. The result is returned as a Cursor object.
insert()This method inserts a new record into the content provider.
delete() This method deletes an existing record from the content provider.
update() This method updates an existing record from the content provider.
getType() This method returns the MIME type of the data at the given URI.
}
}
JSON array: The [ (square bracket) represents the JSON array.
["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
Let's take another example of a JSON array.
{ "Employee" :
[
{"id":"101","name":"Sonoo Jaiswal","salary":"50000"},
{"id":"102","name":"Vimal Jaiswal","salary":"60000"}
]
}
Example:
Step 1: Create a JSON file index.html.
{"info":[
{"name":"Ajay","id":"111","email":"ajay@gmail.com"},
{"name":"John","id":"112","email":"john@gmail.com"},
{"name":"Rahul","id":"113","email":"rahul@gmail.com"},
{"name":"Maich","id":"114","email":"maich@gmail.com"},
{"name":"Vikash","id":"115","email":"vikash@gmail.com"},
{"name":"Mayank","id":"116","email":"mayank@gmail.com"},
{"name":"Prem","id":"117","email":"prem@gmail.com"},
{"name":"Chandan","id":"118","email":"chandan@gmail.com"},
{"name":"Soham","id":"119","email":"soham@gmail.com"},
{"name":"Mukesh","id":"120","email":"mukesh@gmail.com"},
{"name":"Ajad","id":"121","email":"ajad@gmail.com"}
]
}
Step2: Add the ListView in the activity_main.xml layout file.
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="example.javatpoint.com.kotlinjsonparsing.MainActivity">
Mobile Computing and App Development
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</android.support.constraint.ConstraintLayout>
Step 3: Add the following okhttp dependency in the build.gradle file.
compile 'com.squareup.okhttp3:okhttp:3.8.1'
Step 4: Create a data model class Model.kt which includes the information String "id", String
"name", and String "email".
package example.javatpoint.com.kotlinjsonparsing
constructor(id: String,name:String,email:String) {
this.id = id
this.name = name
this.email = email
}
constructor()
}
Step 5: Create an adapter_layout.xml file in the layout directory which contains the row items
for ListView.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
Mobile Computing and App Development
android:id="@+id/linearLayout"
android:padding="5dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tvId"
android:layout_margin="5dp"
android:textSize="16dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tvName"
android:textSize="16dp"
android:layout_margin="5dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tvEmail"
android:layout_margin="5dp"
android:textSize="16dp"/>
</LinearLayout>
Step 6: Create a custom adapter class CustomAdapter.kt and extend BaseAdapter to handle the
custom ListView.
package example.javatpoint.com.kotlinjsonparsing
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.LinearLayout
Mobile Computing and App Development
import android.widget.TextView
init {
this.tvId = row?.findViewById<TextView>(R.id.tvId) as TextView
this.tvName = row?.findViewById<TextView>(R.id.tvName) as TextView
this.tvEmail = row?.findViewById<TextView>(R.id.tvEmail) as TextView
this.linearLayout = row?.findViewById<LinearLayout>(R.id.linearLayout) as LinearLayout
}
}
Step 7: Add the following code in the MainActivity.kt class file. This class reads the JSON data
in the form of a JSON object. Using the JSON object, we read the JSON array data. The JSON
data are bound in ArrayList.
package example.javatpoint.com.kotlinjsonparsing
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.ListView
import android.widget.ProgressBar
import okhttp3.*
import org.json.JSONArray
import org.json.JSONObject
import java.io.IOException
import kotlin.collections.ArrayList
arrayList_details.add(model)
}
runOnUiThread {
//stuff that updates ui
val obj_adapter : CustomAdapter
obj_adapter = CustomAdapter(applicationContext,arrayList_details)
listView_details.adapter=obj_adapter
}
progress.visibility = View.GONE
}
})
}
}
Step 8: Add the Internet permission in the AndroidManifest.xml file.
<uses-permission android:name="android.permission.INTERNET"/>
Output:
Within a repository class, functions can encapsulate network operations and expose their results. This
encapsulation ensures that the components that call the repository don't need to know how the data is stored.
Mobile Computing and App Development
Any future changes to how the data is stored are isolated to the repository class as well. For example, you
might have a remote change such as an update to API endpoints, or you might want to implement local
caching.
Kotlin
class UserRepository constructor(
private val userService: UserService
){
suspend fun getUserById(id: String): User {
return userService.getUser(id)
}
}
To avoid creating an unresponsive UI, don't perform network operations on the main thread. By default,
Android requires you to perform network operations on a thread other than the main UI thread. If you try to
perform network operations on the main thread, a NetworkOnMainThreadException is thrown.
In the previous code example, the network operation isn't actually triggered. The caller of
the UserRepository must implement the threading either using coroutines or using the enqueue() function.
Survive configuration changes
When a configuration change occurs, such as a screen rotation, your fragment or activity is destroyed and
recreated. Any data not saved in the instance state for your fragment activity, which can only hold small
amounts of data, is lost. If this occurs, you might need to make your network requests again.
You can use a ViewModel to let your data survive configuration changes. The ViewModel component is
designed to store and manage UI-related data in a lifecycle-conscious way. Using the
preceding UserRepository, the ViewModel can make the necessary network requests and provide the result
to your fragment or activity using LiveData:
Kotlin
class MainViewModel constructor(
savedStateHandle: SavedStateHandle,
userRepository: UserRepository
) : ViewModel() {
private val userId: String = savedStateHandle["uid"] ?:
throw IllegalArgumentException("Missing user ID")
init {
Mobile Computing and App Development
viewModelScope.launch {
try {
// Calling the repository is safe as it moves execution off
// the main thread
val user = userRepository.getUserById(userId)
_user.value = user
} catch (error: Exception) {
// Show error message to user
}
}
}
}