Saving and retrieving data from realm database in android - android

Hi i used realm to save data into relam database but its not saving data to database
In my application class
Realm.init(this);
RealmConfiguration config = new RealmConfiguration.Builder().build();
Realm.deleteRealm(config);
Realm.setDefaultConfiguration(config);
In my saving activity
public void SaveUserData(final UserData userData, Realm realm)
{
final String userdata = new Gson().toJson(userData);
realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
// realm.createObjectFromJson(com.mediquick.databaseModel.UserData.class, userdata);
com.mediquick.databaseModel.UserData user = realm.createObject(com.mediquick.databaseModel.UserData.class);
user.setLname(userData.getLname());
user.setEmail(userData.getEmail());
user.setToken(userData.getToken());
user.setAddress(userData.getAddress());
user.setMobile_no(userData.getMobile_no());
user.setDob(userData.getDob());
user.setName(userData.getName());
user.setProfile_pic(userData.getProfile_pic());
user.setUser_type(userData.getUser_type());
}
});
And when i retrieve a value
public String getUserToken(Realm realm)
{
final com.mediquick.databaseModel.UserData user = realm.where(com.mediquick.databaseModel.UserData.class).findFirst();
return (user!=null)?user.getToken():null;
}
It gives null back when i retrive token from the database
Any ideas..

Declare Realm Object before onCreate function:
Realm realmDB;
Now write these line in onCreate Method:
Realm.init(this);
realmDB=Realm.getDefaultInstance();
On save button click method:
try{
realmDB.beginTransaction();
UserSchedule us = realmDB.createObject(UserSchedule.class);
us.setId(userData.get_ID());
us.setDate(userData.getDate());
realmDB.commitTransaction();
}
catch (Exception ex){
Log.d("RError",ex.toString());
Toast.makeText(this, "Error in realm", Toast.LENGTH_SHORT).show();
}
To get records:
RealmResults<UserSchedule>userSchedules=realmDB.where(UserSchedule.class).findAll();
for (UserSchedule userSchedule:userSchedules)
{
Toast.makeText(this,userSchedule.getId(), Toast.LENGTH_SHORT).show();
Toast.makeText(this, userSchedule.getId(), Toast.LENGTH_SHORT).show();
}
To delete record:
RealmResults<UserSchedule> result = realmDB.where(UserSchedule.class).findAll();
UserSchedule userSchedule = result.where().equalTo("Id", getItem(position).getS_ID()).equalTo("Date",getItem(position).getDate()).findFirst();
if(userSchedule!=null)
{
if (!realmDB.isInTransaction())
{
realmDB.beginTransaction();
}
userSchedule.deleteFromRealm();
realmDB.commitTransaction();
}
else
{
Toast.makeText(this,"No Record.", Toast.LENGTH_SHORT).show();
}

Could you try this save function:
// SAY YES TO THIS
Realm realm = null;
try { // I could use try-with-resources here
realm = Realm.getDefaultInstance();
realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
realm.insertOrUpdate(dog);
}
});
} finally {
if(realm != null) {
realm.close();
}
}
In your code you are missing call
realm.insertOrUpdate(user)
inside executeTransaction function.

public void saveData(){
realm.executeTransactionAsync(new Realm.Transaction() {
#Override
public void execute(Realm bgRealm) {
Students students = bgRealm.createObject(Students.class);
students.setName(name.getText().toString().trim());
students.setCity(city.getText().toString().trim());
students.setDegree(degree.getText().toString().trim());
students.setGender(gender.getSelectedItem().toString().trim());
}
}, new Realm.Transaction.OnSuccess() {
#Override
public void onSuccess() {
// Transaction was a success.
}
}, new Realm.Transaction.OnError() {
#Override
public void onError(Throwable error) {
// Transaction failed and was automatically canceled.
}
});
}

Related

How do I wait until my data is retrieved from Firebase? [duplicate]

