thread error while using realm in MVVM architecture - multithreading

I'm using the Realm database in my kotlin project.
I use MVVM architecture so I created a repository class which contains codes bellow:
class DatabaseRepository {
private val database = Realm.getDefaultInstance()
fun addOrUpdateUser(user: JSONObject) {
database.executeTransactionAsync{
database.createOrUpdateObjectFromJson(UserModel::class.java, user)
}
}
}
also, I have created my ViewModel class like this:
class DatabaseViewModel(private val database:DatabaseRepository) : ViewModel() {
fun addUser(information: JSONObject) {
database.addOrUpdateUser(information)
}
}
and my View ModelFactory class is like this:
class ViewModelFactory(private val databaseRepository:DatabaseRepository):ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return modelClass.getConstructor(DatabaseRepository::class.java).newInstance(databaseRepository)
}
}
so I create the instance of them in my MainActivity like this:
val databaseRepo=DatabaseRepository()
val factory=ViewModelFactory(databaseRepo)
database = ViewModelProviders.of(this,factory).get(DatabaseViewModel::class.java)
the problem is that while I'm trying to add some data to Database using 'addUser' function in ViewModel class I get this error:
Realm objects can only be accessed on the thread they were created.
what have I done wrong?

the only problem was because of executeTransactionAsync, so I changed from:
executeTransactionAsync
to
executeTransaction
and it worked!

Related

Instanciate Room database in Android Studio

I'm trying to instanciate a Room database in my main activity in Android Studio, following codelabs and tutorials, but my app always crash. Here's a part of the code:
My database (AppDatabase.kt):
#Database(entities = [Device::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
abstract fun deviceDao(): DeviceDao
companion object {
#Volatile
private var INSTANCE: AppDatabase? = null
fun getDatabase(context: Context): AppDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"item_database"
)
.fallbackToDestructiveMigration()
.build() // <---- The crash occurs here
INSTANCE = instance
return instance
}
}
}
}
And here's the activity from which I'm trying to instantiate it:
class NavigationActivity() : AppCompatActivity() {
private lateinit var binding: ActivityNavigationBinding
private val db by lazy { AppDatabase.getDatabase(this) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityNavigationBinding.inflate(layoutInflater)
setContentView(binding.root)
Log.d("instantiation", "$db") // <----- Called from here
val navView: BottomNavigationView = binding.navView
val navController = findNavController(R.id.nav_host_fragment_activity_navigation)
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.navigation_devices, R.id.navigation_logs, R.id.navigation_settings
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
}
Finally, here's the error message, which doesn't helps me much:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.Package.getName()' on a null object reference
at androidx.room.Room.getGeneratedImplementation(Room.java:82)
at androidx.room.RoomDatabase$Builder.build(RoomDatabase.java:1486)
at AppDatabase$Companion.getDatabase(AppDatabase.kt:24)
I tried a lot of things, including ViewModel, Repository and more, but got the crash systematically, at the same point.
Here's also the part of my build.gradle file where I import Room, maybe I'm wrong in some version or whatever...
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-android'
id 'kotlin-kapt'
}
[...]
def roomVersion = "2.4.2"
implementation("androidx.room:room-runtime:$roomVersion")
kapt("androidx.room:room-compiler:$roomVersion")
implementation "androidx.room:room-ktx:$roomVersion"
Make sure package declaration on top of the class is declared, for example:
package com.macrosystems.clean.ui.core.view
import android.content.Context
import android.content.Intent
import android.graphics.Color
etc...

Room cannot verify the data integrity and Crashes on Empty Data

