IT272 Mobile Application Development

Mobile Application DevelopmentUnit 69 min read

Data Storage in Mobile Apps: Preferences, Files & SQLite

Unit 6 of Mobile Application Development covers how to store data in Android apps using SharedPreferences (key-value pairs), raw files (text/binary), and SQLite (relational databases), with code examples, performance comparisons, and real-world use cases like eSewa’s transaction logs and Daraz’s order queues.

Key Concepts and How They Work

1. SharedPreferences: Lightweight Key-Value Storage

SharedPreferences is Android’s simplest way to store primitive data (strings, booleans, integers, floats) persistently. It uses XML files under /data/data/<package>/shared_prefs/ and is ideal for small, app-specific settings.

0isLoggedInusername1theme2lastLogin3—
SharedPreferences stored as XML (simplified hash table with 4 buckets, h(k) = k.hashCode() % 4)

How It Works:

  • Data Types: Stores String, int, boolean, float, long, and Set<String>.
  • Usage: Call getSharedPreferences() to get an instance, then use edit() → putX() → commit() to save.
  • Thread Safety: Not thread-safe; use apply() for async writes.

Example: Saving User Login State

// Save login status
SharedPreferences prefs = getSharedPreferences("UserPrefs", MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("isLoggedIn", true);
editor.putString("username", "user123");
editor.apply(); // Async commit

// Retrieve later
boolean loggedIn = prefs.getBoolean("isLoggedIn", false);
String username = prefs.getString("username", "");

Visual: SharedPreferences File Structure


State After Saving:

<map>
  <boolean name="isLoggedIn" value="true" />
  <string name="username" value="user123" />
</map>

Real-World Use:

  • eSewa App: Uses SharedPreferences to cache the user’s last transaction ID and auto-fill forms.
  • Khalti: Stores payment gateway tokens (e.g., lastUsedBank) for quick access.

2. File Storage: Internal vs. External Files

Files are used for larger data (e.g., images, logs, JSON configs). Android distinguishes between:

  • Internal Storage: Private to the app (deleted when uninstalled).
  • External Storage: Public (requires WRITE_EXTERNAL_STORAGE permission).

Example: Writing a Log File

// Internal file
File file = new File(getFilesDir(), "app_log.txt");
try (FileWriter writer = new FileWriter(file)) {
    writer.write("Error: " + e.getMessage());
}

// External file (requires permission)
File externalFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "backup.json");
FileOutputStream fos = new FileOutputStream(externalFile);
fos.write(jsonData.getBytes());

Visual: File Storage Paths

Real-World Use:

  • Pathao Driver App: Stores trip logs (e.g., driver_123_log.txt) internally for analytics.
  • NTC Website Backup: Uses external storage to archive daily traffic reports as .csv files.

3. SQLite: Relational Database for Structured Data

SQLite is a lightweight database embedded in Android. Use SQLiteOpenHelper to create tables and ContentValues to insert/retrieve data.

id: 1name: 'Ram Thapa'email: 'ram@example.com'user1users
SQLite table structure example (users table)
id: 1product: Smartphoneprice: 45000.0order_1id: 2product: Laptopprice: 89999.0order_2orders
SQLite table structure after inserting Daraz-like orders (simplified tree view)

Example: Storing Orders (Like Daraz)

// Create table
public class DatabaseHelper extends SQLiteOpenHelper {
    public static final String TABLE_ORDERS = "orders";
    public static final String COLUMN_ID = "id";
    public static final String COLUMN_PRODUCT = "product";

    public DatabaseHelper(Context context) {
        super(context, "OrderDB", null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE " + TABLE_ORDERS +
                  "(id INTEGER PRIMARY KEY, product TEXT, price REAL)");
    }
}

// Insert order (e.g., Daraz order #1001)
DatabaseHelper dbHelper = new DatabaseHelper(this);
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("product", "Smartphone");
values.put("price", 45000.0);
db.insert("orders", null, values);

// Query orders
Cursor cursor = db.query("orders", null, null, null, null, null, null);
while (cursor.moveToNext()) {
    String product = cursor.getString(cursor.getColumnIndex("product"));
    // Display in ListView
}

Visual: SQLite Table After Insertion


State After Insert:

id product price
1 Smartphone 45000.0
2 Laptop 89999.0

Real-World Use:

  • NEPSE App: Uses SQLite to store stock prices and user watchlists.
  • Banking Apps (e.g., NMB): Stores transaction history locally for offline access.

4. Comparison Table: Storage Options

