0% found this document useful (0 votes)
7 views

Lecture3-HTTP API calls - UI component navigation - sqlite persistence

The document covers the implementation of HTTP API calls using Retrofit, including the setup of a MovieService interface for various RESTful operations. It also discusses Jetpack Compose navigation components, including creating a navigation drawer and handling navigation events in an Android application. Additionally, it outlines local persistence options such as SQLite, providing examples for database creation, querying, and manipulating data.

Uploaded by

airmetrix
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views

Lecture3-HTTP API calls - UI component navigation - sqlite persistence

The document covers the implementation of HTTP API calls using Retrofit, including the setup of a MovieService interface for various RESTful operations. It also discusses Jetpack Compose navigation components, including creating a navigation drawer and handling navigation events in an Android application. Additionally, it outlines local persistence options such as SQLite, providing examples for database creation, querying, and manipulating data.

Uploaded by

airmetrix
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 29

Course 3 – HTTP API calls.

Jetpack Compose navigation.


Local persistence
REST using Retrofit

h t t p s: / / sq u ar e. g i t h u b . i o / r et r o f i t /
REST using Retrofit

implementation "com.squareup.retrofit2:retrofit:version"
implementation "com.squareup.retrofit2:adapter-rxjava2:version"
implementation "com.squareup.retrofit2:converter-gson:version"

implementation “io.reactivex.rxjava2:rxandroid:version"

h t t p s: / / sq u ar e. g i t h u b . i o / r et r o f i t /
interface MovieService {
REST using Retrofit
@GET("movies")
val movies: Observable<List<Movie>>
@POST("update")
@GET("genres") fun update(@Body movie: Movie): Observable<Movie>
val genres: Observable<List<String>>
@DELETE("delete/{id}")
@GET("moviesByGenre/{genre}") fun delete(@Path("id") id: Int): Observable<ResponseBody>
fun moviesByGenre(@Path("genre") genre: String)
: Observable<List<Movie>> @POST("add")
fun add(@Body movie: Movie): Observable<Movie>
@GET("details/{id}")
fun details(@Path("id") id: Int): Observable<Movie> companion object {
const val SERVICE_ENDPOINT = “http://SERVER_IP:2022”
@POST("updateDescription") }
fun updateDescription(@Body movie: Movie): Observable<Movie> }

@POST("updateRating")
fun updateRating(@Body movie: Movie): Observable<Movie>

h t t p s: / / sq u ar e. g i t h u b . i o / r et r o f i t /
Navigation
Key concepts

h t t p s : / / d e ve l o p e r. a n d r o i d . c o m / g u i d e / n a vi g a t i o n
Navigation
Navigation Components:

• A collection of libraries
• A plugin
• Tooling
Navigation
• Navigation Graph
• NavHostFragment
• NavController
Navigation

h t t p s : / / d e ve l o p e r. a n d r o i d . c o m / g u i d e / n a vi g a t i o n
Navigation Drawer

• App main navigation menu.

• Hidden when not in use.

• Appears:

• with a left swipe from the screen edge

• when the user touches the drawer icon in the


app bar

h t t p s: / / d e ve l o p e r. an d r o i d . c o m / t r a i n i n g / i m p l e m en t i n g - n a v i g a t i o n / n a v - d r a w e r
Create a navigation drawer views
activity project
Generated Artifacts (xml)

• Sources
• Layouts
• Menus
• Navigation
Dependencies
buildscript {
ext.nav_version = “2.5.3”
}

dependencies {
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
}
Add a drawer to a layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout
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:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="@layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>
Declare the menu items
<android.support.design.widget.NavigationView
android:id=“@+id/nav_view”
android:layout_width=“wrap_content”
android:layout_height=“match_parent”
android:layout_grvity=“start”
android:IfitsSystemWindows=“true”
app:menu=“@menu/activity_main_drawer” />

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


<menu xmlns:android=http://schema.android.com/apk/res/android >
<group android:checkableBehavior=“single”>
<item
android:id="@+id/nav_camera"
android:icon="@drawable/ic_menu_camera"
android:title="@string/import" />
<item
android:id="@+id/nav_gallery"
android:icon="@drawable/ic_menu_gallery"
android:title="@string/gallery" />
<item
android:id="@+id/nav_slideshow"
android:icon="@drawable/ic_menu_slideshow"
android:title="@string/slideshow" />
...
</group>
</menu>
Add a header to the
nav drawer
<android.support.design.widget.NavigationView
android:id=“@+id/nav_view”
android:layout_width=“wrap_content”
android:layout_height=“match_parent”
android:layout_grvity=“start”
android:IfitsSystemWindows=“true”
app:menu=“@menu/activity_main_drawer”
app:headerLayout=“@layout/nav_header_main”/>

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


<LinearLayout xmlns:android=http://schema.android.com/apk/res/android >
android:layout_width=“match_parent”
android:layout_height=“192dp”
android:background="?attr/colorPrimaryDark"
android:padding="16dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark"
android:orientation="vertical"
android:gravity="bottom">

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="My header title"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"/>
</LinearLayout>
Handle navigation events
class MainActivity : AppCompatActivity() {

private lateinit var appBarConfiguration: AppBarConfiguration

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)

