Search code examples
kotlinsaveandroid-room

Save data to local storage using Room


I apologize in advance if the question seems incomprehensible, since android development and kotlin are not my main stack. I will try to explain in as clear a language as possible.

I have a class that is responsible for intercepting data from HTTP-request. This implementation reflects the following code

    class PocketScoutInterceptor() : Interceptor {


    fun buildPacket(timestamp: Long, duration: Double, request: Request, response: Response) {
        val reqBody = request.body
        val respBody = response.body?.string()

        val packet = Packet(
            id = 0,
            userId = PocketScoutConfig.userId,
            deviceId = PocketScoutConfig.deviceId,
            sessionId = PocketScoutConfig.sessionId,
            timestamp = timestamp,
            duration = duration.roundToInt(),
            protocol = "http",
            request = room.entities.Request(
                request_method = request.method,
                request_url = request.url.toUrl().toString(),
                request_headers = request.headers.toMultimap() as Mapping,
                request_body = (reqBody?.toString() ?: ""),
                request_size = (reqBody?.toString()?.length ?: 0),
            ),
            room.entities.Response(
                response_code = response.code,
                response_headers = response.headers.toMultimap() as Mapping,
                response_body = (respBody ?: ""),
                response_size = (respBody?.length ?: 0),
            )
        )
    }
}

Further, I need to save this data in a local database, I chose room.

Next I created a database class

    @TypeConverters(value = [RoomTypeConverters::class])
@Database(
    version = 1,
    entities = [Packet::class],
    exportSchema = false
)
abstract class NetworkDatabase : RoomDatabase() {
    abstract fun packetDao(): PacketDao
}

I just have to learn how to save data in local storage. I've watched several videos on this topic and read the documentation several times, but as far as my example is concerned, I can't find an answer. Maybe you can help me


Solution

  • 1). You need to build the database via the Room databaseBuilder function/method. The following change to the @Database annotated class would do this and would return a singleton:-

    @TypeConverters(value = [RoomTypeConverters::class])
    @Database(entities = [Packet::class], version = 1, exportSchema = false)
    abstract class NetworkDatabase: RoomDatabase() {
        abstract fun packetDao(): PacketDao
    
        companion object {
            @Volatile
            private var instance: NetworkDatabase? = null;
            fun getInstance(context: Context): NetworkDatabase {
                if (instance == null) {
                    instance = Room.databaseBuilder(context,NetworkDatabase::class.java,"the_database.db")
                        .allowMainThreadQueries() /* for brevity/convenience but shouldn't really run stuff on the main thread */
                        .build()
                }
                return instance as NetworkDatabase
            }
        }
    }
    
    • Note ideally you would access the database off the main thread. However the above allows the database access to be via the main thread and thus easier to demonstrate.

    2). The next stage is to actually use the above, as an example consider the following activity code (working example):-

    class MainActivity : AppCompatActivity() {
        lateinit var db: NetworkDatabase
        lateinit var dao: PacketDao
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            /* Get an instance of NetworkDatabase  and the packetDao */
            db = NetworkDatabase.getInstance(this)
            dao = db.packetDao()
    
            /* add some data (1 row)*/
            val m1 = Mapping(header = mapOf())
            dao.add(
                Packet(
                    id = 10,
                    deviceId =
                    "device10",
                    sessionId = "session100",
                    timestamp = System.currentTimeMillis(),
                    protocol = "HTML",
                    request = Request(requestMethod = "the method", requestUrl = "blah", requestHeaders = m1,
                        requestBody = "ReqBody", requestSize = 10),
                    userId = "userxxx",
                    duration = 200,
                    response = Response(100,m1,"RspBody",210)
            )
            )
            /* Extract all rows and write to the log */
            for(p in dao.getAll()) {
                Log.d("DBINFO","Packet ID is ${p.id} DeviceId is ${p.deviceId} Duration is ${p.duration} ....")
            }
        }
    }
    

    The above, when run (for the first time) results in the log containing :-

    D/DBINFO: Packet ID is 10 DeviceId is device10 Duration is 200 ....
    

    Obviously you would build the Packet(s) via your Interceptor