Method Use Case Pros Cons
SharedPreferences Small settings (e.g., theme, login) Simple API, fast No complex queries
Internal Files App logs, configs Private, no permissions needed Manual parsing (e.g., JSON)
External Files Large media, backups Public access, survives uninstall Permission-heavy, security risk
SQLite Structured data (e.g., orders, users) ACID-compliant, queries Overhead for small data

5. Exam Tip

  • SharedPreferences: Remember to use apply() for async writes in UI threads.
  • File Handling: Always check for null when reading files and handle IOException.
  • SQLite: Use getReadableDatabase()/getWritableDatabase() correctly to avoid crashes.
  • Permissions: External storage requires <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> in AndroidManifest.xml.
  • Real-World Scenarios: Expect questions on caching (e.g., "How would you store a user’s last visited page in eSewa?").

In the Real World

  1. eSewa Transaction Logs:

    • Uses SQLite to store all transactions (ID, amount, timestamp) for audit trails. The app queries this database to show users their transaction history.
    • Example: When you check "My Transactions," eSewa runs:
      SELECT * FROM transactions WHERE user_id = 123 ORDER BY timestamp DESC;
      
  2. Daraz Order Queue:

    • Uses SQLite to manage pending orders. When you place an order, it’s inserted into an orders table with status PENDING. The app polls this table to update the UI.
    • Visual: Order Status Flow
flowchart TD
    A["User Places Order"] --> B[SQLite Insert
status=PENDING]
    B --> C[Background Service
Polls SQLite]
    C -->|"status=SHIPPED"| D["Notify User"]
    C -->|"status=FAILED"| E["Retry or Alert"]
  1. Khalti Payment Token:
    • Stores the last used bank/merchant token in SharedPreferences under prefs.xml as:
      <map>
        <string name="last_token">bank_abc_123</string>
      </map>
      
    • This avoids re-entering credentials for frequent payments.

Worked Example: Traffic Route Saver (NTC App)

Scenario: The NTC app needs to save the user’s favorite routes (start, end, distance) for quick access.

stateDiagram-v2
    [*] --> RouteSaved
    RouteSaved --> TrafficUpdate
    TrafficUpdate -->|New Route| RouteSaved
    TrafficUpdate -->|Error| [*]
    state RouteSaved {
        [Save to SQLite]
    }
    state TrafficUpdate {
        [Check NTC API]
        [Update UI]
    }
State diagram for NTC app route saving workflow (SQLite + API)

Solution Using SQLite

// Create table
public void onCreate(SQLiteDatabase db) {
    db.execSQL("CREATE TABLE routes (" +
               "id INTEGER PRIMARY KEY, " +
               "start TEXT, end TEXT, distance REAL)");
}

// Save route (e.g., Kathmandu to Pokhara)
ContentValues values = new ContentValues();
values.put("start", "Kathmandu");
values.put("end", "Pokhara");
values.put("distance", 201.5);
db.insert("routes", null, values);

// Retrieve routes
Cursor cursor = db.query("routes", null, null, null, null, null, null);
while (cursor.moveToNext()) {
    String start = cursor.getString(1); // Column index 1 = start
    Log.d("Route", start + " to " + cursor.getString(2));
}

Visual: SQLite Table After Adding Route

id start end distance
1 Kathmandu Pokhara 201.5
2 Bhaktapur Chitwan 180.2

Common Pitfalls and Fixes

  1. Forgetting to Commit:

    • Problem: Changes to SharedPreferences aren’t saved.
    • Fix: Always call editor.commit() or editor.apply().
  2. SQLite Locking:

    • Problem: SQLiteDatabase throws SQLiteLockedException.
    • Fix: Use beginTransaction() for complex operations:
      db.beginTransaction();
      try {
          db.insert(...);
          db.setTransactionSuccessful();
      } finally {
          db.endTransaction();
      }
      
  3. External Storage Permissions:

    • Problem: App crashes on FileOutputStream for external files.
    • Fix: Add to AndroidManifest.xml:
      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
      
      For Android 10+, use MediaStore or scoped storage.

Summary Checklist for Exams

  • Can you list the 5 data types supported by SharedPreferences?
  • How would you save a user’s profile picture? (Hint: Use FileOutputStream for internal storage.)
  • Write the SQL to create a users table with id, name, and email.
  • What’s the difference between commit() and apply() in SharedPreferences?
  • How does Daraz use SQLite to manage orders? (Hint: Think PENDING → SHIPPED status.)

Based on the TU BITM syllabus for Mobile Application Development (IT272), unit 6.

Discussion

Loading…