UNIT 1: INTRODUCTION TO ANDROID PROGRAMMING
1.1 What is Android?
● Definition: Android is an open-source, Linux-based operating system primarily designed
for touchscreen mobile devices such as smartphones and tablets.
● Developer: Developed by the Open Handset Alliance (OHA), led by Google.
● Platform: It's a complete software stack including an operating system, middleware, and
key applications.
● Key Features:
○ Open Source: Allows modification and customization (Android Open Source
Project - AOSP).
○ Large App Ecosystem: Google Play Store.
○ Hardware Flexibility: Runs on diverse hardware.
○ Rich Development Environment: Powerful SDK for app building.
○ Connectivity: Supports various network standards (GSM, Wi-Fi, LTE, 5G, NFC,
etc.).
1.2 History and Versions
● Origins: Android Inc. (2003), acquired by Google (2005).
● First Commercial Version: Android 1.0 (September 2008).
● Version Naming (Examples): Cupcake (1.5), Donut (1.6), Eclair (2.0/2.1), Froyo (2.2),
Gingerbread (2.3), Honeycomb (3.x - Tablet), Ice Cream Sandwich (4.0 - Unified), Jelly
Bean (4.1-4.3), KitKat (4.4), Lollipop (5.x - Material Design), Marshmallow (6.0 - Runtime
Permissions), Nougat (7.x - Multi-window), Oreo (8.x - Notification Channels), Pie (9.0 -
Gestures), Android 10 (Dark Theme), Android 11 (Privacy), Android 12/12L (Material
You), Android 13 (Themed Icons), Android 14 (Performance/Privacy focus).
1.3 Android Architecture
(Layered Stack Description)
● Applications Layer:
○ Top layer: Native apps (Phone, Contacts) & third-party apps.
○ Built using Android framework APIs.
● Application Framework Layer:
○ High-level Java services for apps.
○ Includes: Activity Manager, Content Providers, Resource Manager, Notification
Manager, View System, Location Manager, etc.
● Libraries and Android Runtime Layer:
○ Native Libraries (C/C++): Core libraries (SQLite, WebKit, OpenGL ES, Media
Framework).
○ Android Runtime (ART): Executes app code (replaces Dalvik). Uses AOT/JIT
compilation. Manages memory (garbage collection).
● Hardware Abstraction Layer (HAL):
○ Standard interface between framework and hardware drivers (e.g., Camera HAL,
Bluetooth HAL). Enables hardware agnosticism.
● Linux Kernel Layer:
○ Foundation: Core system services (Process/Memory/Device Management,
Security, Networking).
1.4 Basic Building Blocks (Application Components)
1. Activities: Single screen with UI; managed in an Activity stack.
2. Services: Background processes for long tasks; no UI. (e.g., music playback, data
sync).
3. Broadcast Receivers: Respond to system-wide events (e.g., battery low, SMS
received).
4. Content Providers: Manage shared data; provide access via URIs (e.g., Contacts).
5. Intents: Messaging objects for inter-component communication (start Activity/Service,
deliver Broadcast).
1.5 Android API Levels
● Definition: Integer identifier for each platform version, indicating available APIs.
● Purpose: Manage application compatibility.
● Key Manifest Attributes:
○ minSdkVersion: Minimum API level required to run.
○ targetSdkVersion: API level the app is designed/tested against (influences
behavior). Keep updated.
○ compileSdkVersion: API level used for compilation (usually latest stable).
● Example: Android 13 = API 33. minSdkVersion="21" runs on API 21+.
targetSdkVersion="33" targets Android 13 features.
1.6 Application Structure (Project Structure in Android Studio)
● app (Module Root):
○ manifests:
■ AndroidManifest.xml: Core config (components, permissions, API levels).
○ java (or kotlin):
■ Source code (.java/.kt files), organized by package. Includes test folders.
○ res (Resources): Non-code assets.
■ drawable: Images (bitmaps, XML drawables).
■ layout: UI structure XML files.
■ menu: Menu definition XML files.
■ mipmap: Launcher icons (density-specific).
■ values: XML files for simple values (strings.xml, colors.xml, dimens.xml,
styles.xml).
■ xml: Arbitrary XML files.
■ raw: Arbitrary raw files.
■ font: Font files.
■ anim, animator: Animation XML files.
○ build.gradle (Module Level): Module-specific build script (dependencies, SDK
versions, app ID).
● Gradle Scripts:
○ build.gradle (Project Level): Top-level build config.
○ settings.gradle: Included modules.
○ gradle.properties: Project-wide settings.
○ local.properties: Local environment settings (SDK path).
1.7 First Hello World Program (Conceptual Steps)
1. Setup: Install Android Studio, SDK, create New Project ("Empty Activity").
2. Layout (res/layout/activity_main.xml):
○ Defines UI. Modify the default TextView.
(Code Example - 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>
○
3. Activity (java/com.example.myapp/MainActivity.java):
○ Controls the screen. onCreate() is the entry point.
○ setContentView(R.layout.activity_main) links Java/Kotlin to XML layout.
(Code Example - Java):
package com.example.helloworld;
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);
}
}
4. Manifest (manifests/AndroidManifest.xml):
○ Declare MainActivity as the entry point (LAUNCHER).
(Code Example - XML Snippet):
<application ...>
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
5. Run: Build and execute on an emulator or device.
UNIT 2: ACTIVITY, INTENT AND LAYOUT
2.1 Introduction to Activity
● Core Concept: Represents a single screen with a UI.
● Stack Management: Managed in the "back stack". New activities push onto the stack;
Back button pops the current activity.
● Entry Point: One "main" activity is designated as the launcher.
2.2 Activity Life Cycle
(Callbacks controlling Activity states)
1. onCreate(Bundle savedInstanceState): First creation. Perform one-time initializations
(set layout, init variables, restore state).
2. onStart(): Activity becoming visible.
3. onResume(): Activity in foreground, interacting with user. Start animations, acquire
exclusive resources (camera).
4. onPause(): Activity partially obscured or leaving foreground. Release resources
(camera), save critical data (quickly!).
5. onStop(): Activity no longer visible. Release larger resources, perform heavier saving
operations.
6. onDestroy(): Final cleanup before destruction (due to finish() or system reclaiming
memory).
7. onRestart(): Called after onStop() just before onStart() when activity is coming back to
the foreground.
● State Saving:
○ onSaveInstanceState(Bundle outState): Called before onStop() when activity
might be killed (e.g., rotation). Save small amounts of UI state here.
○ onRestoreInstanceState(Bundle savedInstanceState): Called after onStart() if
state was saved. Restore UI state here (also possible in onCreate).
Importance: Prevents crashes, conserves resources, preserves user progress, handles
configuration changes (like rotation).
2.3 Introduction to Intent
● Definition: A messaging object describing an operation to perform.
● Purpose: Inter-component communication (start Activity/Service, deliver Broadcast).
● Key Information:
○ Component Name: Target component (Explicit Intent).
○ Action: Generic action (e.g., ACTION_VIEW, ACTION_SEND) (Implicit Intent).
○ Data: URI of data to act on (e.g., tel:, http:, content:).
○ Category: Additional info (e.g., CATEGORY_LAUNCHER).
○ Extras: Key-value data passed with the intent.
○ Flags: Modify launch behavior (e.g., FLAG_ACTIVITY_NEW_TASK).
2.4 Types of Intent
1. Explicit Intent:
○ Specifies target component by class name.
○ Used for communication within your own app.
(Code Example - Java):
// From MainActivity to SecondActivity
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.putExtra("USER_MESSAGE", "Data from Main");
startActivity(intent);
2. Implicit Intent:
○ Does not specify target component; uses Action, Data, Category.
○ Allows components from other apps to handle the request.
○ System matches intent to components' <intent-filter> declarations.
○ May show a chooser dialog if multiple apps match.
(Code Example - Java - Open Web Page):
Uri webpage = Uri.parse("https://www.google.com");
Intent intent = new Intent(Intent.ACTION_VIEW, webpage);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
} else {
Toast.makeText(this, "No browser found.", Toast.LENGTH_SHORT).show();
}
(Code Example - Java - Send Email):
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("message/rfc822"); // MIME type
intent.putExtra(Intent.EXTRA_EMAIL, new String[]{"
[email protected]"});
intent.putExtra(Intent.EXTRA_SUBJECT, "Email Subject");
intent.putExtra(Intent.EXTRA_TEXT, "Email body");
// Use Intent.createChooser for better user experience
startActivity(Intent.createChooser(intent, "Send mail..."));
2.5 Layout Manager
(Define UI structure; typically in res/layout/ XML files)
2.5.1 View and View Group
● View: Basic UI building block (widget); occupies rectangular area, handles drawing and
events (e.g., TextView, Button, ImageView).
● ViewGroup: Container for other Views; defines layout structure (e.g., LinearLayout,
RelativeLayout). Base class for layouts.
2.5.2 Linear Layout (LinearLayout)
● Arranges children in a single row (horizontal) or column (vertical).
● Key Attributes:
○ android:orientation: vertical or horizontal.
○ android:layout_weight (for children): Distributes extra space proportionally
(dimension should be 0dp).
○ android:gravity: Aligns content within the LinearLayout.
○ android:layout_gravity (for children): Aligns a single child within the LinearLayout.
(Code Example - XML - Vertical):
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Username:"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Login"/>
</LinearLayout>
2.5.3 Relative Layout (RelativeLayout)
● Arranges children relative to each other (android:layout_toLeftOf, android:layout_below,
etc.) or to the parent (android:layout_alignParentBottom, android:layout_centerInParent,
etc.).
● Flexible but can become complex. Often replaced by ConstraintLayout.
(Code Example - XML):
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<EditText
android:id="@+id/editTextName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Name"/>
<Button
android:id="@+id/buttonCancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/editTextName"
android:layout_alignParentLeft="true"
android:text="Cancel"/>
<Button
android:id="@+id/buttonOk"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@id/buttonCancel"
android:layout_alignParentRight="true"
android:text="OK"/>
</RelativeLayout>
2.5.4 Table Layout (TableLayout)
● Arranges children in rows and columns using TableRow elements.
● Column width determined by the widest cell in that column.
● Less flexible than GridLayout or ConstraintLayout.
● Use android:layout_span on a child within TableRow to span columns.
● Use android:stretchColumns on TableLayout to make columns fill available width.
(Code Example - XML):
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:stretchColumns="1"> <!-- Stretch second column (index 1) -->
<TableRow>
<TextView android:text="User ID:" />
<EditText android:id="@+id/userId" />
</TableRow>
<TableRow>
<TextView android:text="Password:" />
<EditText android:id="@+id/password" android:inputType="textPassword" />
</TableRow>
</TableLayout>
2.5.5 Grid Layout (GridLayout)
● Places children in a rectangular grid (API 14+).
● More flexible than TableLayout; allows row/column spanning (android:layout_rowSpan,
android:layout_columnSpan).
● Position children using android:layout_row and android:layout_column.
● Define grid size using android:rowCount, android:columnCount.
(Code Example - XML):
<GridLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnCount="2"
android:rowCount="2"
android:useDefaultMargins="true">
<TextView android:text="Cell 0,0" android:layout_row="0" android:layout_column="0"/>
<Button android:text="Cell 1,0" android:layout_row="0" android:layout_column="1"/>
<CheckBox android:text="Cell 0,1 Span 2" android:layout_row="1"
android:layout_column="0" android:layout_columnSpan="2"
android:layout_gravity="fill_horizontal"/>
</GridLayout>
2.5.6 Constraint Layout (ConstraintLayout)
● Most flexible and powerful layout; default in Android Studio. Part of androidx.
● Creates flat view hierarchies (better performance) by defining constraints between views
and parent.
● Uses visual editor and attributes like app:layout_constraintTop_toTopOf,
app:layout_constraintStart_toEndOf, etc. (values: parent or @id/other_view_id).
● Key Concepts: Constraints, Handles, Bias, Dimensions (0dp for match constraint),
Guidelines, Barriers, Chains.
(Code Example - XML):
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<EditText
android:id="@+id/editTextName"
android:layout_width="0dp" <!-- Match constraint -->
android:layout_height="wrap_content"
android:hint="Name"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<Button
android:id="@+id/buttonCancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cancel"
app:layout_constraintTop_toBottomOf="@id/editTextName"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginTop="10dp"/>
<Button
android:id="@+id/buttonOk"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="OK"
app:layout_constraintTop_toTopOf="@id/buttonCancel"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
2.5.7 Frame Layout (FrameLayout)
● Simplest layout; stacks children one on top of the other (last added is topmost).
● Good for holding a single child or overlapping views (e.g., progress indicator over
content).
● Use android:layout_gravity to position children within the frame.
(Code Example - XML - Overlapping Views):
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/background"
android:scaleType="centerCrop"/>
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone"/>
</FrameLayout>
2.5.8 Scroll Layout (ScrollView and HorizontalScrollView)
● Containers that make their single child scrollable if its content exceeds the container's
bounds.
● ScrollView: Vertical scrolling.
● HorizontalScrollView: Horizontal scrolling.
● The single child is usually another layout (LinearLayout, ConstraintLayout) holding the
actual content.
(Code Example - XML - Vertical Scroll):
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" <!-- Important -->
android:orientation="vertical">
<!-- Lots of content here that might exceed screen height -->
<TextView android:text="Very long text..."/>
<Button android:text="Button 1"/>
<!-- ... more views ... -->
</LinearLayout>
</ScrollView>
UNIT 3: BASIC UI DESIGN (Common Widgets)
3.1 Button Types
● Push Button (Button): Standard clickable text button. Use android:text, handle clicks
via OnClickListener or android:onClick.
(XML): <Button android:id="@+id/myButton" ... android:text="Click Me"/>
● Check Box (CheckBox): Select multiple options or toggle on/off. Use android:text,
android:checked. Listen with OnCheckedChangeListener.
(XML): <CheckBox android:id="@+id/myCheckBox" ... android:text="Enable Feature"/>
Radio Button (RadioButton): Select one option from a set. Must be inside a RadioGroup. Use
android:text, android:checked. Get selection from RadioGroup.
(XML):
<RadioGroup ...>
<RadioButton android:id="@+id/radio1" ... android:text="Option 1"/>
<RadioButton android:id="@+id/radio2" ... android:text="Option 2"/>
</RadioGroup>
● Toggle Button (ToggleButton): Two-state button (ON/OFF). Use android:textOn,
android:textOff, android:checked. Listen with OnCheckedChangeListener.
(XML): <ToggleButton android:id="@+id/myToggle" ... android:textOn="ON"
android:textOff="OFF"/>
● Image Button (ImageButton): Button displaying an image. Use android:src for image,
android:contentDescription for accessibility.
(XML): <ImageButton android:id="@+id/myImageButton" ...
android:src="@drawable/ic_play"/>
3.2 Text Fields (EditText)
● Allows user text input/editing. Subclass of TextView.
● Key Attributes: android:hint (placeholder), android:inputType (e.g., textPassword,
number, emailAddress), android:lines.
● Get/Set text via getText().toString() and setText().
(XML): <EditText android:id="@+id/myEditText" ... android:hint="Enter name"
android:inputType="textPersonName"/>
3.3 Spinner (Spinner)
● Dropdown list for single selection. Requires an Adapter (like ArrayAdapter) to provide
data.
Use OnItemSelectedListener to detect selection.
(XML): <Spinner android:id="@+id/mySpinner" ... />
(Java - Populate with String Array):
Spinner spinner = findViewById(R.id.mySpinner);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
R.array.planets_array, // Defined in strings.xml
android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(/* ... listener implementation ... */);
3.4 List View (ListView)
● Vertically scrollable list. Requires an Adapter to populate items. Efficient for long lists
(renders visible items). Modern alternative: RecyclerView.
Use OnItemClickListener for item clicks.
(XML): <ListView android:id="@+id/myListView" ... />
(Java - Populate with String Array):
ListView listView = findViewById(R.id.myListView);
String[] values = { "Item 1", "Item 2", "Item 3" };
ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
android.R.layout.simple_list_item_1, values);
listView.setAdapter(adapter);
listView.setOnItemClickListener(/* ... listener implementation ... */);
3.5 Toast (Toast)
● Short-lived popup message for simple feedback. Does not block UI.
(Java):
Toast.makeText(getApplicationContext(), "Operation Complete",
Toast.LENGTH_SHORT).show();
3.6 Scroll View (ScrollView)
● (See section 2.5.8) Container for vertical scrolling of a single child view.
3.6 ProgressBar View (ProgressBar) (Assuming corrected number)
● Indicates operation progress.
● Styles:
○ Determinate: Shows specific progress (e.g., horizontal bar). Update with
setProgress(). Use style="?android:attr/progressBarStyleHorizontal",
android:max, android:progress.
○ Indeterminate: Shows ongoing activity (e.g., spinning wheel). Default behavior.
Use style="?android:attr/progressBarStyleLarge" or Small.
(XML - Indeterminate): <ProgressBar android:id="@+id/loadingSpinner"
style="?android:attr/progressBarStyleLarge" ... />
(XML - Determinate): <ProgressBar android:id="@+id/downloadProgress"
style="?android:attr/progressBarStyleHorizontal" ... android:max="100"
android:progress="25"/>
3.7 Auto Complete Text View (AutoCompleteTextView)
● EditText showing suggestions while typing. Requires an Adapter.
Use android:completionThreshold (chars before suggestions appear).
(XML): <AutoCompleteTextView android:id="@+id/autoComplete" ...
android:completionThreshold="1"/>
(Java - Populate with String Array):
AutoCompleteTextView textView = findViewById(R.id.autoComplete);
String[] suggestions = { "Apple", "Appricot", "Avocado" };
ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
android.R.layout.simple_dropdown_item_1line, suggestions);
textView.setAdapter(adapter);
3.8 Dialog Box (Dialog)
(Small prompt windows. Use DialogFragment for better lifecycle management).
3.8.1 Alert Dialog (AlertDialog)
● Standard dialog: title, message, up to 3 buttons (Positive, Negative, Neutral), list, or
custom layout. Built with AlertDialog.Builder.
(Java):
new AlertDialog.Builder(this)
.setTitle("Confirmation")
.setMessage("Are you sure?")
.setPositiveButton("Yes", (dialog, which) -> { /* Action for Yes */ })
.setNegativeButton("No", null) // Dismisses dialog
.show();
3.8.2 DatePicker Dialog (DatePickerDialog)
● Standard dialog to select Year, Month, Day. Use DatePickerDialog.OnDateSetListener
for result.
(Java):
Calendar cal = Calendar.getInstance();
// ... get current year, month, day ...
DatePickerDialog dateDialog = new DatePickerDialog(this,
(view, year, month, dayOfMonth) -> {
// month is 0-based; Use selected year, month+1, dayOfMonth
}, cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH));
dateDialog.show();
3.8.3 TimePicker Dialog (TimePickerDialog)
● Standard dialog to select Hour, Minute. Use TimePickerDialog.OnTimeSetListener for
result.
(Java):
Calendar cal = Calendar.getInstance();
// ... get current hour, minute ...
boolean is24Hour = android.text.format.DateFormat.is24HourFormat(this);
TimePickerDialog timeDialog = new TimePickerDialog(this,
(view, hourOfDay, minute) -> {
// Use selected hourOfDay, minute
}, cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), is24Hour);
timeDialog.show();
3.8.4 Custom Dialog
● Use your own XML layout inside a dialog. Inflate the layout and set it using
AlertDialog.Builder.setView().
(Java - Conceptual):
AlertDialog.Builder builder = new AlertDialog.Builder(this);
LayoutInflater inflater = this.getLayoutInflater();
View dialogView = inflater.inflate(R.layout.custom_dialog_layout, null);
builder.setView(dialogView);
// ... Find views inside dialogView (EditText, etc.) ...
builder.setTitle("Custom Dialog");
builder.setPositiveButton("OK", (dialog, which) -> { /* Use custom view data */ });
// ...
AlertDialog dialog = builder.create();
dialog.show();
UNIT 4: ADAPTER AND MENU
(Adapters bridge data to UI views like ListView; Menus provide actions).
4.1 Base Adapter (BaseAdapter)
● Abstract base class for custom adapters. Provides full control.
● Implement:
○ getCount(): Total item count.
○ getItem(int position): Data item at position.
○ getItemId(int position): Unique ID for item at position.
○ getView(int position, View convertView, ViewGroup parent): Core method;
create/recycle and populate item view.
■ Use convertView (recycled view) for performance.
■ Use View Holder Pattern (static inner class holding item view
references) to avoid repeated findViewById().
4.2 Array Adapter (ArrayAdapter)
● Concrete adapter for arrays or Lists. Simple for basic TextView items.
(Java - Simple Usage):
String[] data = {"A", "B", "C"};
ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
android.R.layout.simple_list_item_1, // Built-in layout
data);
4.3 ListView using Adapter
● Connects ListView to data via an Adapter.
(Java - Conceptual):
// 1. Get ListView from layout
ListView listView = findViewById(R.id.myListView);
// 2. Prepare data (e.g., ArrayList<String> items)
// 3. Create Adapter (e.g., ArrayAdapter)
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
items);
// 4. Set Adapter on ListView
listView.setAdapter(adapter);
// 5. Set OnItemClickListener (optional)
4.4 GridView using Adapter
● Displays items in a 2D scrollable grid. Uses an Adapter just like ListView.
● Key Attributes: android:numColumns, android:columnWidth, android:verticalSpacing,
android:horizontalSpacing.
(Java - Conceptual):
// 1. Get GridView from layout
GridView gridView = findViewById(R.id.myGridView);
// 2. Prepare data (e.g., ArrayList<MyObject> data)
// 3. Create custom Adapter (e.g., extending BaseAdapter)
MyCustomGridAdapter adapter = new MyCustomGridAdapter(this, data);
// 4. Set Adapter on GridView
gridView.setAdapter(adapter);
// 5. Set OnItemClickListener (optional)
4.5 Photo Gallery using Adapter
● Typically uses GridView (or RecyclerView) with a custom Adapter (extending
BaseAdapter or RecyclerView.Adapter) displaying ImageViews.
● Item Layout (grid_item_image.xml): Contains an <ImageView>.
● Custom Adapter (ImageAdapter extends BaseAdapter):
○ Holds Context and list of image sources (resource IDs, paths, URLs).
○ getView() inflates grid_item_image.xml, gets the ImageView, and loads the image
(using setImageResource, or libraries like Glide/Picasso for efficiency with
paths/URLs).
● Activity: Set up GridView and attach ImageAdapter.
4.6 Using Menu with Views
4.6.1 Option Menu
● Primary menu for an Activity, usually in the App Bar/Action Bar.
Define: res/menu/main_menu.xml. Use <item> tags (android:id, android:title, android:icon,
app:showAsAction).
(XML):
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/action_settings" android:title="Settings" app:showAsAction="never"/>
<item android:id="@+id/action_search" android:title="Search"
android:icon="@drawable/ic_search" app:showAsAction="ifRoom"/>
</menu>
● Inflate: Override onCreateOptionsMenu(Menu menu) in Activity, use
getMenuInflater().inflate().
● Handle Clicks: Override onOptionsItemSelected(MenuItem item) in Activity, check
item.getItemId().
4.6.2 Context Menu
● Floating menu on long-press of a registered View.
● Register View: registerForContextMenu(myListView); in onCreate().
● Define: res/menu/context_menu.xml.
● Create: Override onCreateContextMenu(ContextMenu menu, View v,
ContextMenu.ContextMenuInfo menuInfo) in Activity. Inflate menu. menuInfo provides
context (e.g., list item position).
● Handle Clicks: Override onContextItemSelected(MenuItem item) in Activity. Check
item.getItemId(). Get context info via item.getMenuInfo().
4.6.3 Popup Menu
● Modal menu anchored to a specific View, shown on click (not long-press).
● Define: res/menu/popup_menu.xml.
Show: In the anchor View's OnClickListener:
(Java - Conceptual):
anchorView.setOnClickListener(v -> {
PopupMenu popup = new PopupMenu(MyActivity.this, v); // Anchor to view 'v'
popup.getMenuInflater().inflate(R.menu.popup_menu, popup.getMenu());
popup.setOnMenuItemClickListener(item -> {
// Handle item clicks based on item.getItemId()
return true; // True if handled
});
popup.show();
});
UNIT 5: THREADS AND NOTIFICATION
(Handling background work and user alerts).
5.1 Worker thread
● Problem: Long tasks (network, disk I/O, computation) on the main UI thread cause
ANRs ("Application Not Responding").
● Solution: Perform long tasks on background ("worker") threads.
● Challenge: Worker threads cannot directly update the UI.
● Creation: Use new Thread(Runnable) or ExecutorService.
(Java - Conceptual):
new Thread(() -> {
// Long work here...
final String result = performLongOperation();
// Post result back to UI thread (using Handler or runOnUiThread)
runOnUiThread(() -> {
// Update UI here (e.g., myTextView.setText(result))
});
}).start();
5.2 Handlers & Runnable
● Handler: Schedules Runnables or Messages to be executed on a specific thread's
message queue (usually the main UI thread).
● Purpose: Communicate from worker thread back to UI thread.
● Usage:
1. Create Handler on UI thread: Handler uiHandler = new
Handler(Looper.getMainLooper());
2. From worker thread, post Runnable containing UI updates: uiHandler.post(() -> {
/* UI update code */ });
● Activity.runOnUiThread(Runnable) is often a convenient shortcut.
5.3 AsynTask (in detail)
● Note: Deprecated (API 30+). Use Kotlin Coroutines, Executors, or WorkManager in
modern development. Understanding is still useful.
● Purpose: Simplified background tasks with UI updates.
● Generics: AsyncTask<Params, Progress, Result>
● Key Methods:
○ onPreExecute() (UI Thread): Setup before task starts (e.g., show progress).
○ doInBackground(Params...) (Worker Thread): Required. Background work.
Return Result. Call publishProgress() here. Cannot touch UI.
○ onProgressUpdate(Progress...) (UI Thread): Update UI based on
publishProgress() calls.
○ onPostExecute(Result result) (UI Thread): Called after doInBackground. Update
UI with final Result.
○ onCancelled(Result result) (UI Thread): Called if task cancelled.
● Execution: new MyAsyncTask().execute(params);
(Java - Skeleton):
private class MyAsyncTask extends AsyncTask<Void, Integer, String> {
@Override protected void onPreExecute() { /* Show progress */ }
@Override protected String doInBackground(Void... voids) {
// Long work... publishProgress(percentComplete); ... return result;
}
@Override protected void onProgressUpdate(Integer... values) { /* Update progress bar */ }
@Override protected void onPostExecute(String result) { /* Hide progress, show result */ }
}
5.4 Broadcast Receiver
● Component responding to system or app broadcast Intents.
● Use Cases: React to boot completed, connectivity change, battery low, custom events.
● Registration:
○ Manifest-declared (Static): <receiver> tag in AndroidManifest.xml. Can start
app process (with restrictions on newer Android).
○ Context-registered (Dynamic): Use Context.registerReceiver() /
unregisterReceiver(). Active only while registering component lives. Preferred for
UI-related or non-system broadcasts.
● Implementation: Subclass BroadcastReceiver, override onReceive(Context context,
Intent intent).
○ onReceive runs on main thread – keep it short! Delegate long work to a Service
or WorkManager.
(Java - Skeleton):
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
// Handle boot completed - maybe start a service
}
// ... check other actions ...
}
}
5.5 Services
(Component for long background tasks without UI).
5.5.1 Service life Cycle
● Two main paths: Started (via startService) and Bound (via bindService).
● Started Lifecycle: onCreate() -> onStartCommand() (called for each startService) ->
(running) -> onDestroy(). Service runs until stopSelf() or stopService() is called.
● Bound Lifecycle: onCreate() -> onBind() (returns IBinder for interaction) -> (clients
bound) -> onUnbind() -> onDestroy(). Service lives as long as clients are bound (unless
also started).
● onBind(): Returns IBinder interface for client communication.
● onStartCommand(): Receives Intent from startService(); return value (START_STICKY,
etc.) dictates restart behavior if killed.
5.5.2 Bounded Service
● Clients connect using bindService().
● Allows client-server interaction via the returned IBinder (using Binder, Messenger, or
AIDL).
● Lives only as long as clients are bound (unless also started).
5.5.3 Unbounded Service (Started Service)
● Started via startService().
● Runs independently of the starting component.
● Must manage its own lifetime (stopSelf()).
● Used for fire-and-forget tasks (downloads, music). Communicates status via Notifications
or Broadcasts.
5.6 Notification
● UI alerts displayed outside the app (status bar, notification drawer, heads-up).
● Requires: NotificationManager, NotificationCompat.Builder (from AndroidX),
NotificationChannel (API 26+).
● Steps (API 26+):
1. Create Notification Channel: Define channel ID, name, importance. Do this
once (e.g., in Application class).
2. Create PendingIntent: Intent to fire when notification is tapped (e.g., open
Activity). Use PendingIntent.FLAG_IMMUTABLE.
3. Build Notification: Use NotificationCompat.Builder - set small icon (mandatory),
title, text, priority, content intent, channel ID, etc.
4. Issue Notification: Get NotificationManagerCompat, call notify(notificationId,
builder.build()). Requires POST_NOTIFICATIONS permission on Android 13+.
(Java - Conceptual Build):
// Assuming channel "MY_CHANNEL_ID" created and pendingIntent exists
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "MY_CHANNEL_ID")
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle("Task Complete")
.setContentText("Your task finished successfully.")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent)
.setAutoCancel(true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
// Check POST_NOTIFICATIONS permission before notify() on Android 13+
notificationManager.notify(101, builder.build());
5.7 Alarm (AlarmManager)
● System service to schedule code execution (via PendingIntent) at a future time, even if
app isn't running.
● Types: ELAPSED_REALTIME (time since boot), RTC (wall-clock time). Use _WAKEUP
variants to wake the device.
● Exact vs. Inexact: Use setExact(), setExactAndAllowWhileIdle() for precise timing
(needs SCHEDULE_EXACT_ALARM permission on Android 12+). Prefer
setInexactRepeating() or set() for battery efficiency when precision isn't critical.
WorkManager is often better for deferrable tasks.
● Usage: Get AlarmManager, create PendingIntent (for BroadcastReceiver/Service), call
set...() method.
● Cancel: alarmManager.cancel(pendingIntent).
● Note: Alarms cancelled on reboot; use BOOT_COMPLETED receiver to reschedule if
needed.
(Java - Conceptual One-Time Alarm):
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, MyAlarmReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, intent,
PendingIntent.FLAG_IMMUTABLE);
long triggerTime = System.currentTimeMillis() + 60000; // 1 minute from now
// Check permissions and use appropriate set method (setExactAndAllowWhileIdle, setExact,
set)
// e.g., am.set(AlarmManager.RTC_WAKEUP, triggerTime, pi);
5.8 Accessing Phone services (Call, SMS)
(Use implicit Intents; Requires Manifest permissions and often runtime checks).
● Making a Phone Call:
○ Intent.ACTION_DIAL: Opens dialer with number pre-filled (User initiates call). No
permission needed. Uri.parse("tel:12345")
○ Intent.ACTION_CALL: Initiates call directly. Requires CALL_PHONE permission
(Manifest + Runtime). Uri.parse("tel:12345")
● Sending SMS:
○ Intent.ACTION_SENDTO / ACTION_VIEW: Opens default SMS app pre-filled
(User sends). No permission needed. Uri.parse("smsto:12345"). Use
putExtra("sms_body", "message").
○ SmsManager: Sends directly in background. Requires SEND_SMS permission
(Manifest + Runtime). Use SmsManager.getDefault().sendTextMessage(...).
UNIT 6: CONTENT PROVIDER
(Mechanisms for storing and sharing data).
6.1 Content Providers
● Purpose: Standard interface to manage and share app data securely. Abstracts
underlying storage.
● Key Concepts:
○ Content URI: Uri identifying data: content://<authority>/<path>/<optional_id>.
Authority is unique name (e.g., com.android.contacts).
○ ContentResolver: Client object (getContentResolver()) used to interact with
providers (query, insert, update, delete).
● Usage: Access system providers (Contacts, MediaStore) or create your own by
extending ContentProvider and implementing its methods. Register in Manifest with
authority and permissions.
6.2 SQLite Programming
● Android's built-in relational database engine. Stored in app's private directory. Accessed
via SQL.
6.3 SQLiteOpenHelper
● Helper class managing database creation and versioning. Recommended approach.
● Override:
○ onCreate(SQLiteDatabase db): Executes CREATE TABLE statements when DB
is first created.
○ onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion): Handles schema
changes when DATABASE_VERSION increases (e.g., ALTER TABLE).
● Get DB: getWritableDatabase(), getReadableDatabase().
(Java - Skeleton):
public class MyDbHelper extends SQLiteOpenHelper {
private static final String DBNAME = "app.db";
private static final int VERSION = 1;
public MyDbHelper(Context context) { super(context, DBNAME, null, VERSION); }
@Override public void onCreate(SQLiteDatabase db) { /* db.execSQL("CREATE TABLE ...");
*/ }
@Override public void onUpgrade(SQLiteDatabase db, int oldV, int newV) { /* Drop/Alter
tables */ }
}
6.4 SQLiteDatabase
● Represents the DB connection (from SQLiteOpenHelper).
● Methods:
○ execSQL(String sql): Non-query SQL (CREATE, INSERT, UPDATE, DELETE).
○ rawQuery(String sql, String[] args): Executes SELECT, returns Cursor. Use ?
placeholders for args.
○ query(...): Structured SELECT builder, returns Cursor.
○ insert(String table, String nullColHack, ContentValues values): Insert row using
ContentValues map. Returns row ID.
○ update(String table, ContentValues values, String where, String[] args): Update
rows. Returns count.
○ delete(String table, String where, String[] args): Delete rows. Returns count.
○ Transaction methods: beginTransaction(), setTransactionSuccessful(),
endTransaction().
6.5 Cursor
● Interface providing access to query result set rows.
● Key Methods: getCount(), moveToFirst(), moveToNext(), getColumnIndexOrThrow(),
getString(), getInt(), etc. (get data for current row), close().
● CRUCIAL: Always close() the cursor when done (use try-finally or try-with-resources).
(Java - Iteration):
Cursor cursor = db.query(...);
try {
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndexOrThrow("name"));
// ... process data ...
}
} finally {
if (cursor != null) cursor.close();
}
6.6 Searching for content
● Use selection (WHERE clause) and selectionArgs parameters in
SQLiteDatabase.query() or ContentResolver.query().
● Use ? placeholders in selection and provide values in selectionArgs array to prevent
SQL injection.
(Java - Example Search):
String searchTerm = "term";
String selection = "columnName LIKE ?";
String[] selectionArgs = { "%" + searchTerm + "%" };
Cursor cursor = db.query(TABLE_NAME, columns, selection, selectionArgs, null, null, null);
// ... process cursor ...
6.7 Adding, changing, and removing content
● Use SQLiteDatabase methods (insert, update, delete) with ContentValues for data and
whereClause/whereArgs for targeting rows.
● Or use ContentResolver methods (insert, update, delete) with a Content URI and
ContentValues/whereClause/whereArgs.
(Java - Insert Example):
ContentValues values = new ContentValues();
values.put("name", "New Item");
values.put("quantity", 5);
long newId = db.insert(TABLE_NAME, null, values);
6.8 Building and executing queries
● Prefer SQLiteDatabase.query() for structured SELECTs.
● Use rawQuery() for complex SELECTs.
● Always use ? placeholders and selection arguments.
● Handle and close the Cursor.
6.9 Android JSON
● Standard lightweight data format. Android provides org.json package.
● Classes:
○ JSONObject: Unordered name/value pairs (like Map). Methods: put(), getString(),
getInt(), getJSONObject(), getJSONArray(), optString() etc.
○ JSONArray: Ordered sequence of values (like List). Methods: put(), get(),
getString(), getJSONObject(), etc.
○ JSONException: Thrown on errors.
Parsing (String -> Object):
try {
JSONObject obj = new JSONObject(jsonString);
String name = obj.getString("name");
// ... get other values ...
} catch (JSONException e) { /* Handle error */ }
Creating (Object -> String):
try {
JSONObject obj = new JSONObject();
obj.put("key", "value");
JSONArray arr = new JSONArray();
arr.put(1); arr.put(2);
obj.put("numbers", arr);
String output = obj.toString(); // or obj.toString(indentation)
} catch (JSONException e) { /* Handle error */ }
● Libraries: Gson or Moshi highly recommended for simplifying conversion between
JSON and Java/Kotlin objects (POJOs).
UNIT 7: LOCATION BASED SERVICES AND GOOGLE MAP
(Location awareness and map integration).
Prerequisites: Setup Google Cloud Project, enable Maps SDK for Android, get API key, restrict
key, add key to Manifest, add dependencies (play-services-maps, play-services-location).
7.1 Display Google Maps
7.1.1 Creating the project: (Covered by prerequisites - dependencies)
7.1.2 Obtaining the Maps API Key: (Covered by prerequisites - Cloud Console setup &
Manifest entry)
(XML - Manifest Snippet):
xml <application ...> <meta-data android:name="com.google.android.geo.API_KEY"
android:value="YOUR_API_KEY_HERE"/> </application>
7.1.3 Displaying the Map:
Use SupportMapFragment in layout XML.
(XML):
<fragment
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
● Implement OnMapReadyCallback in Activity/Fragment.
● Get fragment, call getMapAsync(this).
Receive GoogleMap object in onMapReady(GoogleMap map).
(Java - Activity Skeleton):
public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback {
private GoogleMap mMap;
@Override protected void onCreate(Bundle savedInstanceState) { /*...*/
SupportMapFragment mapFragment = (SupportMapFragment)
getSupportFragmentManager().findFragmentById(R.id.map);
if (mapFragment != null) mapFragment.getMapAsync(this);
}
@Override public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
// Map is ready - add markers, move camera, etc.
LatLng sydney = new LatLng(-34, 151);
mMap.addMarker(new MarkerOptions().position(sydney).title("Sydney"));
mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
}
}
7.1.4 Displaying the Zoom Control:
● Use UiSettings obtained from GoogleMap object in onMapReady.
(Java): mMap.getUiSettings().setZoomControlsEnabled(true);
7.1.5 Changing Views (Map Types):
● Use mMap.setMapType() with constants like GoogleMap.MAP_TYPE_NORMAL,
MAP_TYPE_SATELLITE, MAP_TYPE_HYBRID, MAP_TYPE_TERRAIN.
(Java): mMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
7.1.6 Navigating to a specific location:
● Use CameraUpdateFactory to create CameraUpdates.
Call mMap.moveCamera() (instant) or mMap.animateCamera() (smooth).
(Java):
LatLng location = new LatLng(40.7128, -74.0060); // NYC
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(location, 15.0f));
7.1.7 Adding Markers:
Use mMap.addMarker(MarkerOptions). Customize MarkerOptions (position, title, snippet, icon,
draggable).
(Java):
Marker marker = mMap.addMarker(new MarkerOptions()
.position(someLatLng)
.title("Marker Title")
.snippet("More details")
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))
.draggable(true));
● Use listeners like setOnMarkerClickListener, setOnMarkerDragListener.
7.1.8 Getting the location that was touched:
Set listeners mMap.setOnMapClickListener or mMap.setOnMapLongClickListener. The callback
receives the LatLng of the clicked point.
(Java):
mMap.setOnMapClickListener(latLng -> {
// Add marker or get address for latLng
Toast.makeText(this, "Clicked: " + latLng, Toast.LENGTH_SHORT).show();
});
7.1.9 Geocoding and Reverse Geocoding:
● Use Geocoder class. Perform on background thread. May require network.
● Geocoding: Address String -> List<Address> (containing LatLng). Use
geocoder.getFromLocationName(addressString, maxResults).
Reverse Geocoding: LatLng -> List<Address> (containing address lines). Use
geocoder.getFromLocation(latitude, longitude, maxResults).
(Java - Conceptual Reverse Geocoding):
// Run in background thread
Geocoder geocoder = new Geocoder(this, Locale.getDefault());
try {
List<Address> addresses = geocoder.getFromLocation(latLng.latitude, latLng.longitude, 1);
if (addresses != null && !addresses.isEmpty()) {
Address address = addresses.get(0);
// Build address string from address.getAddressLine(i)
final String addressText = // ... built address ...
runOnUiThread(() -> { /* Update UI with addressText */ });
}
} catch (IOException e) { /* Handle error */ }
7.2. Getting Location Data
● Use Fused Location Provider API (com.google.android.gms:play-services-location).
● Permissions: ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION
(Manifest + Runtime Request). ACCESS_BACKGROUND_LOCATION for background
use (Android 10+).
● Get Client: fusedLocationClient =
LocationServices.getFusedLocationProviderClient(this);
● Last Known Location: Quick, but may be null/stale.
fusedLocationClient.getLastLocation().addOnSuccessListener(...). Check permissions
first.
● Requesting Updates: For current/continuous location.
1. Create LocationRequest: Set interval, priority (PRIORITY_HIGH_ACCURACY,
PRIORITY_BALANCED_POWER_ACCURACY, etc.).
2. Create LocationCallback: Override onLocationResult(LocationResult result) to
receive Location objects.
3. Start Updates: fusedLocationClient.requestLocationUpdates(locationRequest,
locationCallback, Looper.getMainLooper()). Check permissions first.
4. Stop Updates: fusedLocationClient.removeLocationUpdates(locationCallback).
Call this in onPause() or when done.
(Java - Location Callback Skeleton):
locationCallback = new LocationCallback() {
@Override
public void onLocationResult(@NonNull LocationResult locationResult) {
for (Location location : locationResult.getLocations()) {
// Process location.getLatitude(), location.getLongitude(), etc.
}
}
};
7.3. Monitoring a Location
● This is achieved by requesting continuous location updates (Section 7.2).
● Manage start/stop updates based on app lifecycle (onResume/onPause) or user actions.
● Background Monitoring: Requires ACCESS_BACKGROUND_LOCATION permission
and typically running updates within a Foreground Service (which must show a
persistent notification). Geofencing API is an alternative for triggering actions based on
entering/exiting defined areas.