This question already has answers here:
How to return DataSnapshot value as a result of a method?
(6 answers)
Closed 3 years ago.
My problem is that I need to wait for the data from Firebase to be retrieved on the method "onDataChange" before ending my main method.
My code is (CalendarDbHelper) :
public synchronized ArrayList<Day> listDays()
{
final CountDownLatch done = new CountDownLatch(1);
db.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.exists())
{
for(DataSnapshot postSnapShot:dataSnapshot.getChildren())
{
Day day=postSnapShot.getValue(Day.class);
listDays.add(day);
}
}
done.countDown();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
try {
done.await();
} catch(InterruptedException e) {
e.printStackTrace();
}
return listDays;
}
As you can see, I'm already trying to wait with a CountDownLatch, but it doesn't work : it gets stuck.
I need the listDays for the activity "CalendarActivity" where I use it like this :
//Real initialization of the database
db = FirebaseDatabase.getInstance().getReference();
mDatabase = new CalendarDbHelper(db);
final List<Day> allDays = mDatabase.listDays();
//Activating things to click on
if(allDays.size() > 0){
calendarRV.setVisibility(View.VISIBLE);
calendarRVAdapter = new CalendarAdapter(this, allDays, new CalendarAdapter.OnListItemClickListener() {
#Override
public void onListItemClick(int clickedItemIndex) {
String id = allDays.get(clickedItemIndex).getId();
MyCustomAlertDialog(id);
}
});
calendarRV.setAdapter(calendarRVAdapter);
}else {
calendarRV.setVisibility(View.GONE);
Toast.makeText(this, "There is no product in the database. Start adding now", Toast.LENGTH_LONG).show();
}
if this is your "main method",you should put the return data when the onDataChange is triggered
Try this.
public synchronized ArrayList<Day> listDays()
{
final CountDownLatch done = new CountDownLatch(1);
db.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot)
{
if(dataSnapshot.exists())
{
for(DataSnapshot postSnapShot:dataSnapshot.getChildren())
{
Day day=postSnapShot.getValue(Day.class);
listDays.add(day);
}
// Do whatever you want to do with your list from here..
}
done.countDown();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
try {
done.await();
} catch(InterruptedException e) {
e.printStackTrace();
}
return listDays;
}

Data is not updated normally (room database)

I need when refresh page make request to API and insert getting data to my room database. But when I try to insert data I get io.reactivex.exceptions.OnErrorNotImplementedException: UNIQUE constraint failed: data.id (code 1555). So I decided to check is my table empty and if isn't make update request, but so my recyclerview doesn't work normally, and data doesn't update properly on db. Here is my code:
private void getData() {
progressBar.setVisibility(View.VISIBLE);
APIInterface service = RetrofitInstance.getRetrofitInstance().create(APIInterface.class);
Call<DataAll> call = service.getData();
call.enqueue(new Callback<DataAll>() {
#Override
public void onResponse(Call<DataAll> call, Response<DataAll> response) {
if(response.body() != null) {
List<Data> allData = response.body().getData();
Disposable disposable = db.dataDao().dataSize().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<Integer>() {
#Override
public void accept(Integer dbSize) throws Exception {
if(dbSize > 0)
updateData(allData);
else
insertData(allData);
fillListFromDb();
}
});
}
}
#Override
public void onFailure(Call<DataAll> call, Throwable t) {
tvErrorMessage.setVisibility(View.VISIBLE);
recyclerDataList.setVisibility(View.GONE);
progressBar.setVisibility(View.GONE);
swipeRefreshToUpdateList.setRefreshing(false);
Toast.makeText(getApplicationContext(), R.string.errorMessage, Toast.LENGTH_LONG).show();
t.printStackTrace();
}
});
}
private void fillListFromDb() {
Disposable disposable = db.dataDao().getAllData().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<List<Data>>() {
#Override
public void accept(List<Data> data) throws Exception {
listData.clear();
listData.addAll(data);
adapter = new MyAdapter(listData);
adapter.notifyDataSetChanged();
recyclerDataList.setAdapter(adapter);
progressBar.setVisibility(View.GONE);
swipeRefreshToUpdateList.setRefreshing(false);
}
});
}
private void updateData(List<Data> data) {
Completable.fromAction( () ->
db.dataDao().updateData(data))
.subscribeOn(Schedulers.io())
.subscribe();
}
private void insertData(List<Data> data) {
Completable.fromAction(() ->
db.dataDao().addData(data)).
subscribeOn(Schedulers.io())
.subscribe();
}
And onCreate method:
#Override
protected void onCreate(Bundle savedInstanceState) {
// ……
swipeRefreshToUpdateList.setOnRefreshListener(() -> {
tvErrorMessage.setVisibility(View.GONE);
recyclerDataList.setVisibility(View.VISIBLE);
getData();
});
}
Please help me
If you want an insert operation to overwrite existing object in DB, then you should use OnConflictStrategy.REPLACE.
See example:
#Dao
interface CatDao {
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertCats(cats: List<Cat>)
You have to check you List<Data> one by one in your updateData
For exemple :
#Override
public void onResponse(Call<DataAll> call, Response<DataAll> response) {
if(response.body() != null) {
List<Data> allData = response.body().getData();
for (Data data:allData){
if(isStored(data.getId())){
updateData(data);
else {
insertData(data);
}
}
}
}
}
}
you can create a new method in your DataDao findDataById(string id) and use it the boolean isStored(String id) method and update it directly
Good luck ! hope that will help you.

