Android Practicals:
1:A Simple Calculator
activity_main.xml
<EditText
android:id="@+id/et1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter Number 1"
android:inputType="numberDecimal"/>
<EditText
android:id="@+id/et2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter Number 2"
android:inputType="numberDecimal"/>
<TextView
android:id="@+id/tvResult"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Result: "
android:textSize="24sp"
android:padding="20dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button android:id="@+id/btnAdd" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Add" android:layout_weight="1"/>
<Button android:id="@+id/btnSub" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Sub" android:layout_weight="1"/>
<Button android:id="@+id/btnMul" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Mul" android:layout_weight="1"/>
<Button android:id="@+id/btnDiv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Div" android:layout_weight="1"/>
</LinearLayout>
MainActivity.java
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
EditText et1, et2;
TextView tvResult;
Button btnAdd, btnSub, btnMul, btnDiv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et1 = findViewById(R.id.et1);
et2 = findViewById(R.id.et2);
tvResult = findViewById(R.id.tvResult);
btnAdd = findViewById(R.id.btnAdd);
btnSub = findViewById(R.id.btnSub);
btnMul = findViewById(R.id.btnMul);
btnDiv = findViewById(R.id.btnDiv);
btnAdd.setOnClickListener(this);
btnSub.setOnClickListener(this);
btnMul.setOnClickListener(this);
btnDiv.setOnClickListener(this);
}
@Override
public void onClick(View v) {
String num1Str = et1.getText().toString();
String num2Str = et2.getText().toString();
if(num1Str.isEmpty() || num2Str.isEmpty()){
Toast.makeText(this, "Please enter numbers", Toast.LENGTH_SHORT).show();
return;
}
double num1 = Double.parseDouble(num1Str);
double num2 = Double.parseDouble(num2Str);
double res = 0;
try {
int id = v.getId();
if (id == R.id.btnAdd) res = num1 + num2;
else if (id == R.id.btnSub) res = num1 - num2;
else if (id == R.id.btnMul) res = num1 * num2;
else if (id == R.id.btnDiv) {
if(num2 == 0) throw new ArithmeticException("Div by Zero");
res = num1 / num2;
}
tvResult.setText("Result: " + res);
} catch (Exception e) {
Toast.makeText(this, "Error: " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
Assignment 2: Currency Converter
Files required: activity_main.xml, MainActivity.java
res/layout/activity_main.xml
XML
<EditText
android:id="@+id/etAmount"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter Amount"
android:inputType="numberDecimal"/>
<Spinner
android:id="@+id/spinnerFrom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"/>
<Spinner
android:id="@+id/spinnerTo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"/>
<Button
android:id="@+id/btnConvert"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Convert"
android:layout_marginTop="20dp"/>
<TextView
android:id="@+id/tvResult"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="22sp"
android:layout_marginTop="20dp"/>
MainActivity.java
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
EditText etAmount;
Spinner spFrom, spTo;
Button btnConvert;
TextView tvResult;
// Currencies: INR, USD, EUR, JPY, GBP
String[] currencies = {"INR", "USD", "EUR", "JPY", "GBP"};
// Conversion rates relative to INR (Approx for demo)
// INR, USD (1$=83), EUR (1€=90), JPY (1¥=0.55), GBP (1£=105)
double[] ratesToINR = {1.0, 83.0, 90.0, 0.55, 105.0};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etAmount = findViewById(R.id.etAmount);
spFrom = findViewById(R.id.spinnerFrom);
spTo = findViewById(R.id.spinnerTo);
btnConvert = findViewById(R.id.btnConvert);
tvResult = findViewById(R.id.tvResult);
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, currencies);
spFrom.setAdapter(adapter);
spTo.setAdapter(adapter);
btnConvert.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(etAmount.getText().toString().isEmpty()) return;
double amount = Double.parseDouble(etAmount.getText().toString());
int fromIndex = spFrom.getSelectedItemPosition();
int toIndex = spTo.getSelectedItemPosition();
// Logic: Convert 'From' to INR, then INR to 'To'
double amountInINR = amount * ratesToINR[fromIndex];
double finalAmount = amountInINR / ratesToINR[toIndex];
tvResult.setText(String.format("%.2f %s", finalAmount, currencies[toIndex]));
}
});
}
Assignment 3: Explicit Intent (Registration Form) - FIXED
- res/layout/activity_main.xml
(No changes needed, but double-check the IDs match exactly)
XML
<EditText
android:id="@+id/etName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter Name"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Select Gender:"
android:layout_marginTop="10dp"/>
<RadioGroup
android:id="@+id/rgGender"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RadioButton android:id="@+id/rbMale" android:text="Male" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
<RadioButton android:id="@+id/rbFemale" android:text="Female" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
</RadioGroup>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Select Skills:"
android:layout_marginTop="10dp"/>
<CheckBox android:id="@+id/cbCoding" android:text="Coding" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
<CheckBox android:id="@+id/cbDesign" android:text="Design" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
<Button
android:id="@+id/btnSubmit"
android:text="Submit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"/>
2. MainActivity.java (Updated with Safer Logic)
Ensure your package name at the top matches your project exactly.
Java
package com.example.explicitintent; // CHANGE THIS to your actual package name
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
EditText etName;
RadioGroup rgGender;
CheckBox cbCoding, cbDesign;
Button btnSubmit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etName = findViewById(R.id.etName);
rgGender = findViewById(R.id.rgGender);
cbCoding = findViewById(R.id.cbCoding);
cbDesign = findViewById(R.id.cbDesign);
btnSubmit = findViewById(R.id.btnSubmit);
btnSubmit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Validation: Prevent empty name
if(etName.getText().toString().isEmpty()) {
Toast.makeText(MainActivity.this, "Please enter name", Toast.LENGTH_SHORT).show();
return;
}
Intent i = new Intent(MainActivity.this, ResultActivity.class);
// 1. Pass Name
i.putExtra("name", etName.getText().toString());
// 2. Pass Gender (Safe Check)
int selectedId = rgGender.getCheckedRadioButtonId();
if (selectedId != -1) {
RadioButton rb = findViewById(selectedId);
i.putExtra("gender", rb.getText().toString());
} else {
i.putExtra("gender", "Not Selected");
}
// 3. Pass Skills
StringBuilder skills = new StringBuilder();
if(cbCoding.isChecked()) skills.append("Coding ");
if(cbDesign.isChecked()) skills.append("Design");
// If nothing checked
String finalSkills = skills.length() > 0 ? skills.toString() : "None";
i.putExtra("skills", finalSkills);
startActivity(i);
}
});
}
}
3. AndroidManifest.xml (THE CRITICAL PART)
This is where the crash usually happens. You must declare inside the tag.
XML
<activity android:name=".ResultActivity" />
</application>
4. ResultActivity.java
Create a new Java Class named ResultActivity and paste this:
Java
package com.example.explicitintent; // CHANGE THIS to your package name
import android.os.Bundle;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
public class ResultActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_result); // Make sure this layout exists
TextView tvData = findViewById(R.id.tvData);
// Get data safely
String name = getIntent().getStringExtra("name");
String gender = getIntent().getStringExtra("gender");
String skills = getIntent().getStringExtra("skills");
tvData.setText("Registration Details:\n\nName: " + name + "\nGender: " + gender + "\nSkills: " + skills);
}
}
5. res/layout/activity_result.xml
Make sure this file exists in your layout folder.
XML
<TextView
android:id="@+id/tvData"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="22sp"
android:textStyle="bold"
android:text="Loading..."/>
Checklist to fix the crash:
Open AndroidManifest.xml.
Look for the tag.
Ensure is inside it.
Ensure package name at the top of Java files matches your project structure.
Assignment 4: Implicit Intent
Files required: activity_main.xml, MainActivity.java
- res/layout/activity_main.xml
XML
<EditText android:id="@+id/etUrl" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="https://www.google.com"/>
<Button android:id="@+id/btnBrowser" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Open Browser"/>
<EditText android:id="@+id/etPhone" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Enter Number" android:inputType="phone"/>
<Button android:id="@+id/btnDial" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Dial Number"/>
2. MainActivity.java
Java
package com.example.implicitintent;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EditText etUrl = findViewById(R.id.etUrl);
Button btnBrowser = findViewById(R.id.btnBrowser);
EditText etPhone = findViewById(R.id.etPhone);
Button btnDial = findViewById(R.id.btnDial);
// 1. Open Browser
btnBrowser.setOnClickListener(v -> {
String url = etUrl.getText().toString();
if (!url.startsWith("http")) url = "http://" + url;
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(i);
});
// 2. Open Dialer
btnDial.setOnClickListener(v -> {
String num = etPhone.getText().toString();
Intent i = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + num));
startActivity(i);
});
}
}
- AndroidManifest.xml (THE CRITICAL PART)
This is where the crash usually happens. You must declare inside the tag.
XML
<activity android:name=".ResultActivity" />
</application>
Assignment 5: Shared Preferences (Login)
Files required: activity_main.xml, MainActivity.java
- res/layout/activity_main.xml
XML
<EditText android:id="@+id/etUser" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Username"/>
<EditText android:id="@+id/etPass" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Password" android:inputType="textPassword"/>
<Button android:id="@+id/btnLogin" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Login"/>
<Button android:id="@+id/btnLogout" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Logout" android:enabled="false"/>
<TextView android:id="@+id/tvStatus" android:layout_width="match_parent" android:layout_height="wrap_content" android:textAlignment="center" android:paddingTop="20dp"/>
2. MainActivity.java
Java
package com.example.sharedpref;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
EditText etUser, etPass;
Button btnLogin, btnLogout;
TextView tvStatus;
SharedPreferences sp;
int attemptCount = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etUser = findViewById(R.id.etUser);
etPass = findViewById(R.id.etPass);
btnLogin = findViewById(R.id.btnLogin);
btnLogout = findViewById(R.id.btnLogout);
tvStatus = findViewById(R.id.tvStatus);
sp = getSharedPreferences("LoginPrefs", MODE_PRIVATE);
// Check if already logged in
String savedUser = sp.getString("username", null);
if(savedUser != null){
loggedInState(savedUser);
}
btnLogin.setOnClickListener(v -> {
String u = etUser.getText().toString();
String p = etPass.getText().toString();
// Hardcoded credential check
if(u.equals("admin") && p.equals("1234")) {
SharedPreferences.Editor editor = sp.edit();
editor.putString("username", u);
editor.apply();
loggedInState(u);
} else {
attemptCount++;
Toast.makeText(this, "Wrong Credentials", Toast.LENGTH_SHORT).show();
if(attemptCount >= 3) {
btnLogin.setEnabled(false);
tvStatus.setText("LOCKED: Too many attempts");
}
}
});
btnLogout.setOnClickListener(v -> {
SharedPreferences.Editor editor = sp.edit();
editor.clear();
editor.apply();
// Reset UI
etUser.setVisibility(View.VISIBLE);
etPass.setVisibility(View.VISIBLE);
btnLogin.setVisibility(View.VISIBLE);
btnLogout.setEnabled(false);
tvStatus.setText("Logged Out");
etUser.setText(""); etPass.setText("");
});
}
private void loggedInState(String user){
etUser.setVisibility(View.GONE);
etPass.setVisibility(View.GONE);
btnLogin.setVisibility(View.GONE);
btnLogout.setEnabled(true);
tvStatus.setText("Welcome, " + user);
}
}
Assignment 6: Notification (Fixed for Android 13+)
- AndroidManifest.xml Add the permission tag just before the tag.
XML
<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/Theme.AppCompat.Light">
<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>
2. MainActivity.java This version checks if your phone is Android 13+. If it is, it asks for permission. If you click "Allow", the notification will work.
Java
package com.example.notificationapp;
import android.Manifest;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.widget.Button;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.content.ContextCompat;
public class MainActivity extends AppCompatActivity {
private static final String CHANNEL_ID = "my_channel_01";
private static final int PERMISSION_REQUEST_CODE = 101;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 1. Create the channel immediately
createNotificationChannel();
Button btnNotify = findViewById(R.id.btnNotify);
btnNotify.setOnClickListener(v -> {
// 2. Check Permission for Android 13+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.POST_NOTIFICATIONS}, PERMISSION_REQUEST_CODE);
} else {
showNotification();
}
} else {
// Android 12 or lower doesn't need runtime permission
showNotification();
}
});
}
private void showNotification() {
// Intent to open Google when clicked
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.google.com"));
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(android.R.drawable.ic_dialog_info) // Must use a valid icon
.setContentTitle("New Alert")
.setContentText("Tap to open Google")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent)
.setAutoCancel(true);
// Show the notification
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
try {
notificationManager.notify(1, builder.build());
} catch (SecurityException e) {
Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show();
}
}
private void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = "My Notification Channel";
String description = "Channel for app alerts";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
// Register the channel with the system
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
}
3. res/layout/activity_main.xml (Simple button layout)
XML
<Button
android:id="@+id/btnNotify"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Send Notification" />
How to Run/Test:
Run the app.
Click the button.
Crucial Step: A dialog will pop up asking "Allow this app to send notifications?". Click Allow.
Click the button again (or it might appear immediately). You should see the icon in the status bar.
Assignment 7: File Storage (Fixed Layout & No Bar)
- MainActivity.java
Java
package com.example.filestorage; // CHANGE THIS to your package name
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
public class MainActivity extends AppCompatActivity {
EditText etInput;
TextView tvDisplay;
String FILE_NAME = "myfile.txt";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// --- HIDE THE TOP BAR ---
if (getSupportActionBar() != null) {
getSupportActionBar().hide();
}
etInput = findViewById(R.id.etInput);
tvDisplay = findViewById(R.id.tvDisplay);
// Internal Storage Listeners
findViewById(R.id.btnSaveInt).setOnClickListener(v -> saveInternal());
findViewById(R.id.btnReadInt).setOnClickListener(v -> readInternal());
// External Storage Listeners
findViewById(R.id.btnSaveExt).setOnClickListener(v -> saveExternal());
findViewById(R.id.btnReadExt).setOnClickListener(v -> readExternal());
}
// --- Internal Storage ---
private void saveInternal() {
String data = etInput.getText().toString();
if(data.isEmpty()) {
Toast.makeText(this, "Enter text first", Toast.LENGTH_SHORT).show();
return;
}
try {
FileOutputStream fos = openFileOutput(FILE_NAME, MODE_PRIVATE);
fos.write(data.getBytes());
fos.close();
Toast.makeText(this, "Saved to Internal", Toast.LENGTH_SHORT).show();
etInput.setText(""); // Clear input
} catch (Exception e) { e.printStackTrace(); }
}
private void readInternal() {
try {
FileInputStream fis = openFileInput(FILE_NAME);
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) sb.append(line);
tvDisplay.setText("Internal Content:\n" + sb.toString());
fis.close();
} catch (Exception e) {
tvDisplay.setText("No file found in Internal Storage");
}
}
// --- External Storage ---
private void saveExternal() {
String data = etInput.getText().toString();
if(data.isEmpty()) {
Toast.makeText(this, "Enter text first", Toast.LENGTH_SHORT).show();
return;
}
try {
// getExternalFilesDir(null) doesn't require extra permissions in Manifest for newer Android
File file = new File(getExternalFilesDir(null), FILE_NAME);
FileOutputStream fos = new FileOutputStream(file);
fos.write(data.getBytes());
fos.close();
Toast.makeText(this, "Saved to External", Toast.LENGTH_SHORT).show();
etInput.setText("");
} catch (Exception e) { e.printStackTrace(); }
}
private void readExternal() {
try {
File file = new File(getExternalFilesDir(null), FILE_NAME);
FileInputStream fis = new FileInputStream(file);
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) sb.append(line);
tvDisplay.setText("External Content:\n" + sb.toString());
fis.close();
} catch (Exception e) {
tvDisplay.setText("No file found in External Storage");
}
}
}
2. res/layout/activity_main.xml (Added ScrollView so buttons are never hidden)
XML
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp"
android:gravity="center_horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="File Storage Demo"
android:textSize="24sp"
android:textStyle="bold"
android:layout_marginBottom="20dp"/>
<EditText
android:id="@+id/etInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter text here..."
android:background="#E0E0E0"
android:padding="15dp"
android:layout_marginBottom="20dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Internal Storage (Private)"
android:textStyle="bold"
android:layout_marginTop="10dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="2">
<Button
android:id="@+id/btnSaveInt"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Save"
android:layout_marginEnd="5dp"/>
<Button
android:id="@+id/btnReadInt"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Read"
android:layout_marginStart="5dp"/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="External Storage (Public)"
android:textStyle="bold"
android:layout_marginTop="20dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="2">
<Button
android:id="@+id/btnSaveExt"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Save"
android:layout_marginEnd="5dp"/>
<Button
android:id="@+id/btnReadExt"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Read"
android:layout_marginStart="5dp"/>
</LinearLayout>
<TextView
android:id="@+id/tvDisplay"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:textSize="18sp"
android:textAlignment="center"
android:text="Result will appear here..."/>
</LinearLayout>
Assignment 8: SQLite Database
Goal: CRUD operations for a Student Database. Structure: DBHelper.java (Database Logic) + MainActivity.java (UI Logic).
- DBHelper.java (Create this class)
Java
package com.example.sqlitedemo;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DBHelper extends SQLiteOpenHelper {
public DBHelper(Context context) {
super(context, "StudentDB.db", null, 1);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table Student(id TEXT primary key, name TEXT, marks TEXT)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("drop table if exists Student");
onCreate(db);
}
public boolean insertData(String id, String name, String marks) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put("id", id);
cv.put("name", name);
cv.put("marks", marks);
long result = db.insert("Student", null, cv);
return result != -1;
}
public boolean updateData(String id, String name, String marks) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put("name", name);
cv.put("marks", marks);
Cursor cursor = db.rawQuery("select * from Student where id = ?", new String[]{id});
if (cursor.getCount() > 0) {
long result = db.update("Student", cv, "id=?", new String[]{id});
return result != -1;
}
return false;
}
public boolean deleteData(String id) {
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery("select * from Student where id = ?", new String[]{id});
if (cursor.getCount() > 0) {
long result = db.delete("Student", "id=?", new String[]{id});
return result != -1;
}
return false;
}
public Cursor getData() {
SQLiteDatabase db = this.getWritableDatabase();
return db.rawQuery("select * from Student", null);
}
}
2. MainActivity.java
Java
package com.example.sqlitedemo;
import android.database.Cursor;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
EditText etId, etName, etMarks;
Button btnAdd, btnUpdate, btnDelete, btnView;
DBHelper DB;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etId = findViewById(R.id.etId);
etName = findViewById(R.id.etName);
etMarks = findViewById(R.id.etMarks);
btnAdd = findViewById(R.id.btnAdd);
btnUpdate = findViewById(R.id.btnUpdate);
btnDelete = findViewById(R.id.btnDelete);
btnView = findViewById(R.id.btnView);
DB = new DBHelper(this);
btnAdd.setOnClickListener(v -> {
String id = etId.getText().toString();
String name = etName.getText().toString();
String marks = etMarks.getText().toString();
if(DB.insertData(id, name, marks))
Toast.makeText(this, "Inserted", Toast.LENGTH_SHORT).show();
else
Toast.makeText(this, "Failed", Toast.LENGTH_SHORT).show();
});
btnUpdate.setOnClickListener(v -> {
String id = etId.getText().toString();
String name = etName.getText().toString();
String marks = etMarks.getText().toString();
if(DB.updateData(id, name, marks))
Toast.makeText(this, "Updated", Toast.LENGTH_SHORT).show();
else
Toast.makeText(this, "No ID Found", Toast.LENGTH_SHORT).show();
});
btnDelete.setOnClickListener(v -> {
String id = etId.getText().toString();
if(DB.deleteData(id))
Toast.makeText(this, "Deleted", Toast.LENGTH_SHORT).show();
else
Toast.makeText(this, "No ID Found", Toast.LENGTH_SHORT).show();
});
btnView.setOnClickListener(v -> {
Cursor res = DB.getData();
if(res.getCount() == 0) {
Toast.makeText(this, "No Entry Exists", Toast.LENGTH_SHORT).show();
return;
}
StringBuffer buffer = new StringBuffer();
while(res.moveToNext()){
buffer.append("ID :"+res.getString(0)+"\n");
buffer.append("Name :"+res.getString(1)+"\n");
buffer.append("Marks :"+res.getString(2)+"\n\n");
}
new AlertDialog.Builder(this)
.setCancelable(true)
.setTitle("Entries")
.setMessage(buffer.toString())
.show();
});
}
}
3. res/layout/activity_main.xml
XML
<EditText android:id="@+id/etId" android:hint="ID" android:layout_width="match_parent" android:layout_height="wrap_content"/>
<EditText android:id="@+id/etName" android:hint="Name" android:layout_width="match_parent" android:layout_height="wrap_content"/>
<EditText android:id="@+id/etMarks" android:hint="Marks" android:layout_width="match_parent" android:layout_height="wrap_content"/>
<Button android:id="@+id/btnAdd" android:text="Insert" android:layout_width="match_parent" android:layout_height="wrap_content"/>
<Button android:id="@+id/btnUpdate" android:text="Update" android:layout_width="match_parent" android:layout_height="wrap_content"/>
<Button android:id="@+id/btnDelete" android:text="Delete" android:layout_width="match_parent" android:layout_height="wrap_content"/>
<Button android:id="@+id/btnView" android:text="View All" android:layout_width="match_parent" android:layout_height="wrap_content"/>
Assignment 8: SQLite Database (Fixed Layout & No Bar)
- DBHelper.java (This file handles the database logic. Create a new Java class named DBHelper and paste this.)
Java
package com.example.sqlitedemo; // CHANGE THIS to your package name
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DBHelper extends SQLiteOpenHelper {
public DBHelper(Context context) {
super(context, "StudentDB.db", null, 1);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table Student(id TEXT primary key, name TEXT, marks TEXT)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("drop table if exists Student");
onCreate(db);
}
public boolean insertData(String id, String name, String marks) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put("id", id);
cv.put("name", name);
cv.put("marks", marks);
long result = db.insert("Student", null, cv);
return result != -1; // returns true if insert is successful
}
public boolean updateData(String id, String name, String marks) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put("name", name);
cv.put("marks", marks);
Cursor cursor = db.rawQuery("select * from Student where id = ?", new String[]{id});
if (cursor.getCount() > 0) {
long result = db.update("Student", cv, "id=?", new String[]{id});
return result != -1;
}
return false;
}
public boolean deleteData(String id) {
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery("select * from Student where id = ?", new String[]{id});
if (cursor.getCount() > 0) {
long result = db.delete("Student", "id=?", new String[]{id});
return result != -1;
}
return false;
}
public Cursor getData() {
SQLiteDatabase db = this.getWritableDatabase();
return db.rawQuery("select * from Student", null);
}
}
2. MainActivity.java (Added code to hide the top bar)
Java
package com.example.sqlitedemo; // CHANGE THIS to your package name
import android.database.Cursor;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
EditText etId, etName, etMarks;
Button btnAdd, btnUpdate, btnDelete, btnView;
DBHelper DB;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// --- FIX: HIDE THE TOP BAR ---
if (getSupportActionBar() != null) {
getSupportActionBar().hide();
}
etId = findViewById(R.id.etId);
etName = findViewById(R.id.etName);
etMarks = findViewById(R.id.etMarks);
btnAdd = findViewById(R.id.btnAdd);
btnUpdate = findViewById(R.id.btnUpdate);
btnDelete = findViewById(R.id.btnDelete);
btnView = findViewById(R.id.btnView);
DB = new DBHelper(this);
btnAdd.setOnClickListener(v -> {
String id = etId.getText().toString();
String name = etName.getText().toString();
String marks = etMarks.getText().toString();
if(id.isEmpty()) {
Toast.makeText(this, "Enter ID", Toast.LENGTH_SHORT).show();
return;
}
if(DB.insertData(id, name, marks)) {
Toast.makeText(this, "Inserted Successfully", Toast.LENGTH_SHORT).show();
clearFields();
} else {
Toast.makeText(this, "Insert Failed (ID might exist)", Toast.LENGTH_SHORT).show();
}
});
btnUpdate.setOnClickListener(v -> {
String id = etId.getText().toString();
String name = etName.getText().toString();
String marks = etMarks.getText().toString();
if(DB.updateData(id, name, marks)) {
Toast.makeText(this, "Updated Successfully", Toast.LENGTH_SHORT).show();
clearFields();
} else {
Toast.makeText(this, "ID not found", Toast.LENGTH_SHORT).show();
}
});
btnDelete.setOnClickListener(v -> {
String id = etId.getText().toString();
if(DB.deleteData(id)) {
Toast.makeText(this, "Deleted Successfully", Toast.LENGTH_SHORT).show();
clearFields();
} else {
Toast.makeText(this, "ID not found", Toast.LENGTH_SHORT).show();
}
});
btnView.setOnClickListener(v -> {
Cursor res = DB.getData();
if(res.getCount() == 0) {
Toast.makeText(this, "No Data Found", Toast.LENGTH_SHORT).show();
return;
}
StringBuffer buffer = new StringBuffer();
while(res.moveToNext()){
buffer.append("ID : " + res.getString(0) + "\n");
buffer.append("Name : " + res.getString(1) + "\n");
buffer.append("Marks : " + res.getString(2) + "\n\n");
}
// Show data in a pop-up dialog
new AlertDialog.Builder(this)
.setCancelable(true)
.setTitle("Student Records")
.setMessage(buffer.toString())
.setPositiveButton("OK", null)
.show();
});
}
private void clearFields() {
etId.setText("");
etName.setText("");
etMarks.setText("");
}
}
3. res/layout/activity_main.xml (Added ScrollView so all 4 buttons are reachable)
XML
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp"
android:gravity="center_horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Student Database"
android:textSize="24sp"
android:textStyle="bold"
android:layout_marginBottom="20dp"/>
<EditText
android:id="@+id/etId"
android:hint="Enter Student ID"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:layout_marginBottom="10dp"/>
<EditText
android:id="@+id/etName"
android:hint="Enter Student Name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPersonName"
android:layout_marginBottom="10dp"/>
<EditText
android:id="@+id/etMarks"
android:hint="Enter Marks"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="numberDecimal"
android:layout_marginBottom="20dp"/>
<Button
android:id="@+id/btnAdd"
android:text="Insert Data"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/btnUpdate"
android:text="Update Data"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/btnDelete"
android:text="Delete Data"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/btnView"
android:text="View All Data"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="#4CAF50"/> </LinearLayout>
Assignment 9: Firebase Realtime Database.
CRITICAL PREREQUISITE: Before running this code, you must connect your Android Studio project to Firebase:
Go to Tools > Firebase.
Select Realtime Database > Get Started.
Click Connect to Firebase (Sign in to Google).
Click Add the Realtime Database SDK to your app (Accept Changes).
Important: Go to your Firebase Console (website) > Build > Realtime Database > Rules and set .read and .write to true (Test Mode).
Assignment 9: Employee Management (Firebase)
- AndroidManifest.xml (Add Internet permission)
XML
<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/Theme.AppCompat.Light">
<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>
2. Employee.java (Create this new Java class for data structure)
Java
package com.example.firebasedemo; // Check Package Name
public class Employee {
String id;
String name;
String role;
// Empty constructor is required for Firebase
public Employee() {
}
public Employee(String id, String name, String role) {
this.id = id;
this.name = name;
this.role = role;
}
public String getName() { return name; }
public String getRole() { return role; }
}
3. MainActivity.java (Includes fix to hide top bar)
Java
package com.example.firebasedemo; // Check Package Name
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
// Firebase Imports
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
public class MainActivity extends AppCompatActivity {
EditText etName, etRole;
TextView tvData;
DatabaseReference dbRef;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// --- HIDE TOP BAR ---
if (getSupportActionBar() != null) {
getSupportActionBar().hide();
}
etName = findViewById(R.id.etName);
etRole = findViewById(R.id.etRole);
tvData = findViewById(R.id.tvData);
// Initialize Firebase
// "Employees" is the name of the folder in the database
dbRef = FirebaseDatabase.getInstance().getReference("Employees");
// 1. INSERT DATA
findViewById(R.id.btnAdd).setOnClickListener(v -> {
String name = etName.getText().toString();
String role = etRole.getText().toString();
if(name.isEmpty() || role.isEmpty()){
Toast.makeText(this, "Please fill all fields", Toast.LENGTH_SHORT).show();
return;
}
// Generate unique key
String id = dbRef.push().getKey();
Employee emp = new Employee(id, name, role);
// Save to Firebase
dbRef.child(id).setValue(emp)
.addOnSuccessListener(aVoid -> {
Toast.makeText(this, "Employee Added", Toast.LENGTH_SHORT).show();
etName.setText("");
etRole.setText("");
})
.addOnFailureListener(e -> {
Toast.makeText(this, "Failed: " + e.getMessage(), Toast.LENGTH_SHORT).show();
});
});
// 2. READ DATA (Real-time Listener)
dbRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
StringBuilder sb = new StringBuilder();
sb.append("--- Employee List ---\n\n");
// Iterate through all children in "Employees" node
for(DataSnapshot ds : snapshot.getChildren()){
Employee emp = ds.getValue(Employee.class);
if(emp != null) {
sb.append("Name: ").append(emp.getName()).append("\n");
sb.append("Role: ").append(emp.getRole()).append("\n");
sb.append("----------------\n");
}
}
tvData.setText(sb.toString());
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
Toast.makeText(MainActivity.this, "Error: " + error.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
4. res/layout/activity_main.xml (Uses ScrollView to ensure everything is visible)
XML
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp"
android:gravity="center_horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Firebase Employee App"
android:textSize="24sp"
android:textStyle="bold"
android:layout_marginBottom="30dp"/>
<EditText
android:id="@+id/etName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter Employee Name"
android:inputType="textPersonName"
android:background="#F0F0F0"
android:padding="15dp"
android:layout_marginBottom="10dp"/>
<EditText
android:id="@+id/etRole"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter Job Role"
android:inputType="text"
android:background="#F0F0F0"
android:padding="15dp"
android:layout_marginBottom="20dp"/>
<Button
android:id="@+id/btnAdd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Add To Database"
android:backgroundTint="#FF5722"
android:textColor="#FFFFFF"/>
<TextView
android:id="@+id/tvData"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:textSize="16sp"
android:text="Loading Data..."
android:background="#FAFAFA"
android:padding="10dp"/>
</LinearLayout>
Assignment 9 (Firebase Employee App) with full Add, View, Update, and Delete functionality.
Follow these steps exactly in this order.
Phase 1: Firebase Setup (Do this first)
Connect Project: Go to Tools > Firebase > Realtime Database.
Click Connect to Firebase.
Click Add the Realtime Database SDK to your app.
Set Permissions (Crucial):
Go to Firebase Console.
Open your project > Realtime Database > Rules.
Change false to true and click Publish:
JSON
{
"rules": {
".read": true,
".write": true
}
}
Phase 2: The Android Code
Step 1: Add Permission
File: manifests/AndroidManifest.xml Add the internet permission line exactly above the tag.
XML
<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/Theme.AppCompat.Light">
<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>
Step 2: Create Model Class
File: Right-click package folder > New > Java Class > Name it Employee.
Java
package com.example.firebasedemo; // CHECK YOUR PACKAGE NAME
public class Employee {
String id;
String name;
String role;
// Empty constructor is required for Firebase
public Employee() {
}
public Employee(String id, String name, String role) {
this.id = id;
this.name = name;
this.role = role;
}
public String getId() { return id; }
public String getName() { return name; }
public String getRole() { return role; }
// This controls what text is shown in the ListView
@Override
public String toString() {
return name + " (" + role + ")";
}
}
Step 3: Create Layout (Fixes 'Cannot resolve symbol' error)
File: res/layout/activity_main.xml Copy all of this code and replace the content of the file.
XML
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Employee Manager"
android:textSize="24sp"
android:textStyle="bold"
android:gravity="center"
android:layout_marginBottom="20dp"
android:textColor="#333333"/>
<EditText
android:id="@+id/etName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter Name"
android:background="#FFFFFF"
android:padding="12dp"
android:layout_marginBottom="10dp"/>
<EditText
android:id="@+id/etRole"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter Role"
android:background="#FFFFFF"
android:padding="12dp"
android:layout_marginBottom="20dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="3"
android:layout_marginBottom="10dp">
<Button
android:id="@+id/btnAdd"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Add"
android:backgroundTint="#4CAF50"
android:layout_marginEnd="5dp"/>
<Button
android:id="@+id/btnUpdate"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Update"
android:backgroundTint="#2196F3"
android:layout_marginEnd="5dp"/>
<Button
android:id="@+id/btnDelete"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Delete"
android:backgroundTint="#F44336"/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Tap any item below to Select/Edit:"
android:textStyle="italic"
android:gravity="center"
android:layout_marginBottom="5dp"/>
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"/>
Step 4: The Main Logic
File: MainActivity.java
Java
package com.example.firebasedemo; // CHECK YOUR PACKAGE NAME
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
EditText etName, etRole;
Button btnAdd, btnUpdate, btnDelete;
ListView listView;
DatabaseReference dbRef;
List<Employee> employeeList;
ArrayAdapter<Employee> adapter;
String selectedId = null; // Stores ID of the employee we clicked on
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Hide the Action Bar
if (getSupportActionBar() != null) getSupportActionBar().hide();
// 1. Initialize Views
etName = findViewById(R.id.etName);
etRole = findViewById(R.id.etRole);
btnAdd = findViewById(R.id.btnAdd);
btnUpdate = findViewById(R.id.btnUpdate);
btnDelete = findViewById(R.id.btnDelete);
listView = findViewById(R.id.listView);
// 2. Setup List and Adapter
employeeList = new ArrayList<>();
adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, employeeList);
listView.setAdapter(adapter);
// 3. Connect to Database
dbRef = FirebaseDatabase.getInstance().getReference("Employees");
// --- ADD BUTTON ---
btnAdd.setOnClickListener(v -> {
String name = etName.getText().toString();
String role = etRole.getText().toString();
if (name.isEmpty() || role.isEmpty()) return;
String id = dbRef.push().getKey(); // Create new ID
Employee emp = new Employee(id, name, role);
dbRef.child(id).setValue(emp);
Toast.makeText(this, "Added", Toast.LENGTH_SHORT).show();
clearInputs();
});
// --- LIST ITEM CLICK (Select for Update/Delete) ---
listView.setOnItemClickListener((parent, view, position, id) -> {
Employee selectedEmp = employeeList.get(position);
// Fill boxes with data
etName.setText(selectedEmp.getName());
etRole.setText(selectedEmp.getRole());
// Save ID for later use
selectedId = selectedEmp.getId();
Toast.makeText(this, "Selected: " + selectedEmp.getName(), Toast.LENGTH_SHORT).show();
});
// --- UPDATE BUTTON ---
btnUpdate.setOnClickListener(v -> {
if (selectedId == null) {
Toast.makeText(this, "Select item first", Toast.LENGTH_SHORT).show();
return;
}
String name = etName.getText().toString();
String role = etRole.getText().toString();
Employee emp = new Employee(selectedId, name, role);
dbRef.child(selectedId).setValue(emp); // Overwrite data
Toast.makeText(this, "Updated", Toast.LENGTH_SHORT).show();
clearInputs();
});
// --- DELETE BUTTON ---
btnDelete.setOnClickListener(v -> {
if (selectedId == null) {
Toast.makeText(this, "Select item first", Toast.LENGTH_SHORT).show();
return;
}
dbRef.child(selectedId).removeValue(); // Delete data
Toast.makeText(this, "Deleted", Toast.LENGTH_SHORT).show();
clearInputs();
});
// --- REALTIME SYNC (View) ---
dbRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
employeeList.clear();
for (DataSnapshot ds : snapshot.getChildren()) {
Employee emp = ds.getValue(Employee.class);
employeeList.add(emp);
}
adapter.notifyDataSetChanged();
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
}
});
}
private void clearInputs() {
etName.setText("");
etRole.setText("");
selectedId = null;
}
}
Phase 3: Testing
Run the app.
Add: Type "Alex" and "Manager", click Add. (It appears in the list).
Select: Tap on "Alex" in the list. The text boxes will fill up.
Update: Change "Manager" to "Director", click Update. (List updates automatically).
Delete: Tap on "Alex", click Delete. (Item disappears).
Assignment 10: Image Animation & Processing
Requirement: Add an image named sample.jpg (or png) to res/drawable/ folder.
- res/layout/activity_main.xml
XML
<ImageView
android:id="@+id/imageView"
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@drawable/sample"
android:scaleType="centerCrop"/>
<LinearLayout android:orientation="horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content">
<Button android:id="@+id/btnRotate" android:text="Rotate" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
<Button android:id="@+id/btnZoom" android:text="Zoom" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
<Button android:id="@+id/btnGrey" android:text="Greyscale" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
</LinearLayout>
2. MainActivity.java
Java
package com.example.imagedemo;
import android.animation.ObjectAnimator;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.widget.Button;
import android.widget.ImageView;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
ImageView img;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
img = findViewById(R.id.imageView);
// 1. Animation: Rotate
findViewById(R.id.btnRotate).setOnClickListener(v -> {
ObjectAnimator anim = ObjectAnimator.ofFloat(img, "rotation", 0f, 360f);
anim.setDuration(1000);
anim.start();
});
// 2. Animation: Zoom (Scale)
findViewById(R.id.btnZoom).setOnClickListener(v -> {
ObjectAnimator scaleX = ObjectAnimator.ofFloat(img, "scaleX", 1f, 1.5f);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(img, "scaleY", 1f, 1.5f);
scaleX.setDuration(1000).start();
scaleY.setDuration(1000).start();
});
// 3. Processing: Greyscale (Pixel manipulation)
findViewById(R.id.btnGrey).setOnClickListener(v -> {
BitmapDrawable drawable = (BitmapDrawable) img.getDrawable();
Bitmap bitmap = drawable.getBitmap();
Bitmap newBitmap = toGrayscale(bitmap);
img.setImageBitmap(newBitmap);
});
}
private Bitmap toGrayscale(Bitmap bmpOriginal) {
int width, height;
height = bmpOriginal.getHeight();
width = bmpOriginal.getWidth();
Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
int pixel = bmpOriginal.getPixel(i, j);
int r = Color.red(pixel);
int g = Color.green(pixel);
int b = Color.blue(pixel);
// Standard Greyscale formula
int gray = (int) (0.299 * r + 0.587 * g + 0.114 * b);
bmpGrayscale.setPixel(i, j, Color.rgb(gray, gray, gray));
}
}
return bmpGrayscale;
}
}
Here are Assignments 11, 12, and 13 (Android). I have applied the fix (Hiding the Top Bar and using ScrollView) to all of them so they work on small screens.
I will provide the Flutter Assignments (14–17) in the next message to keep this organized.
Assignment 11: Audio & Video Player
Pre-requisites:
Create a folder: res > raw (Right-click res -> New -> Android Resource Directory -> Select raw).
Paste an audio file named audio.mp3 and a video file named video.mp4 into res/raw. (If you don't have them, the app will crash).
- res/layout/activity_main.xml
XML
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp"
android:gravity="center_horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Media Player"
android:textSize="24sp"
android:textStyle="bold"
android:layout_marginBottom="30dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Audio Player"
android:textStyle="bold"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"
android:layout_marginBottom="30dp">
<Button android:id="@+id/btnPlay" android:text="Play" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
<Button android:id="@+id/btnPause" android:text="Pause" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
<Button android:id="@+id/btnStop" android:text="Stop" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Video Player"
android:textStyle="bold"
android:layout_marginBottom="10dp"/>
<VideoView
android:id="@+id/videoView"
android:layout_width="match_parent"
android:layout_height="250dp"
android:layout_gravity="center"/>
</LinearLayout>
2. MainActivity.java
Java
package com.example.mediaplayer; // CHECK PACKAGE NAME
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.widget.Button;
import android.widget.MediaController;
import android.widget.VideoView;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
MediaPlayer mp;
VideoView vv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (getSupportActionBar() != null) getSupportActionBar().hide();
// --- AUDIO SETUP ---
// Ensure 'audio.mp3' exists in res/raw
mp = MediaPlayer.create(this, R.raw.audio);
Button btnPlay = findViewById(R.id.btnPlay);
Button btnPause = findViewById(R.id.btnPause);
Button btnStop = findViewById(R.id.btnStop);
btnPlay.setOnClickListener(v -> mp.start());
btnPause.setOnClickListener(v -> mp.pause());
btnStop.setOnClickListener(v -> {
mp.stop();
mp = MediaPlayer.create(this, R.raw.audio); // Reset after stop
});
// --- VIDEO SETUP ---
vv = findViewById(R.id.videoView);
// Ensure 'video.mp4' exists in res/raw
String videoPath = "android.resource://" + getPackageName() + "/" + R.raw.video;
Uri uri = Uri.parse(videoPath);
vv.setVideoURI(uri);
// Add controls (Play/Pause/Scrub bar) to the video
MediaController mediaController = new MediaController(this);
vv.setMediaController(mediaController);
mediaController.setAnchorView(vv);
}
}
Assignment 12: GPS Location
Pre-requisites:
Add permissions to AndroidManifest.xml.
Enable GPS on your phone/emulator before testing.
- AndroidManifest.xml
XML
<manifest ... >
<application ...>
...
</application>
2. res/layout/activity_main.xml
XML
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp"
android:gravity="center">
<Button
android:id="@+id/btnGetLoc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Get Current Location"
android:backgroundTint="#FF6200EB"/>
<TextView
android:id="@+id/tvLat"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="Latitude: "
android:textSize="18sp"/>
<TextView
android:id="@+id/tvLong"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="Longitude: "
android:textSize="18sp"/>
<TextView
android:id="@+id/tvAddress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="Address: "
android:textSize="18sp"/>
</LinearLayout>
3. MainActivity.java
Java
package com.example.gpsdemo;
import android.Manifest;
import android.content.pm.PackageManager;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.util.List;
import java.util.Locale;
public class MainActivity extends AppCompatActivity implements LocationListener {
Button btnGetLoc;
TextView tvLat, tvLong, tvAddress;
LocationManager locationManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (getSupportActionBar() != null) getSupportActionBar().hide();
btnGetLoc = findViewById(R.id.btnGetLoc);
tvLat = findViewById(R.id.tvLat);
tvLong = findViewById(R.id.tvLong);
tvAddress = findViewById(R.id.tvAddress);
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
btnGetLoc.setOnClickListener(v -> getLocation());
}
private void getLocation() {
// Check Runtime Permission
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 100);
} else {
try {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 5, this);
Toast.makeText(this, "Fetching Location...", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public void onLocationChanged(@NonNull Location location) {
tvLat.setText("Latitude: " + location.getLatitude());
tvLong.setText("Longitude: " + location.getLongitude());
try {
Geocoder geocoder = new Geocoder(this, Locale.getDefault());
List<Address> addresses = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1);
if (!addresses.isEmpty()) {
tvAddress.setText("Address: " + addresses.get(0).getAddressLine(0));
}
} catch (Exception e) {
tvAddress.setText("Address: Could not fetch");
}
}
// Required empty methods
@Override public void onStatusChanged(String provider, int status, Bundle extras) {}
@Override public void onProviderEnabled(@NonNull String provider) {}
@Override public void onProviderDisabled(@NonNull String provider) {}
}
Assignment 13: REST API (Volley)
Goal: Fetch data from a test API (jsonplaceholder.typicode.com). Pre-requisites:
Dependencies: Open build.gradle (Module: app) and add this inside dependencies { ... }: implementation 'com.android.volley:volley:1.2.1' (Then click "Sync Now").
Permission: Add in AndroidManifest.xml.
- res/layout/activity_main.xml
XML
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp">
<Button
android:id="@+id/btnFetch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Fetch Data from API" />
<TextView
android:id="@+id/tvResult"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="Data will appear here..."
android:textSize="16sp"/>
</LinearLayout>
2. MainActivity.java
Java
package com.example.restapi;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonArrayRequest;
import com.android.volley.toolbox.Volley;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class MainActivity extends AppCompatActivity {
Button btnFetch;
TextView tvResult;
String url = "https://jsonplaceholder.typicode.com/users";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (getSupportActionBar() != null) getSupportActionBar().hide();
btnFetch = findViewById(R.id.btnFetch);
tvResult = findViewById(R.id.tvResult);
btnFetch.setOnClickListener(v -> getData());
}
private void getData() {
RequestQueue queue = Volley.newRequestQueue(this);
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(Request.Method.GET, url, null,
new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray response) {
StringBuilder sb = new StringBuilder();
try {
for (int i = 0; i < response.length(); i++) {
JSONObject user = response.getJSONObject(i);
String name = user.getString("name");
String email = user.getString("email");
sb.append("Name: ").append(name).append("\n");
sb.append("Email: ").append(email).append("\n\n");
}
tvResult.setText(sb.toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(MainActivity.this, "Error Fetching Data", Toast.LENGTH_SHORT).show();
}
});
queue.add(jsonArrayRequest);
}
}
Assignment 14. This covers exactly what you did to get it running, the final code, and an explanation of how it works for your Viva.
Assignment 14: Flutter BMI Calculator
- Project Setup Steps
Open Android Studio.
Go to File > New > New Flutter Project.
Project Name: bmi_calculator (lowercase, no spaces).
Platforms (Crucial):
✅ Check: Android.
⬜ Uncheck: iOS, macOS, Web (to prevent errors).
Click Create.
- The Code
File Location: lib/main.dart
Action: Delete all existing code in that file and paste this:
Dart
import 'package:flutter/material.dart';
// 1. The Entry Point
void main() {
runApp(const MaterialApp(
debugShowCheckedModeBanner: false,
home: BmiCalculator(), // Opens our Calculator Screen
));
}
// 2. The Main Screen (Stateful because data changes)
class BmiCalculator extends StatefulWidget {
const BmiCalculator({super.key});
@override
State createState() => _BmiCalculatorState();
}
class _BmiCalculatorState extends State {
// 3. Controllers to retrieve text from Input Fields
final TextEditingController heightController = TextEditingController();
final TextEditingController weightController = TextEditingController();
// Variables to store output
double result = 0;
String msg = "";
// 4. The Logic Function
void calculateBMI() {
// Validation: Don't run if empty
if(heightController.text.isEmpty || weightController.text.isEmpty) return;
// Get inputs (Parse String to Double)
double h = double.parse(heightController.text) / 100; // Convert cm to meters
double w = double.parse(weightController.text);
// Logic: Weight / (Height * Height)
setState(() {
result = w / (h * h);
// Categorize result
if (result < 18.5) {
msg = "Underweight";
} else if (result < 25) {
msg = "Healthy";
} else {
msg = "Overweight";
}
});
}
// 5. The UI Design (Build Method)
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("BMI Calculator"), backgroundColor: Colors.blue),
// SingleChildScrollView fixes "Pixel Overflow" error on small screens
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
// Height Input
TextField(
controller: heightController,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
labelText: "Height (cm)",
border: OutlineInputBorder()
),
),
const SizedBox(height: 20), // Spacing
// Weight Input
TextField(
controller: weightController,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
labelText: "Weight (kg)",
border: OutlineInputBorder()
),
),
const SizedBox(height: 30),
// Calculate Button
ElevatedButton(
onPressed: calculateBMI,
child: const Text("Calculate BMI"),
style: ElevatedButton.styleFrom(minimumSize: const Size(double.infinity, 50)),
),
const SizedBox(height: 30),
// Display Result
Text(
"BMI: ${result.toStringAsFixed(2)}",
style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold)
),
Text(
msg,
style: TextStyle(
fontSize: 22,
color: msg == "Healthy" ? Colors.green : Colors.red,
fontWeight: FontWeight.bold
)
),
],
),
),
),
);
}
}
3. Code Explanation (For Viva)
main(): The starting point. It runs MaterialApp, which is the root of a Flutter app.
StatefulWidget: We use this because the screen needs to update (change state) when we calculate the result. If we used StatelessWidget, the result text would never update on the screen.
TextEditingController: These are "listeners" attached to the TextFields. They allow us to read what the user typed (heightController.text).
setState(): This is the most important command. It tells Flutter: "Data has changed! Please redraw the screen immediately." Without this, the variables would update in the background, but the user would still see "0".
SingleChildScrollView: A wrapper that makes the screen scrollable. This prevents the "Yellow/Black error bars" if the keyboard pops up and covers the inputs.
- How to Run
Ensure your Emulator is selected in the top toolbar.
Click the Green Play Button.
Here is the complete, structured guide for Assignment 15.
Assignment 15: Flutter Registration Form
Goal: Create a form with different types of inputs (Text, Radio, Dropdown, Checkbox) and pass that data to a second screen.
- Project Setup Steps
Option A (Fastest): You can simply overwrite the lib/main.dart file in your existing bmi_calculator project.
Option B (New Project):
File > New > New Flutter Project.
Name: registration_form (lowercase).
Platforms: Check Android only.
Click Create.
- The Code
File Location: lib/main.dart
Action: Delete everything and paste this code.
Dart
import 'package:flutter/material.dart';
// 1. Entry Point
void main() {
runApp(const MaterialApp(
debugShowCheckedModeBanner: false,
home: RegisterPage(), // Start at the Form Screen
));
}
// --- SCREEN 1: The Input Form ---
class RegisterPage extends StatefulWidget {
const RegisterPage({super.key});
@override
State createState() => _RegisterPageState();
}
class _RegisterPageState extends State {
// Controller for Text Input
final TextEditingController nameController = TextEditingController();
// Variables to hold current selection
String gender = "Male";
String city = "Mumbai";
bool isCoder = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Registration"), backgroundColor: Colors.purple),
body: SingleChildScrollView( // Prevents keyboard overflow issues
padding: const EdgeInsets.all(20),
child: Column(
children: [
// 1. Text Field
TextField(
controller: nameController,
decoration: const InputDecoration(labelText: "Enter Name", border: OutlineInputBorder())
),
const SizedBox(height: 20),
// 2. Radio Buttons (Gender)
const Align(alignment: Alignment.centerLeft, child: Text("Select Gender:", style: TextStyle(fontWeight: FontWeight.bold))),
Row(
children: [
Radio(
value: "Male",
groupValue: gender,
onChanged: (val) => setState(() => gender = val.toString())
),
const Text("Male"),
Radio(
value: "Female",
groupValue: gender,
onChanged: (val) => setState(() => gender = val.toString())
),
const Text("Female"),
],
),
const SizedBox(height: 10),
// 3. Dropdown Menu (City)
const Align(alignment: Alignment.centerLeft, child: Text("Select City:", style: TextStyle(fontWeight: FontWeight.bold))),
DropdownButton<String>(
value: city,
isExpanded: true, // Make it full width
// Map list of strings to DropdownMenuItem widgets
items: ["Mumbai", "Delhi", "Pune", "Bangalore"].map((String val) {
return DropdownMenuItem(value: val, child: Text(val));
}).toList(),
onChanged: (val) => setState(() => city = val!),
),
const SizedBox(height: 10),
// 4. Checkbox (Skills)
CheckboxListTile(
title: const Text("I know Coding"),
value: isCoder,
onChanged: (val) => setState(() => isCoder = val!),
controlAffinity: ListTileControlAffinity.leading, // Checkbox on left
),
const SizedBox(height: 30),
// 5. Submit Button & Navigation
ElevatedButton(
style: ElevatedButton.styleFrom(minimumSize: const Size(double.infinity, 50), backgroundColor: Colors.purple),
onPressed: () {
// Validation
if (nameController.text.isEmpty) return;
// NAVIGATE AND PASS DATA
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ResultPage(
name: nameController.text,
gender: gender,
city: city,
isCoder: isCoder,
)),
);
},
child: const Text("Submit", style: TextStyle(color: Colors.white, fontSize: 18)),
)
],
),
),
);
}
}
// --- SCREEN 2: Result Display ---
class ResultPage extends StatelessWidget {
// Variables to receive data
final String name, gender, city;
final bool isCoder;
// Constructor: This is how data enters this screen
const ResultPage({
super.key,
required this.name,
required this.gender,
required this.city,
required this.isCoder
});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Submission Details"), backgroundColor: Colors.teal),
body: Center(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Card(
elevation: 5, // Shadow effect
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisSize: MainAxisSize.min, // Wrap content tightly
children: [
Text("Name: $name", style: const TextStyle(fontSize: 20)),
const SizedBox(height: 10),
Text("Gender: $gender", style: const TextStyle(fontSize: 20)),
const SizedBox(height: 10),
Text("City: $city", style: const TextStyle(fontSize: 20)),
const SizedBox(height: 10),
Text("Skills: ${isCoder ? "Coder" : "None"}", style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
const SizedBox(height: 20),
// Go Back Button
ElevatedButton(
onPressed: () => Navigator.pop(context),
child: const Text("Go Back")
)
],
),
),
),
),
),
);
}
}
3. Code Explanation (For Viva)
Navigator.push: This command puts a new screen on top of the current screen (like a stack of cards).
MaterialPageRoute: This handles the animation of sliding the new screen in (standard Android/iOS transition).
Passing Data (The Constructor):
In ResultPage, we defined variables (final String name...) and a Constructor (required this.name...).
When we call ResultPage(...) inside Navigator.push, we are actually creating the screen object and handing it the data before it gets displayed.
Navigator.pop(context): This removes the top screen (ResultPage) and goes back to the previous screen (RegisterPage).
Widgets Used:
Radio: Used groupValue to ensure only one circle is selected at a time.
DropdownButton: Requires a list of items (DropdownMenuItem) and an onChanged function to update the selected value.
- How to Run
Ensure Emulator is running.
Click the Green Play Button.
Fill out the form and click Submit. You should see the second screen with your details.
ssignment 16: Flutter Database (SQFlite)
Goal: Create a Note-taking app where data persists (remains saved) even after you close the app, using a local SQLite database.
- Project Setup & Dependencies (CRITICAL)
Unlike previous assignments, this one requires external libraries (plugins).
Create New Project: Name it sqflite_demo (lowercase).
Open pubspec.yaml: Find this file in the project folder list on the left.
Add Dependencies: Scroll down to dependencies: and add sqflite and path_provider. It should look exactly like this (indentation matters!):
YAML
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
ADD THESE TWO LINES:
sqflite: ^2.3.0
path_provider: ^2.1.1
Download: Click the "Pub get" button at the top of the screen (or run flutter pub get in terminal).
- The Code
File Location: lib/main.dart
Action: Delete everything and paste this code.
Dart
import 'package:flutter/material.dart';
// Imports for Database functionality
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io';
import 'package:path/path.dart';
void main() {
runApp(const MaterialApp(
debugShowCheckedModeBanner: false,
home: DatabaseApp(),
));
}
class DatabaseApp extends StatefulWidget {
const DatabaseApp({super.key});
@override
State createState() => _DatabaseAppState();
}
class _DatabaseAppState extends State {
final TextEditingController _controller = TextEditingController();
// Variable to hold the database connection
Database? _database;
// List to hold the notes fetched from DB
List<Map<String, dynamic>> _notes = [];
@override
void initState() {
super.initState();
_initDatabase(); // Start DB when app launches
}
// --- 1. INITIALIZE DATABASE ---
Future _initDatabase() async {
// Get the safe folder on the phone to store files
Directory documentsDirectory = await getApplicationDocumentsDirectory();
// Create path: .../Documents/notes.db
String path = join(documentsDirectory.path, "notes.db");
// Open DB (and create table if it doesn't exist)
_database = await openDatabase(
path,
version: 1,
onCreate: (db, version) {
return db.execute("CREATE TABLE Notes (id INTEGER PRIMARY KEY, content TEXT)");
}
);
// Load existing notes
_refreshNotes();
}
// --- 2. CREATE (Insert) ---
Future _addNote() async {
if (_controller.text.isEmpty) return;
await _database?.insert('Notes', {
'content': _controller.text
});
_controller.clear(); // Clear input box
_refreshNotes(); // Reload list
}
// --- 3. READ (Query) ---
Future _refreshNotes() async {
// Get all rows from the table
final data = await _database?.query('Notes');
setState(() {
_notes = data ?? [];
});
}
// --- 4. DELETE ---
Future _deleteNote(int id) async {
await _database?.delete('Notes', where: 'id = ?', whereArgs: [id]);
_refreshNotes();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("My Notes (SQLite)"), backgroundColor: Colors.orange),
body: Column(
children: [
// Input Area
Padding(
padding: const EdgeInsets.all(15.0),
child: Row(
children: [
Expanded(
child: TextField(
controller: _controller,
decoration: const InputDecoration(
hintText: "Enter a new note",
border: OutlineInputBorder()
)
)
),
const SizedBox(width: 10),
ElevatedButton(
onPressed: _addNote,
style: ElevatedButton.styleFrom(backgroundColor: Colors.orange),
child: const Icon(Icons.add, color: Colors.white),
),
],
),
),
const Divider(thickness: 2),
// List of Notes
Expanded(
child: ListView.builder(
itemCount: _notes.length,
itemBuilder: (context, index) {
return Card(
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
child: ListTile(
// Display the content
title: Text(_notes[index]['content']),
// Delete Button
trailing: IconButton(
icon: const Icon(Icons.delete, color: Colors.red),
onPressed: () => _deleteNote(_notes[index]['id']),
),
),
);
},
),
)
],
),
);
}
}
3. Code Explanation (For Viva)
sqflite Plugin: This allows Flutter to talk to the native SQLite database engine inside Android/iOS.
path_provider Plugin: Android phones have specific folders where apps are allowed to save files. We can't just save to "C:/". This plugin finds the correct, safe folder (getApplicationDocumentsDirectory).
async and await: Database operations (opening, writing, reading) are slow compared to drawing the UI.
If we ran them normally, the app would freeze/hang while saving.
await means: "Pause this specific function here, let the app keep running, and come back when the database is done."
Future: This is the return type for async functions. It's like a "Promise" that a result will arrive later.
onCreate: This only runs once—the very first time the app is installed and run. This is where we write the SQL CREATE TABLE command.
- How to Run
Stop the app if it is currently running (Red Square button).
Run the app again (Green Play button) to ensure the new dependencies are loaded.
Test:
Type "Buy Milk" and click Add (+).
Type "Call Mom" and click Add (+).
Close the app completely (Stop button).
Run it again.
Result: The notes should still be there! (This proves the database works).
Great job getting the database assignment working! That was the hardest one.
Here is the Final Assignment (Assignment 17): Flutter REST API.
Goal: Fetch data from the internet (a list of fake users) and display it in a list.
Assignment 17: Flutter REST API
Step 1: Add the Dependency (Crucial)
We need a library called http to make network requests.
Open pubspec.yaml.
Scroll to dependencies:.
Add http: ^1.1.0 under flutter:.
Important: You can remove sqflite and path_provider if you want, or just add http below them.
It should look like this:
YAML
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
ADD THIS LINE:
http: ^1.1.0
Click Pub get (or run flutter pub get in terminal).
Step 2: The Code
File Location: lib/main.dart
Action: Delete everything and paste this code.
Dart
import 'package:flutter/material.dart';
import 'dart:convert'; // To convert JSON text to Lists/Maps
import 'package:http/http.dart' as http; // To make network requests
void main() {
runApp(const MaterialApp(
debugShowCheckedModeBanner: false,
home: ApiPage(),
));
}
class ApiPage extends StatefulWidget {
const ApiPage({super.key});
@override
State createState() => _ApiPageState();
}
class _ApiPageState extends State {
// List to store the fetched data
List users = [];
// Boolean to track if we are currently loading
bool isLoading = false;
@override
void initState() {
super.initState();
fetchUsers(); // Auto-load data when app starts
}
// --- THE API LOGIC ---
Future fetchUsers() async {
setState(() {
isLoading = true; // Show loading spinner
});
// 1. Make the Network Request
// We use a test API that gives free fake data
final url = Uri.parse('https://jsonplaceholder.typicode.com/users');
final response = await http.get(url);
// 2. Check if successful (200 OK)
if (response.statusCode == 200) {
setState(() {
// 3. Decode the JSON string into a Dart List
users = json.decode(response.body);
isLoading = false; // Hide spinner
});
} else {
setState(() => isLoading = false);
throw Exception('Failed to load users');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("REST API Call"), backgroundColor: Colors.indigo),
body: isLoading
? const Center(child: CircularProgressIndicator()) // Show Spinner if loading
: ListView.builder( // Show List if data is ready
itemCount: users.length,
itemBuilder: (context, index) {
final user = users[index];
return Card(
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
elevation: 3,
child: ListTile(
// Circle with first letter of name
leading: CircleAvatar(
backgroundColor: Colors.indigo,
child: Text(user['name'][0], style: const TextStyle(color: Colors.white)),
),
title: Text(user['name'], style: const TextStyle(fontWeight: FontWeight.bold)),
subtitle: Text(user['email']),
trailing: const Icon(Icons.arrow_forward_ios, size: 16),
),
);
},
),
);
}
}
Step 3: Code Explanation (For Viva)
http.get(): This sends a request to the server asking for data (like typing a URL in a browser).
async / await: Network calls take time (milliseconds or seconds). await pauses the code until the data arrives so the app doesn't crash.
json.decode(): The internet sends data as a long String (JSON). This function converts that String into a Dart List so we can access user['name'] or user['email'].
isLoading: This is a simple flag.
When true: We show a CircularProgressIndicator (spinner).
When false: We show the ListView.
initState(): This function runs automatically once when the screen loads. We call fetchUsers() here so the user sees data immediately without pressing a button.
Step 4: Run It
Make sure your Emulator has an Internet Connection (usually it shares your computer's Wi-Fi).
Click Run.
You should briefly see a spinning circle, and then a list of names (Leanne Graham, Ervin Howell, etc.).
Viva:
This is a comprehensive set of Viva Preparation Notes based on the assignments you uploaded. Since there are 17 assignments covering Android (Java) and Flutter, I have divided this into logical parts to ensure high detail.
Here is Part 1, covering Android Basics, Intents, Storage, and System Components (Assignments 1–7).
Assignment 1: Calculator
Goal: Create a basic calculator handling Addition, Subtraction, Multiplication, and Division.
Key Concepts:
Event Handling: Using OnClickListener to detect button presses.
String Manipulation: Concatenating strings to form numbers and parsing them using Double.parseDouble.
Logic: The code uses boolean flags (isAddition, isSubtraction) to track which operator was pressed.
Code Highlight:
The calculation logic splits the string based on the operator (e.g., expression.split("\+")) to separate the two numbers.
Input Validation: It checks for division by zero.
Viva Questions:
Q: Why do we use Double.parseDouble()?
A: TextFields/TextViews return Strings. We must convert them to doubles to perform arithmetic.
Q: Why do we need try-catch in the calculation block?
A: To handle exceptions like invalid formats or division by zero, preventing the app from crashing.
Q: What is R.id?
A: It is a resource ID class generated effectively to identify views (like buttons and textviews) in the Java code.
Assignment 2: Currency Converter
Goal: Convert amounts between 5 currencies (INR, USD, EUR, JPY, GBP) using a spinner.
Key Concepts:
Spinner: A dropdown menu in Android. Requires an ArrayAdapter to populate data.
2D Array: The logic uses a 2D double[][] array to store conversion rates relative to one another.
Code Highlight:
conversionRates[fromIndex][toIndex] retrieves the specific rate based on the spinner positions.
Viva Questions:
Q: What is an Adapter in Android?
A: An Adapter acts as a bridge between the UI component (Spinner/ListView) and the underlying data source (Array/List).
Q: How do you get the selected item from a Spinner?
A: Using spinner.getSelectedItemPosition() or spinner.getSelectedItem().toString().
Assignment 3: Explicit Intent (Registration Form)
Goal: Pass complex data (Strings, Booleans, Integers) from one Activity to another.
Key Concepts:
Explicit Intent: Used to start a specific component (Activity) within the same app.
Bundle/Extras: Data is attached to the intent using putExtra.
UI Components: Using RadioGroup for single choice , CheckBox for multiple choices, SeekBar for range, and Switch.
Code Highlight:
Sender: intent.putExtra("key", value);
Receiver: getIntent().getStringExtra("key"); or getBooleanExtra("key", false);.
Viva Questions:
Q: What is the difference between Explicit and Implicit Intents?
A: Explicit starts a specific class (Activity A -> Activity B). Implicit requests an action (Open Webpage) and lets the system find the best app.
Q: What happens if you don't provide a default value in getIntExtra?
A: It is mandatory to provide a default value (e.g., 0) to prevent errors if the key doesn't exist.
Assignment 4: Implicit Intent
Goal: Interact with other applications (Browser, SMS, Dialer, Other Apps).
Key Concepts:
URI Parsing: Formatting strings into URIs (e.g., 12345, smsto:12345, http://...).
Intent Actions:
Intent.ACTION_VIEW: Open a URL.
Intent.ACTION_SENDTO: Send SMS/Email to specific person.
Intent.ACTION_DIAL: Open dialer.
Intent.ACTION_SEND: Share content to any compatible app.
Code Highlight:
The "Receiver App" uses an intent-filter with in the Manifest to accept implicit intents.
Viva Questions:
Q: What is an Intent Filter?
A: It defines the capabilities of a component (Activity), telling the Android system what kind of implicit intents it can handle.
Q: Difference between ACTION_DIAL and ACTION_CALL?
A: DIAL opens the keypad with the number typed in. CALL initiates the call immediately (requires permission).
Assignment 5: Shared Preferences
Goal: Create a Login system that remembers the username and handles security (wrong attempts).
Key Concepts:
SharedPreferences: Used to store small amounts of primitive data (Key-Value pairs) in an XML file.
Mode Private: File is only accessible by the calling application.
Logic: Tracks counter for wrong attempts. Disables login button after 3 failures.
Code Highlight:
Writing: editor.putString("user", val); editor.commit();.
Reading: sp.getString("user", "");.
File Path: Stored at /data/data/package_name/shared_prefs/.
Viva Questions:
Q: commit() vs apply()?
A: commit() writes data synchronously (blocks main thread, returns boolean). apply() writes asynchronously (faster, void return).
Q: Is SharedPreferences secure for storing passwords?
A: No, because it's a simple XML file. For real apps, use EncryptedSharedPreferences or Keystore.
Assignment 6: Notification
Goal: Trigger a notification that opens a website when clicked.
Key Concepts:
Notification Channel (Android 8.0+): Essential for notifications to appear. Groups notifications by type.
NotificationManager: System service to issue notifications.
PendingIntent: Wraps a regular intent (ACTION_VIEW for website) to be executed later when the user clicks the notification.
Code Highlight:
Requires permission: .
setAutoCancel(true) ensures the notification disappears after clicking.
Viva Questions:
Q: What is a PendingIntent?
A: It is a token given to another application (like the Notification Manager) allowing it to execute your intent with your app's permissions at a later time.
Q: Why is a Notification Channel required?
A: Starting Android Oreo, channels allow users to customize settings (sound, vibration) for specific categories of notifications within an app.
Assignment 7: File Storage (Internal & External)
Goal: Save and retrieve text files from Internal Storage (private) and External Storage (public/SD card).
Key Concepts:
Internal Storage: openFileOutput and openFileInput. Private to the app. Deleted if app is uninstalled.
External Storage: Checks Environment.getExternalStorageState() to see if media is mounted. Uses standard Java File, FileInputStream, and FileOutputStream.
Code Highlight:
Internal Path: /data/data/package_name/files/.
External Path: /sdcard/Android/data/package_name/files/.
Uses InputStreamReader and BufferedReader to read text line by line.
Viva Questions:
Q: Difference between Internal and External storage?
A: Internal is always available and private. External might be removable (SD card) and permissions are managed differently.
Q: Why do we use MODE_PRIVATE?
A: To ensure other apps cannot access the file created by this app.
Would you like me to proceed to Part 2 (Databases: SQLite & Firebase, Audio/Video, and GPS)?
yes
Here is Part 2 of the Viva Preparation Notes, covering Advanced Android topics: Databases (SQLite & Firebase), Media, Graphics, Location, and Networking (Assignments 8–13).
Assignment 8: SQLite Database
Goal: Implement a local database for a Student Management System with CRUD (Create, Read, Update, Delete) operations.
Key Concepts:
SQLiteOpenHelper: A helper class to manage database creation and version management.
ContentValues: A key-value store used to insert or update rows in the database table.
Cursor: An interface that provides random read-write access to the result set returned by a database query.
Code Highlight:
Creating Table: db.execSQL("CREATE TABLE ...") inside the onCreate method.
Inserting: db.insert(TAB_NAME, null, cv) where cv holds the data.
Reading: db.rawQuery("SELECT * FROM ...", null) returns a Cursor.
Viva Questions:
Q: What is the difference between getWritableDatabase() and getReadableDatabase()?
A: getWritableDatabase() opens the database for reading and writing. getReadableDatabase() opens it for reading only (and will fail if disk is full, whereas writable might throw an error immediately).
Q: Why do we need the moveToNext() method in a Cursor?
A: The Cursor starts before the first record. moveToNext() moves it to the first row (and subsequent rows) so data can be read.
Q: What happens if you don't close the Cursor (c.close())?
A: It can lead to memory leaks and reduce application performance.
Assignment 9: Firebase Realtime Database
Goal: Create a cloud-based Employee management system that syncs data in real-time.
Key Concepts:
NoSQL Database: Firebase stores data as a JSON tree, not tables/rows like SQLite.
DatabaseReference: Represents a specific location in your Database and is used for reading or writing data to that location.
Asynchronous: Data retrieval happens in the background using listeners.
Code Highlight:
Push ID: dbRef.push().getKey() generates a unique, time-based ID for new records.
Permissions: Requires internet permission and google-services.json file.
Listener: ValueEventListener with onDataChange is used to read data whenever it changes on the server.
Viva Questions:
Q: What is the google-services.json file?
A: It is a configuration file downloaded from the Firebase Console that connects your specific Android app to your Firebase project resources.
Q: How is Firebase different from SQLite?
A: SQLite is local (offline) and relational (SQL). Firebase is cloud-based (online), real-time, and NoSQL (JSON).
Q: What does dbRef.child(id).setValue(emp) do?
A: It writes the emp object to the specific path defined by id, overwriting any existing data at that path.
Assignment 10: Image Animation & Processing
Goal: Perform animations (Translate, Rotate, Scale, Fade) and pixel manipulation (Invert, Monochrome) on an image.
Key Concepts:
ObjectAnimator: A subclass of ValueAnimator that provides support for animating properties on target objects (like View.ALPHA or rotation).
Bitmap: A representation of an image that allows direct access to pixel data.
Pixel Manipulation: extracting ARGB (Alpha, Red, Green, Blue) values from a pixel integer.
Code Highlight:
Animation: ObjectAnimator.ofFloat(img, "rotation", 0f, 270f).
Greyscale Formula: (int)(0.299R + 0.587G + 0.114*B) is the standard luminosity formula for converting color to greyscale.
Inverting: 255 - Color.red(pixel) inverts the color channel.
Viva Questions:
Q: What is the difference between a Drawable and a Bitmap?
A: A Drawable is a general abstraction for "something that can be drawn." A Bitmap is a specific type of image storage containing actual pixel data.
Q: Why use AnimatorSet?
A: It allows you to play multiple animations together (simultaneously) or sequentially.
Assignment 11: Audio & Video Player
Goal: Play multimedia files using Android's media classes.
Key Concepts:
MediaPlayer: The primary API for playing sound and audio.
VideoView: A specialized View wrapper that handles both the video display surface and the media playback.
MediaController: A view containing media controls (play, pause, seek bar) to control a video.
Code Highlight:
Audio: MediaPlayer.create(context, R.raw.sample) initializes the player.
Video: vv.setVideoURI(uri) sets the source, and vv.start() begins playback.
Viva Questions:
Q: Where do you store local audio/video files in Android Studio?
A: In the res/raw folder. This folder is for raw assets that are not compiled into binary XML.
Q: Why should you call mp.release()?
A: To free up system resources (memory and hardware codecs) when the media player is no longer needed.
Assignment 12: GPS Location
Goal: Retrieve and display the user's current Latitude, Longitude, and Physical Address.
Key Concepts:
LocationManager: System service that provides access to the system location services.
Geocoder: A class for handling geocoding (coordinate to address) and reverse geocoding.
Permissions: Requires ACCESS_FINE_LOCATION (GPS) and ACCESS_COARSE_LOCATION (Network) in Manifest.
Code Highlight:
checkSelfPermission is critical to handle runtime permissions (mandatory since Android 6.0).
manager.requestLocationUpdates(LocationManager.GPS_PROVIDER, ...) requests periodic updates.
Viva Questions:
Q: What is the difference between Fine and Coarse location?
A: Fine uses GPS (precise). Coarse uses WiFi/Cell Towers (approximate, battery efficient).
Q: What is Geocoding?
A: Converting a street address into latitude/longitude coordinates. This assignment uses Reverse Geocoding (Lat/Long to Address).
Assignment 13: REST API (Fetching Data)
Goal: Fetch JSON data from a web URL using three different libraries: Volley, OkHttp, and Retrofit.
Key Concepts:
REST API: Representational State Transfer. It allows apps to communicate with servers using HTTP methods (GET, POST).
JSON Parsing: Converting the String response from the server into usable Java objects (JSONObject/JSONArray).
Libraries Comparison:
Volley: Google's library. Good for small, fast requests. Uses RequestQueue.
OkHttp: Efficient HTTP client. Handles connection pooling. Uses client.newCall(req).enqueue.
Retrofit: Type-safe HTTP client. Uses Interfaces and Annotations (@GET) to define endpoints. Automatically converts JSON to Java Objects (POJOs) using GSON.
Viva Questions:
Q: Which permission is required for API calls?
A: android.permission.INTERNET.
Q: Why is Retrofit considered "Type-safe"?
A: It maps the API directly to Java/Kotlin interfaces and classes, ensuring that the data types match at compile time, reducing runtime errors.
Q: What is the role of GSON?
A: It is a serialization/deserialization library that converts JSON strings into Java Objects and vice-versa.
Would you like me to proceed to Part 3 (Flutter Development: Basics, Forms, Databases, and APIs)?
yes
Here is Part 3 of the Viva Preparation Notes, covering the transition to Flutter Development (Assignments 14–17).
Assignment 14: Flutter BMI Calculator
Goal: Create a Flutter app to calculate Body Mass Index (BMI).
Key Concepts:
StatefulWidget: Used here because the result (s) changes based on user input, requiring the UI to redraw (setState).
TextEditingController: Used to manage and retrieve text from TextField widgets.
setState: The method that tells the Flutter framework to rebuild the widget tree because some data has changed.
Code Highlight (Dart/Flutter):
double.parse(textwcon.text) ?? 0; handles conversion from String to Double, using the null-aware operator (?? 0) to provide a default value.
TextInputType.number in TextField ensures the correct keyboard pops up.
Viva Questions:
Q: What is the difference between a StatelessWidget and a StatefulWidget?
A: Stateless widgets have no mutable state (their properties are immutable). Stateful widgets have a mutable state that can change over the lifetime of the widget, triggering UI updates via setState().
Q: What is the role of the build method?
A: The build method is responsible for returning a widget tree—a description of the UI—based on the current state and configuration.
Q: What is Hot Reload in Flutter?
A: A development feature that injects updated source code files into the running Dart Virtual Machine (VM) without restarting the app or losing the current state.
Assignment 15: Flutter Registration Form
Goal: Pass data between two screens (Registration and Result) using various input widgets.
Key Concepts:
Navigation (Navigator.push): Used to move from the main page to the ResultPage.
Widget Types:
TextField (for Name)
RadioListTile (for Gender)
DropdownButton (for City selection)
CheckboxListTile (for Languages)
SwitchListTile (for changing the background color/theme).
Constructor (in ResultPage): The data (name, gender, etc.) is passed to the next screen via the ResultPage's constructor.
Code Highlight:
Navigator.push(context, MaterialPageRoute(builder: (context) => ResultPage(...))) is the standard way to transition to a new screen.
The SwitchListTile uses setState to toggle the _darkbkgrd boolean, which immediately changes the Scaffold's backgroundColor.
Viva Questions:
Q: How do you pass data between screens in Flutter?
A: By passing the data to the constructor of the destination Widget (as done in ResultPage).
Q: What is a Scaffold?
A: It is a framework that provides basic structure (App Bar, Body, Floating Action Button, Drawers, etc.) for a mobile screen.
Q: What are MaterialApp and CupertinoApp?
A: They are the root widgets that define the app's overall structure, themes, and navigation, providing Google's Material Design and Apple's Cupertino (iOS) look and feel, respectively.
Assignment 16: Flutter SQFlite Database
Goal: Implement local CRUD operations using the sqflite plugin.
Key Concepts:
SQFlite: A Flutter plugin that provides access to SQLite databases on Android and iOS.
path_provider: Plugin used to find the correct platform-specific directory (application documents) to store the database file.
Async/Await: All database operations are asynchronous (Future) and must be handled using await or .then().
Code Highlight:
Database Creation: Uses openDatabase(path, version: 1, onCreate: _onCreate).
Insertion: db.insert(_tableName, row). Data is passed as a Dart Map<String, dynamic>.
Reading: db.query(_tableName) returns a List<Map<String, dynamic>>.
Viva Questions:
Q: Why are database operations async?
A: Because they involve I/O operations (reading/writing to disk), which can take time. Making them async prevents the database calls from blocking the UI thread (preventing "jank").
Q: How is data stored and retrieved from SQFlite?
A: Data is stored and retrieved as Dart Maps (Map<String, dynamic>), where keys correspond to column names.
Q: What is a Dart Future?
A: An object representing a potential value or error that will be available at some time in the future. It's similar to a Java Promise.
Assignment 17: Flutter REST API Program
Goal: Fetch JSON data from an external API and display it in a ListView.
Key Concepts:
http Package: Used for making network requests (GET, POST, etc.).
dart:convert: Used for decoding the JSON string response into Dart objects (json.decode(str)).
Model Class (POJO/Data Class): A Dart class (Employee) that mirrors the structure of the JSON data for type safety and easy access.
FutureBuilder or initState + Visibility: Used to manage the UI state while waiting for the network data to load. (This assignment uses initState and a Visibility widget with a CircularProgressIndicator replacement.)
Code Highlight:
Fetching: final response = await http.get(Uri.parse(url));.
Mapping: List.from(json.decode(response.body).map((x) => Employee.fromJson(x))) converts the raw JSON list into a list of Employee objects.
pubspec.yaml: This is where external dependencies like http are declared.
Viva Questions:
Q: How do you handle JSON data in Flutter?
A: Use the http package for fetching and the dart:convert library to decode the JSON string into Dart objects, typically mapped to a Model Class.
Q: What is the purpose of initState?
A: It is called once when a StatefulWidget is inserted into the widget tree. It is typically used to initialize state variables and start asynchronous data fetching (like API calls).
Q: Why is the CircularProgressIndicator used with Visibility?
A: It is a common pattern to show a loading indicator (CircularProgressIndicator) while the asynchronous data fetch is in progress (isLoaded is false) and display the actual content (ListView) once data is available (isLoaded is true).
Summary of All Assignments
Assignment Topic Core Technology Key Concept
1 Calculator Android (Java) OnClickListener, Double.parseDouble, Input Validation
2 Currency Converter Android (Java) Spinner, ArrayAdapter, 2D Array Logic
3 Explicit Intent Android (Java) Intent.putExtra, Data Passing, SeekBar, CheckBox
4 Implicit Intent Android (Java) Intent.ACTION_VIEW/SENDTO/DIAL, Uri.parse, Intent-Filter
5 Shared Preferences Android (Java) SharedPreferences, MODE_PRIVATE, Intruder Logic
6 Notification Android (Java) NotificationChannel, PendingIntent, NotificationCompat.Builder
7 File Storage Android (Java) Internal (openFileOutput), External (Environment.getExternalStorageState)
8 SQLite Database Android (Java) SQLiteOpenHelper, ContentValues, Cursor, CRUD Operations
9 Firebase RTDB Android (Java) DatabaseReference, NoSQL, ValueEventListener, Real-time updates
10 Image Processing Android (Java) ObjectAnimator, Bitmap, Pixel Manipulation (ARGB), Greyscale formula
11 Audio/Video Player Android (Java) MediaPlayer, VideoView, MediaController, res/raw
12 GPS Location Android (Java) LocationManager, Geocoder, Runtime Permissions (ACCESS_FINE_LOCATION)
13 REST API Fetch Android (Java) Volley / OkHttp / Retrofit, JSON Parsing, INTERNET Permission
14 BMI Calculator Flutter (Dart) StatefulWidget, TextEditingController, setState, Basic Layout
15 Registration Form Flutter (Dart) Navigator.push, Passing Data via Constructor, Various Input Widgets
16 SQFlite Database Flutter (Dart) sqflite, path_provider, Future, Async/Await CRUD
17 Flutter REST API Flutter (Dart) http package, Model Class (fromJson), initState, Visibility (Loading)
I have now gone through all 17 assignments and provided detailed viva notes for each. Please let me know if you have specific questions on any of the assignments or concepts!