I am working on Android Application in Which I am getting specific Data from Room Database by specific path in the Storage. My App Got Crashes as It does not have Any Data in the Storage and the Logcat gives me this..
java.lang.IllegalStateException: Room cannot verify the data integrity. Looks like you've changed schema but forgot to update the version number. You can simply fix this by increasing the version number.
at androidx.room.RoomOpenHelper.checkIdentity(RoomOpenHelper.java:154)
at androidx.room.RoomOpenHelper.onOpen(RoomOpenHelper.java:135)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onOpen(FrameworkSQLiteOpenHelper.java:195)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:428)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:317)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:145)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:106)
at androidx.room.RoomDatabase.inTransaction(RoomDatabase.java:476)
at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.java:281)
at com.maximus.technologies.views.activities.scanneddatabase.TodoDaoScanned_Impl.getAllScan(TodoDaoScanned_Impl.java:152)
at com.maximus.technologies.views.fragments.scanhistorypackage.QRRetrievingScanClassPresenter$getAllDatFromDatabase$1.invokeSuspend(QRRetrievingScanClassPresenter.kt:29)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:241)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
The Above Error or crash Only occurs as the app dont have any data in Storage. But as I put a Data the Crash Problem Get Resolved.
I am not able to Understand what the Problem actually is...
Here is My Room Database Class..
#Database(
entities = [TodoEntity::class,TodoEntityScanned::class],
version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun TodoDao(): TodoDao
abstract fun TodoDaoScanned(): TodoDaoScanned
object DatabaseBuilder {
private var INSTANCE: AppDatabase? = null
fun getInstance(context: Context): AppDatabase {
if (INSTANCE == null) {
synchronized(AppDatabase::class) {
INSTANCE = buildRoomDB(context)
}
}
return INSTANCE!!
}
private fun buildRoomDB(context: Context) =
Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"mindorks-example-coroutines"
).build()
}
}
Room Database Retrieving Interface where app Crashes on getall()
override fun getAllDatFromDatabase(appDatabasescanned: AppDatabase) {
var list = listOf<TodoEntityScanned>()
try {
GlobalScope.launch(Dispatchers.Default) {
list = appDatabasescanned.TodoDaoScanned().getAllScan()
Log.d("hello","hello")
mView.showAllData(list)
}
}
catch (e:Exception){
Log.d("get hello",e.toString())
}
}
The getAll lies in Dao Class
interface TodoDao {
#Query("SELECT * FROM tablefilepaths")
fun getAll(): List<TodoEntity>
#Query("SELECT * FROM tablefilepaths WHERE imagespath LIKE :title")
fun findByTitle(title: String): TodoEntity
#Insert
fun insertpaths(todo: TodoEntity)
#Delete
fun deletepaths(todo: TodoEntity)
#Query("DELETE FROM tablefilepaths WHERE id = :noteId")
fun deleteNoteById(noteId: Int)
#Update
fun updateTodo(vararg todos: TodoEntity)}
Here is My Fragment Class Where I am Setting data in RecyclerView
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recyclerviewcreatehistory?.layoutManager = LinearLayoutManager(context)
recyclerviewcreatehistory?.setHasFixedSize(true)
filefetch()
customAdaptercreatehistory = CustomAdapterCreateHistory(this.context ?: return, charItemcreate!!,this)
recyclerviewcreatehistory?.adapter = customAdaptercreatehistory
}
fun filefetch() {
val noteDatabase: AppDatabase = AppDatabase.DatabaseBuilder.getInstance(requireContext())
retrivingpresenter = QRRetrievingClassPresenter(this)
retrivingpresenter!!.getAllDatFromDatabase(noteDatabase)
}
override fun showAllData(note_list: List<TodoEntity>) {
if (note_list is ArrayList<*>) {
val arraylist = note_list as ArrayList<TodoEntity>
charItemcreate=arraylist
}
if (charItemcreate.isEmpty()){
}else{
customAdaptercreatehistory?.updateUsers(note_list as ArrayList<TodoEntity>)
customAdaptercreatehistory?.notifyDataSetChanged()
// Log.d("hello", note_list[0].imagesPathData)
}
}
You have to do some checks in your getAllDatFromDatabase() inside your coroutine. I guess list variable equals null or something like that. You should check if there are any files and if not you need to put there something else.

Injecting a different bean during local development with Quarkus