result of creation account in firebase is true but it's not added in firebase console

(Application Flow)
sign up -> create account in firebase authentication, sharedpreference.put(email & pw) for automatic login, save user info in database in firebase -> login -> mainActivity
before I released apk and proguard, it works well without any problem.
But after I had problems with proguard, I eliminate proguard rules and change minifyEnabled true to false in gradle.
Then I rebuild and run my app.
result of FirebaseAuth.createUserWithEmailAndPassword is true.
and result of UserData upload is true.
also result of login is true.
After all success, I checked my firebase console.
But new auth data is not added.
And userdata is created but every information is null.
Sharedpreference is empty as well.
I checked my previous code when it works well.
All codes are same.
And I searched all day long, but I haven't gotten any hint for handling it.
==FirebaseAuth Class ===
public void singUp(String userEmail, String userPwd) {
firebaseAuth.createUserWithEmailAndPassword(userEmail,userPwd)
.addOnSuccessListener(new OnSuccessListener<AuthResult>() {
#Override
public void onSuccess(AuthResult authResult) {
firebaseAuthListener.onSignUpComplete(true);
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
firebaseAuthListener.onSignUpComplete(false);
if(e instanceof FirebaseAuthUserCollisionException) {
signUpErrorListener.setErrorMessage("이미 사용 중인 이메일입니다. 다시 시도해주세요.");
}
}
});
}
public void login(final String userEmail, String userPwd){
firebaseAuth.signInWithEmailAndPassword(userEmail,userPwd)
.addOnSuccessListener(new OnSuccessListener<AuthResult>() {
#Override
public void onSuccess(AuthResult authResult) {
firebaseLoginListener.onLoginComplete(true);
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
firebaseLoginListener.onLoginComplete(false);
}
});
}
public void userDataUpload(final UserData userData){
firestore.collection("User")
.add(userData).addOnSuccessListener(new OnSuccessListener<DocumentReference>() {
#Override
public void onSuccess(DocumentReference documentReference) {
firebaseAuthListener.onUserDataComplete(true);
String recording_key = documentReference.getId();
recordingKeyListener.onSaveRecordKey(recording_key);
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
firebaseAuthListener.onUserDataComplete(false);
}
});
}
==SignUp Class =====
complete_btn.setOnClickListener(this);
#Override
public void onClick(View view) {
int id = view.getId();
switch (id){
case R.id.complete_btn:
boolean check_pw = checkPassword(userPassword_textInput,check_userpw_textInput);
if(check_pw) {
if(isSignUpSuccess) {
isComplete();
}else{
onSignUpComplete(true);
}
}else{
Toast.makeText(this, "비밀번호 일치 오류입니다. 다시 입력해주세요.", Toast.LENGTH_SHORT).show();
}
break;
}
}
private boolean checkPassword(TextInputLayout userPassword_textInput, TextInputLayout check_userpw_textInput) {
return true when passwords are same / return false in the other case
}
private void isComplete() {
userEmail = changeToString(userEmail_textInput);
userPwd = changeToString(userPassword_textInput);
userAge = changeToString(userAge_textInput);
userName = changeToString(userName_textInput);
singUp();
}
}
private void singUp() {
setUserData();
firebaseAuthData.singUp(userEmail, userPwd);
}
private void setUserData(){
userData.setUserName(userName);
userData.setUserEmail(userEmail);
userData.setUserAge(userAge);
userData.setUserGender(userSex);
userData.setUserJob(userJob);
}
#Override
public void onSignUpComplete(boolean isSuccess) {
this.isSignUpSuccess = isSuccess;
if(isSuccess){
firebaseAuthData.userDataUpload(userData);
SharedPreference sharedPreference = new SharedPreference();
sharedPreference.put(this,"email",userEmail);
sharedPreference.put(this,"pwd",userPwd);
}else{
Toast.makeText(this, "회원가입에 실패하였습니다.", Toast.LENGTH_SHORT).show();
LoadingProgress.dismissDialog();
}
}
#Override
public void onUserDataComplete(boolean isSuccess) {
LoadingProgress.dismissDialog();
if(isSuccess){
goNext(MainActivity.class);
}else{
Toast.makeText(this, "회원가입 실패 ", Toast.LENGTH_SHORT).show();
}
}
}
If the result of creation auth data is true, new account info should be added in my firebase console. At the same time, save user's email and pw in user's device using shared preference, plus created userdata with information that user input not null.
=====SignUp Class=======
(Global Variable)
//for checking created user account but not setting userData in Database
Boolean isSignUpSuccess = true;
complete_btn.setOnClickListener(this);
#Override
public void onClick(View view) {
int id = view.getId();
switch (id){
case R.id.complete_btn:
boolean check_pw = checkPassword(userPassword_textInput,check_userpw_textInput);
if(check_pw) {
if(isSignUpSuccess) {
isComplete();
}else{
onSignUpComplete(true);
}
}else{
Toast.makeText(this, "비밀번호 일치 오류입니다. 다시 입력해주세요.", Toast.LENGTH_SHORT).show();
}
break;
}
}

