You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android个人财务记账APP:按时间管理用户交易数据的实现咨询

Hey there! As someone who’s helped tons of new Android devs build similar apps, let’s walk through your question step by step.

你的财务记账APP数据存储方案建议

先聊核心问题:该不该用SharedPreferences?

Short answer: SharedPreferences is not ideal for your use case, but it can work if you’re only testing with a handful of simple records. Here’s the breakdown:

  • SharedPreferences is designed for small, key-value pairs (like user settings, theme preferences) — it’s not built to handle structured, multi-entry data like transaction records.
  • As your app grows (users add more transactions), storing and querying data with SharedPreferences will get messy fast: you’ll have to handle serialization/deserialization manually, and sorting/filtering by time will become inefficient.

For a personal finance app, Room Database is the way to go. It’s Google’s official SQLite wrapper for Android, built to handle structured data, supports easy querying/sorting, and scales well as your app grows. But if you still want to try SharedPreferences for learning purposes, I’ll cover that too.


如果一定要用SharedPreferences,怎么实现?

You’ll need to serialize your transaction data into a format that SharedPreferences can store (like JSON), then deserialize it when you need to work with the data. Here’s a step-by-step example:

1. Define a Transaction data class

First, create a class to represent each transaction:

data class Transaction(
    val id: String,
    val amount: Double,
    val category: String,
    val timestamp: Long, // Store time as Unix timestamp for easy sorting
    val note: String? = null
)

2. Use a JSON library (like Gson) for serialization

Add Gson to your app’s build.gradle (Module level):

dependencies {
    implementation 'com.google.code.gson:gson:2.10.1'
}

3. Write helper methods to save/load transactions

Create a utility class to handle SharedPreferences operations:

class TransactionPrefsHelper(context: Context) {
    private val prefs = context.getSharedPreferences("transactions", Context.MODE_PRIVATE)
    private val gson = Gson()

    // Save list of transactions
    fun saveTransactions(transactions: List<Transaction>) {
        val json = gson.toJson(transactions)
        prefs.edit().putString("transaction_list", json).apply()
    }

    // Load all transactions
    fun loadTransactions(): List<Transaction> {
        val json = prefs.getString("transaction_list", null) ?: return emptyList()
        val type = object : TypeToken<List<Transaction>>() {}.type
        return gson.fromJson(json, type)
    }
}

4. Implement sorting and time-based filtering

Once you load the transactions, you can sort them and filter by time:

// Get all transactions sorted by time (newest first)
val allTransactions = prefsHelper.loadTransactions()
val sortedTransactions = allTransactions.sortedByDescending { it.timestamp }

// Filter transactions between two timestamps (e.g., start of day to end of day)
val startTime = // Unix timestamp for start of target period
val endTime = // Unix timestamp for end of target period
val filteredTransactions = sortedTransactions.filter {
    it.timestamp in startTime..endTime
}

推荐方案:用Room Database实现(更适合长期开发)

Room is built exactly for scenarios like this. Here’s how to set it up:

1. Add Room dependencies to build.gradle

dependencies {
    implementation "androidx.room:room-runtime:2.5.2"
    kapt "androidx.room:room-compiler:2.5.2"
    // For Kotlin coroutines support (optional but recommended)
    implementation "androidx.room:room-ktx:2.5.2"
}

2. Define the Transaction Entity

This class represents a table in the database:

@Entity(tableName = "transactions")
data class Transaction(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    val amount: Double,
    val category: String,
    val timestamp: Long,
    val note: String? = null
)

3. Create a DAO (Data Access Object)

This defines all the database operations you need:

@Dao
interface TransactionDao {
    // Insert a new transaction
    @Insert
    suspend fun insertTransaction(transaction: Transaction)

    // Get all transactions sorted by timestamp (newest first)
    @Query("SELECT * FROM transactions ORDER BY timestamp DESC")
    suspend fun getAllTransactionsSorted(): List<Transaction>

    // Get transactions between two timestamps
    @Query("SELECT * FROM transactions WHERE timestamp BETWEEN :startTime AND :endTime ORDER BY timestamp DESC")
    suspend fun getTransactionsInTimeRange(startTime: Long, endTime: Long): List<Transaction>
}

4. Create the Room Database class

@Database(entities = [Transaction::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun transactionDao(): TransactionDao

    companion object {
        // Singleton instance to avoid multiple database connections
        @Volatile
        private var INSTANCE: AppDatabase? = null

        fun getDatabase(context: Context): AppDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    AppDatabase::class.java,
                    "app_database"
                ).build()
                INSTANCE = instance
                instance
            }
        }
    }
}

5. Use Room in your app

You can use coroutines to perform database operations (since they can’t run on the main thread):

// Get database instance
val db = AppDatabase.getDatabase(context)
val transactionDao = db.transactionDao()

// Insert a transaction
CoroutineScope(Dispatchers.IO).launch {
    val newTransaction = Transaction(
        amount = 50.0,
        category = "Food",
        timestamp = System.currentTimeMillis(),
        note = "Lunch at café"
    )
    transactionDao.insertTransaction(newTransaction)
}

// Get all sorted transactions
CoroutineScope(Dispatchers.IO).launch {
    val sortedTransactions = transactionDao.getAllTransactionsSorted()
    // Update UI with data (switch to main thread)
    withContext(Dispatchers.Main) {
        // Update your RecyclerView or list here
    }
}

// Get transactions in a time range
CoroutineScope(Dispatchers.IO).launch {
    val startTime = // Unix timestamp for start of period
    val endTime = // Unix timestamp for end of period
    val filteredTransactions = transactionDao.getTransactionsInTimeRange(startTime, endTime)
    // Update UI
    withContext(Dispatchers.Main) {
        // Handle filtered data
    }
}

Final Notes

  • Room will handle all the heavy lifting of sorting and querying, so you don’t have to write manual sorting logic like you would with SharedPreferences.
  • As your app grows, you can easily add more features (like categories, reports) with Room, which would be much harder with SharedPreferences.

内容的提问来源于stack exchange,提问作者Mehran

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:10:35