With Spring and Micronaut, there are very concise ways to inject a different bean depending on what environment/profile an application is running in. I'm trying to do the same with Quarkus.
I've read this post: https://quarkus.io/blog/quarkus-dependency-injection/. And the process is alluded to in this StackOverflow post: How can I override a CDI bean in Quarkus for testing?. That last post says, "create bean in test directory".
My problem is slightly different. I'd like to inject a bean when in "development". In production, I'd like the default bean injected. From the docs, I can't see a way to have the app make this distinction.
If I have a default class like this:
#DefaultBean
#ApplicationScoped
class ProdProvider : SomeProvider {}
And I want to override it like this:
#Alternative
#Priority(1)
class DevProvider : SomeProvider {}
How can I make this happen only in dev mode?
In one case, I have a credential provider class that sets up Google's PubSub emulator while in local development. In production, I use a class that implements the same interface, but a real credential provider. The particular case that led me to asking this question, though is a a class that implements one method:
#ApplicationScoped
class VaultLoginJwtProvider : LoginJwtProvider {
#ConfigProperty(name = "vault.tokenPath")
private val jwtPath: String? = null
companion object {
val logger: Logger = LoggerFactory.getLogger("VaultTokenProvider")
}
override fun getLoginJwt(): Optional<String> {
logger.info("Using Vault Login JWT")
return try {
Optional.of(String(Files.readAllBytes(Paths.get(jwtPath))).trim { it <= ' ' })
} catch (e: Exception) {
logger.error("Could not read vault token at $jwtPath")
logger.error(e.printStackTrace().toString())
Optional.empty()
}
}
}
That class is injected into another class via constructor injection:
#Singleton
class JwtServiceImpl(
#RestClient val vaultClient: VaultClient,
#Inject val loginJwtProvider: LoginJwtProvider
) {
private var serviceJwt: String? = null
companion object {
val logger: Logger = LoggerFactory.getLogger("JwtServiceImpl")
}
private fun getLoginToken(): String? {
val vaultLogin = VaultLogin(
role = "user-service",
jwt = loginJwtProvider.getLoginJwt().get()
)
val loginResponse = vaultClient.login(vaultLogin)
return loginResponse.auth.clientToken
}
}
I'd like to inject more of a "mock" class while in development that just returns a static string. I could use ProfileManager.getActiveProfile(), but that has me mixing development concerns into my logic. And I don't feel that that has any place in my compiled production code.
This is possible in Micronaut by using the annotation #Requires(env = ["dev", "test"]). I did briefly look at using #Produces but the Oracle EE docs seemed a little bit difficult for me to grasp. If that's the solution, I'll dig in.
In case anybody else comes across this, this is how to do it: https://quarkus.io/guides/cdi-reference#enabling-beans-for-quarkus-build-profile
For example:
import javax.enterprise.inject.Produces;
import com.oi1p.common.EmailSender;
import com.oi1p.common.ErrorEmailSender;
import com.oi1p.common.LogOnlyEmailSender;
import io.quarkus.arc.DefaultBean;
import io.quarkus.arc.profile.IfBuildProfile;
#ApplicationScoped
public class Producers {
#Produces
#IfBuildProfile("dev")
public EmailSender logOnlyEmailSender() {
return new LogOnlyEmailSender();
}
#Produces
#DefaultBean
public EmailSender errorEmailSender() {
// TODO: implement a real email sender. This one explodes when poked.
return new ErrorEmailSender();
}
}
My solution is to create the final bean on my own inside a #javax.ws.rs.ext.Provider. Not as elegant as Micronaut #Requires, but well, it works.
Note that instance of SomeProvider is not a "bean", you have to care for the lifecycle on your own (dependency injection, PostConstruct, no PreDestroy, ...).
org.acme.SomeProvider.java
package org.acme;
import javax.enterprise.context.ApplicationScoped;
public interface SomeProvider {
void providerMethod();
#ApplicationScoped
class ProdProviderRequirement {
void foo() {}
}
class ProdProvider implements SomeProvider {
private final ProdProviderRequirement prodProviderRequirement;
ProdProvider(final ProdProviderRequirement prodProviderRequirement) {
this.prodProviderRequirement = prodProviderRequirement;
}
#Override
public void providerMethod() {
prodProviderRequirement.foo();
}
}
class DevProvider implements SomeProvider {
#Override
public void providerMethod() {}
}
}
org.acme.SomeProviderFactory.java
package org.acme;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import javax.ws.rs.ext.Provider;
import org.acme.SomeProvider.DevProvider;
import org.acme.SomeProvider.ProdProvider;
import org.acme.SomeProvider.ProdProviderRequirement;
#Provider
class SomeProviderFactory {
SomeProvider someProvider;
#Inject
SomeProviderFactory(final ProdProviderRequirement prodProviderRequirement) {
final var someCondition = true;
someProvider = someCondition ? new DevProvider() : new ProdProvider(prodProviderRequirement);
}
#Produces
#ApplicationScoped
SomeProvider someProvider() {
return someProvider;
}
}

How can I keep my current architecture of the back end while separating my local and remote data sources?