Delete Realm object from RealmRecyclerViewAdapter

I'm getting a lot of IllegalStateExceptions, that are hard for me to debug.
They occur when I'm deleting a Realm object from a RealmAdapter.
For the RealmAdapter, I'm using the 'io.realm:android-adapters:1.3.0' version.
This is how I delete my object on long press in my adapter:
//Delete message object
new MaterialDialog.Builder(holder.cardView.getContext()).title("Delete")
.content("Delete message?")
.positiveText("YES")
.negativeText("Cancel")
.onPositive(new MaterialDialog.SingleButtonCallback() {
#Override
public void onClick(#NonNull MaterialDialog dialog, #NonNull DialogAction which) {
//Call delete
ApiManager.ApiManagerService apiManagerService = ApiManager.createService(ApiManager.ApiManagerService.class);
apiManagerService.deleteMessage(message.getId()).enqueue(new Callback<Void>() {
#Override
public void onResponse(Call<Void> call, Response<Void> response) {
Logger.d("delete message onResponse callback");
//Delete from realm
Realm realm = Realm.getDefaultInstance();
realm.beginTransaction();
try {
message.deleteFromRealm();
} catch(Exception e) {
e.printStackTrace();
}
realm.commitTransaction();
//Notify adapter
notifyDataSetChanged();
}
#Override
public void onFailure(Call<Void> call, Throwable t) {
Logger.d("delete message onFailure callback");
}
});
}
})
.show();
return false;
}
Is the correct way to handle deleting an object from inside an adapter?
This
#Override
public void onResponse(Call<Void> call, Response<Void> response) {
Logger.d("delete message onResponse callback");
//Delete from realm
Realm realm = Realm.getDefaultInstance();
realm.beginTransaction();
try {
message.deleteFromRealm();
} catch(Exception e) {
e.printStackTrace();
}
realm.commitTransaction();
//Notify adapter
notifyDataSetChanged();
}
should be
#Override
public void onResponse(Call<Void> call, Response<Void> response) {
Logger.d("delete message onResponse callback");
//Delete from realm
final long messageId = message.getId();
Realm realm = Realm.getDefaultInstance(); // TODO: use Realm bound to lifecycle
realm.executeTransactionAsync(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
realm.where(Message.class).equalTo("messageId", messageId).findAll().deleteAllFromRealm();
}
});
realm.close();
//Notify adapter
////notifyDataSetChanged();
}

