Digvijay
Digvijay

Reputation: 3281

Fetching data using retrofit2 and saving in room

I am using retrofit2 for fetching data from the server and after fetching saving data in room database and then showing in recycler view.Whenever app runs its fetches data from the server and save it in room database.I have successfully fetched JSON data from server and saved in room database and from room it is properly showing in recycler view.

Problem: Whenever data fetches from the server it inserts the same old data in room again due to which same data shows multiple times in recycler view.

What I want: I don't want recycler view to show same data multiple times.I don't want to copy same data again in room database.

This is what I have done so far:

UserDao.java

@Dao
public interface UserDao {

@Insert(onConflict = OnConflictStrategy.REPLACE)
void Insert(User... users);

@Query("SELECT * FROM Users")
LiveData<List<User>> getRoomUsers();

}

User.java

@Entity(tableName = "Users")
public class User {

@PrimaryKey
private String id;

@ColumnInfo(name = "name")
@SerializedName("name")
@Expose
private String name;

@ColumnInfo(name = "age")
@SerializedName("age")
@Expose
private String age;

public User(String id,String name, String age) {
this.id = id; 
this.name = name;
this.age = age;
}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getAge() {
return age;
}

public void setAge(String age) {
this.age = age;
}
}    

UserRepository.java

public class UserRepository {

private Context context;
private UserDb userDb;
private LiveData<List<User>> listLiveData;

public UserRepository(Context context) {
this.context = context;
userDb = UserDb.getInstance(context);
listLiveData = userDb.userDao().getRoomUsers();
}

public void getUserList(){

      Retrofit retrofit = RetrofitClient.getInstance();
      ApiService apiService = retrofit.create(ApiService.class);

      Call<List<User>> userList = apiService.getUser();

      userList.enqueue(new Callback<List<User>>() {
          @Override
          public void onResponse(Call<List<User>> call, final Response<List<User>> response) {

              Completable.fromAction(new Action() {
                      @Override
                      public void run() throws Exception {

                          if(response.body() != null) {

                              List<User> list = response.body();

                              for (int i = 0; i < list.size(); i++) {

                                  String names = list.get(i).getName();
                                  String age = list.get(i).getAge();
                                  String id = UUID.randomUUID().toString();


                                  User user = new User(id,names,age);

                                  userDb.userDao().Insert(user);
                              }

                          }

                      }
                  }).subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new CompletableObserver() {
                        @Override
                        public void onSubscribe(Disposable d) {

                        }

                        @Override
                        public void onComplete() {

                            Toast.makeText(context,"Data inserted",Toast.LENGTH_SHORT).show();
                        }

                        @Override
                        public void onError(Throwable e) {

                            Toast.makeText(context,e.getMessage(),Toast.LENGTH_SHORT).show();
                        }
                    });


          }

          @Override
          public void onFailure(Call<List<User>> call, Throwable t) {
              Toast.makeText(context,t.getMessage(),Toast.LENGTH_LONG).show();
          }
      });

}

public LiveData<List<User>> getRoomUsers(){

    return listLiveData;
  }
}

UserViewModel.java

public class UserViewModel extends AndroidViewModel {

private UserRepository repo;
private LiveData<List<User>> listLiveData;

public UserViewModel(@NonNull Application application) {
super(application);

repo = new UserRepository(application);
listLiveData = repo.getRoomUsers();

}

public LiveData<List<User>> getListLiveData() {
return listLiveData;
}
}

MainActivity.java

public class MainActivity extends AppCompatActivity {

UserRepository userRepository;
RecyclerView recyclerView;
UserViewModel userModel;
List<User> userList;
UserAdapter adapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

userRepository = new UserRepository(this);
userModel = ViewModelProviders.of(this).get(UserViewModel.class);

recyclerView = findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));

userList = new ArrayList<>();

adapter = new UserAdapter(userList,this);
recyclerView.setAdapter(adapter);

userModel.getListLiveData().observe(this, new Observer<List<User>>() {

    @Override
    public void onChanged(List<User> users) {
        adapter.setUserList(users);
    }
});

FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Intent i = new Intent(MainActivity.this,AddUser.class);
        startActivity(i);
    }
});

    userRepository.getUserList();
}

UserAdapter.java

public class UserAdapter extends 
RecyclerView.Adapter<UserAdapter.ViewHolder> {

List<User> userList;
Context context;

public UserAdapter(List<User> userList, Context context) {
    this.userList = userList;
    this.context = context;
}

@NonNull
@Override
public UserAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.user_row_layout,parent,false);

    ViewHolder viewHolder = new ViewHolder(v);

    return viewHolder;
}

@Override
public void onBindViewHolder(@NonNull UserAdapter.ViewHolder holder, int position) {

    User users = userList.get(position);

    holder.row_name.setText(users.getName());
    holder.row_age.setText(users.getAge());
}

@Override
public int getItemCount() {
    return userList.size();
}

public void setUserList(List<User> userList) {
    this.userList = userList;
    notifyDataSetChanged();
}

public class ViewHolder extends RecyclerView.ViewHolder {

    TextView row_name,row_age;

    public ViewHolder(@NonNull View itemView) {
        super(itemView);

        row_name = itemView.findViewById(R.id.row_name);
        row_age = itemView.findViewById(R.id.row_age);
    }
  }
}

Someone please let me know how can I achieve desired result. Any help would be appreciated.

THANKS

Upvotes: 1

Views: 2277

Answers (2)

Zun
Zun

Reputation: 1710

The answer is quite simple, you do not have a unique primary key. You're generating a key yourself using

String id = UUID.randomUUID().toString();

In your first request, you might have this:

User("mdkasdkasjkdjakjdkasd", "Zun", 22);

and in your second request you get

User("djei3ujf493j9fj49dj9", "Zun", 22);

as such, you'll always have duplicate entries in your database since room considers the user with name 'Zun" to NOT be the same.

In order to solve this, create a unique primary key that's unique to a User class. Do not use a random text generator.

Upvotes: 2

Hardik Chauhan
Hardik Chauhan

Reputation: 2746

Okay you should do it like this,

  1. check if user is exist in db or not,
@Query("SELECT * FROM user WHERE id = :userId")
public User idUserExists(int userId);
  1. if it does than add update query
@Update
public void updateUser(User user); // keep the model with same user id
  1. else insert the new record
@Insert 
public void insertUser(User user); // Model with new user Id

Upvotes: -1

Related Questions