val navController = findNavController(R.id.nav_host_fragment)

appBarConfiguration = AppBarConfiguration(
setOf(
R.id.nav_home,
R.id.nav_gallery
), drawer_layout
)
setupActionBarWithNavController(navController, appBarConfiguration)
nav_view.setupWithNavController(navController)
}
}
Local Persistence Options
• Internal storage

• Internal cache files

• External storage

• Shared preferences

• Databases

h t t p s : / / d e ve l o p e r. a n d r o i d . c o m / g u i d e / t o p i c s / d a t a /
Options
•On device:
•SQLite
•Realm
•Room
•SQLDelight
•ObjectBox
•On cloud:
•Firebase Realtime Database
•Firebase Firestore
•Couchbase Lite
SQLite
Define a schema and a contract

object FeedReaderContract {
// Table contents are grouped
// together in an anonymous object.
object FeedEntry : BaseColumns {
const val TABLE_NAME = "entry"
const val COLUMN_NAME_TITLE = "title"
const val COLUMN_NAME_SUBTITLE = "subtitle"
}
}

h t t p s : / / d e ve l o p e r. a n d r o i d . c o m / t r a i n i n g / d a t a - s t o r a g e / s q l i t e
SQLite Helper
Create a database using an SQL helper

private const val SQL_CREATE_ENTRIES = """


CREATE TABLE ${FeedEntry.TABLE_NAME} (
${BaseColumns._ID} INTEGER PRIMARY KEY,
${FeedEntry.COLUMN_NAME_TITLE} TEXT,
${FeedEntry.COLUMN_NAME_SUBTITLE} TEXT)
"""

private const val SQL_DELETE_ENTRIES =


"DROP TABLE IF EXISTS ${FeedEntry.TABLE_NAME}"
SQLite
class FeedReaderDbHelper(context: Context) :
SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {

override fun onCreate(db: SQLiteDatabase) {


db.execSQL(SQL_CREATE_ENTRIES)
}

override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {


// This database is only a cache for online data, so its upgrade policy is
// to simply to discard the data and start over
db.execSQL(SQL_DELETE_ENTRIES)
onCreate(db)
}

override fun onDowngrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {


onUpgrade(db, oldVersion, newVersion)
}

companion object {
// If you change the database schema, you must increment the database version.
const val DATABASE_VERSION = 1
const val DATABASE_NAME = "FeedReader.db"
}
}
SQLite - Insert
// Gets the data repository in write mode
val db = dbHelper.writableDatabase
// Create a new map of values, where column names are the keys
val values = ContentValues().apply {
put(FeedEntry.COLUMN_NAME_SUBTITLE, subtitle)
}
// Insert the new row, returning the primary key value of the new row
val newRowId = db?.insert(FeedEntry.TABLE_NAME, null, values)
SQLite - Query
val dbHelper = FeedReaderDbHelper(context)
val db = dbHelper.readableDatabase
// Define a projection that specifies which columns from the database
// you will actually use after this query.
val projection = arrayOf(
BaseColumns._ID,
FeedEntry.COLUMN_NAME_TITLE,
FeedEntry.COLUMN_NAME_SUBTITLE)
// Filter results WHERE "title" = 'My Title'
val selection = "${FeedEntry.COLUMN_NAME_TITLE} = ?"
val selectionArgs = arrayOf("My Title")
// How you want the results sorted in the resulting Cursor
val sortOrder = "${FeedEntry.COLUMN_NAME_SUBTITLE} DESC"
val cursor = db.query(
SQLite - Query
val dbHelper = FeedReaderDbHelper(context)
val db = dbHelper.readableDatabase
val projection = arrayOf(...)
val selection = "${FeedEntry.COLUMN_NAME_TITLE} = ?"
val selectionArgs = arrayOf("My Title")
val sortOrder = "${FeedEntry.COLUMN_NAME_SUBTITLE} DESC"
val cursor = db.query(...)
val itemIds = mutableListOf<Long>()
with(cursor) {
while (moveToNext()) {
val itemId = getLong(getColumnIndexOrThrow(BaseColumns._ID))
itemIds.add(itemId)
}
}
SQLite - Delete
val dbHelper = FeedReaderDbHelper(context)
val db = dbHelper.writableDatabase
// Define 'where' part of query.
val selection = "${FeedEntry.COLUMN_NAME_TITLE} LIKE ?"
// Specify arguments in placeholder order.
val selectionArgs = arrayOf("MyTitle")
// Issue SQL statement.
val deletedRows = db.delete(FeedEntry.TABLE_NAME, selection, selectionArgs)
SQLite - Update
val dbHelper = FeedReaderDbHelper(context)
val db = dbHelper.writableDatabase
// New value for one column
val title = "MyNewTitle"
val values = ContentValues().apply {
put(FeedEntry.COLUMN_NAME_TITLE, title)
}
// Which row to update, based on the title
val selection = "${FeedEntry.COLUMN_NAME_TITLE} LIKE ?"
val selectionArgs = arrayOf("MyOldTitle")
val count = db.update(
FeedEntry.TABLE_NAME,
values,
)

You might also like