So long story short, trying to utilize googles good practices. I made a mistake of going dagger 2 for the project Di. And now I am stuck. I followed along the Sunflower architecture
I am trying to separate local data(ld) source and remote data(rd) source while if possible keeping the architecture I have. I currently have 2 data sources ld and rd that implement datasource interface. And my repository only recognises functions from that interface. In the googles example they share the same functions across both data sources, while my project diverges from that and they should have different functions. (Ld should insert quotes into DB while remote should just fetch quotes)
I've tried making a new interface that implements the datasource but is specific to local data source, and that didn't work, keep getting a missing binding error from dagger.
Github project
interface QuoteDataSource { //data source interface for both data sources
suspend fun getQuotes(): Result<List<Quote>>
}
class DefaultQuoteRepository #Inject constructor(
#ApplicationModule.QuoteRemoteDataSource private val quoteRemoteDataSource: QuoteDataSource,
#ApplicationModule.QuoteLocalDataSource private val quoteLocalDataSource: QuoteDataSource,
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
) : BaseRepository(), QuoteRepository {
#JvmStatic
#Singleton
#QuoteRemoteDataSource
#Provides
fun provideQuoteRemoteDataSource(
jsonNetworkService: JsonNetworkService
): QuoteDataSource {
return QuoteRemoteDataSource(jsonNetworkService.apiService)
}
#JvmStatic
#Singleton
#QuoteLocalDataSource
#Provides
fun provideQuoteLocalDataSource(
database: LocalQuoteDataBase,
ioDispatcher: CoroutineDispatcher
): QuoteDataSource {
return QuoteLocalDataSource(
database.quotesDao(), ioDispatcher
)
}
class QuoteLocalDataSource constructor( // for fetching locally stored quotes, might save favorite quootes or save the json quotes
private val quotesDao: QuotesDao,
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
) : QuoteDataSource {
override suspend fun getQuotes(): Result<List<Quote>> = withContext(ioDispatcher) {
return#withContext try {
Success(quotesDao.getQuotes())
} catch (e: Exception) {
Result.Error(IOException("Unable to fetch quotes!"))
}
}
class QuoteRemoteDataSource #Inject constructor(
private val apiService: QuoteApi
) : QuoteDataSource {
override suspend fun getQuotes(): Result<List<Quote>> {
val response = apiService.getQuotes().await()
try {
if (response.isSuccessful)
if(!response.body().isNullOrEmpty())
return Result.Success(response.body()) as Result<List<Quote>>
return Result.Error(IOException("Error occurred during fetching quotes!"))
} catch (e: Exception) {
Result.Error(IOException("Unable to fetch quotes!"))
}
return Result.Error(IOException("Unable to fetch quotes!"))
}
I am somehow trying to have localdata source have its own functions that are recognised by the default quote repository. As if i just add functions to the localds they won't be available to the repository.

Need to verify Autommaper implemented correctly in Asp.Net MVC

I have implemented Automapper in my MVC project but not sure if it is been done correctly. I am currently using Entity Framework Database First Approach and retrieving data using stored procedures. As you would be aware Entity Framework creates complex type object which is a wrapper around Stored Procedures.So I have created two classes for mapping purpose. One is used in the repository class to map the complex type to Entity class and second is the viewmodel that is used to map the entity class to view model in the controller. I havent explicitly mapped my entity class to viewmodel in the controller. So I am wondering how is the data bound to the grid as the grid is expecting viewmodel. I am looking forward for suggestions in terms of the approach that I have taken.
spGetUserProfileByUserProfileID_Result - Complex type object
UserProfile - Entity class.
UserProfileViewModel - ViewModel
AutoMapperConfiguration Class
public static void Configure()
{
Assembly[] assemblies = BuildManager.GetReferencedAssemblies().OfType<Assembly>().ToArray();
Mapper.Initialize(cfg =>
cfg.AddProfiles(AllClasses.FromAssemblies(assemblies)
.Where(
a =>
a.FullName.EndsWith("Mapping"))));
}
Mapping class
public class DomainToModelMapping : Profile
{
public DomainToModelMapping()
{
CreateMap<spGetUserProfileByUserProfileID_Result, UserProfile>().ReverseMap();
CreateMap<UserProfileViewModel, UserProfile>().ReverseMap();
}
}
Repository
public List<UserProfile> GetUserProfileById(int id)
{
if (MCRHelper.UserValidate() == 1)
{
var userProfiles = db.spGetUserProfileByUserProfileID(id);
return Mapper.Map<List<UserProfile>>(userProfiles);
}
else
{
return null;
}
}
Controller
public ActionResult UserProfile_Read([DataSourceRequest]DataSourceRequest request)
{
var response = mcrRepository.GetUserProfileById(0).ToDataSourceResult(request);
return Json(response, JsonRequestBehavior.AllowGet);
}
If I add the following , to my controller to map to viewmodel, I get an error Missing type map configuration or unsupported mapping.
Mapping types:
DataSourceResult -> UserProfile
Kendo.Mvc.UI.DataSourceResult -> CC.GRP.MCRequest.Models.UserProfile
var userProfile = mcrRepository.GetUserProfileById(0).ToDataSourceResult(request);
return Json(Mapper.Map<UserProfile>(userProfile), JsonRequestBehavior.AllowGet);
If your question is how to return the viewmodel instead of the entity model from your controller using Automapper, then use Automapper Queryable Extensions:
using Automapper.QueryableExtensions;
...
public JsonResult UserProfile_Read([DataSourceRequest]DataSourceRequest request)
{
var users = mcrRepository.GetUserProfileById(0).Project().To<UserProfileViewModel>();
var response = users.ToDataSourceResult(request);
return Json(response, JsonRequestBehavior.AllowGet);
}

Resources