using Rxjava with retrofit and realm

i want to use the cached data in realm then update the data from server using retrofit. i managed that by the following:
public void getNotifications() {
Observable.concat(getCashedNotifications(), downloadNotification())
.subscribe(new Action1<List<Notification>>() {
#Override
public void call(List<Notification> notifications) {
setSize(notifications.size() + "");
}
});
}
private Observable<List<Notification>> getCashedNotifications() {
return Observable.just(mRealm.copyFromRealm(mRealm.where(Notification.class).findAll()));
}
private Observable<List<Notification>> downloadNotification() {
return mApiHandler.createRetrofitService(NotificationServices.class)
.getNotificationByUser(10)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(new Action1<NotificationResponse>() {
#Override
public void call(final NotificationResponse notificationResponse) {
setLoading(false);
mRealm.executeTransactionAsync(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
realm.copyToRealmOrUpdate(notificationResponse.getResult().getData().getNotifications());
}
});
}
})
.map(new Func1<NotificationResponse, List<Notification>>() {
#Override
public List<Notification> call(NotificationResponse notificationResponse) {
if (notificationResponse.getResult() != null) {
return notificationResponse.getResult().getData().getNotifications();
} else {
return new ArrayList<>();
}
}
});
}
my problem is to get the current status like :
1- if there is no data in realm show progress
2- if there is no data and no network show error dialog
3- if there is data in realm and no network show the data from realm only
4- if there is no data in realm and no data from retrofit show no data state
any idea how to know the resuslts from concat are from ? (retrofit or realm)
what i ended up with is to edit the getNotifications method to the following
public void getNotifications() {
setNoData(false);
setLoading(false);
if (ConectivityUtils.isDeviceConnectedToNetwork(mContext)) {
if (mRealm.where(Notification.class).count() > 0) {
Observable.concat(getCashedNotifications(), downloadNotification())
.subscribe(new Action1<List<Notification>>() {
#Override
public void call(List<Notification> notifications) {
setSize(notifications.size() + "");
}
});
} else {
// show progress
setLoading(true);
downloadNotification().subscribe(new Action1<List<Notification>>() {
#Override
public void call(List<Notification> notifications) {
setLoading(false);
if (notifications.size() > 0) {
setSize(notifications.size() + "");
} else {
// no data in realm and retrofit
setNoData(true);
setErrorMessage("No data");
}
}
});
}
} else {
if (mRealm.where(Notification.class).count() > 0) {
getCashedNotifications().subscribe(new Action1<List<Notification>>() {
#Override
public void call(List<Notification> notifications) {
setSize(notifications.size() + "");
}
});
} else {
//show no network
setNoData(true);
setErrorMessage("No Network");
}
}
}
but i believe that there is better and cleaner solution than this

Categories

Resources