I am using room database in my app.The app shows books under three categories All Books,Home Books and Library Books.The app shows books data based on user selection.Everything works fine,the app shows correct category books,but when user deletes a Book from any category then the app and list refreshes, then some times app shows wrong data means if a user is viewing books under Home Books category and he deletes a book then the app shows him random books instead of showing his selected Home Books.
// This is how I am loading data:
public void loadBooks(){
if(booksType==1){
mBookViewModel.getAllBooks().observe(this, new Observer<List<Books>>() {
#Override
public void onChanged(#Nullable final List<Books>books) {
adapter.setBooks(books);
}
});
}
if(booksType==2){
mBookViewModel.getHomeBooks().observe(this, new Observer<List<Books>>() {
#Override
public void onChanged(#Nullable final List<Books>books) {
// Update the cached copy of the words in the adapter.
adapter.setBooks(books);
}
});
}
if(booksType==3){
mBookViewModel.getLibrarayBooks().observe(this, new Observer<List<Books>>() {
#Override
public void onChanged(#Nullable final List<Books>books) {
// Update the cached copy of the words in the adapter.
adapter.setBooks(books);
}
});
}
calculateSum();// calculating sum of values of a column.
}
public void calculateSum(){
double total=mBookViewModel.getBookSum();
}
// This how I am deleting a book:
public void delete(Books book){
int rowsDeleted = mBookViewModel.deleteBook(book);
loadBooks(); //have to call this method as I am doing other stuff also.Like calculating the sum of other integer fields.
// suppose user is viewing Home Books(means bookType==2) after this call instead of showing user Home Books the app shows him any random list of books.It does not happen always but after user deletes five to six books continuously and fast.
}
// My View Model:
LiveData<List<Books>> getAllBooks() {return mRepository.getAllBooks(); }
LiveData<List<Books>> getHomeBooks() {return mRepository.getHomeBooks(); }
LiveData<List<Books>> getLibraryBooks() {return mRepository.getLibraryBooks(); }
double getBookSum() {return mRepository.getBookSum(); }
// Repository:
LiveData<List<Books>> getallBooks() {
try {
return new getAllBooksAsyncTask(mBooksDao).execute().get();
} catch (ExecutionException e) {
e.printStackTrace();
return null;
} catch (InterruptedException e) {
e.printStackTrace();
return null;
}
}
private static class getAllBooksAsyncTask extends AsyncTask<Void, Void, LiveData<List<Books>>> {
private BooksDao mAsyncTaskDao;
getAllBooksAscAsyncTask(BooksDao dao) {
mAsyncTaskDao = dao;
}
#Override
protected LiveData<List<Books>> doInBackground(Void... voids) {
return mAsyncTaskDao.getAllBooks();
}
}
LiveData<List<Books>> getallBooks() {
try {
return new getAllBooksAsyncTask(mBooksDao).execute().get();
} catch (ExecutionException e) {
e.printStackTrace();
return null;
} catch (InterruptedException e) {
e.printStackTrace();
return null;
}
}
private static class getHomeBooksAsyncTask extends AsyncTask<Void, Void, LiveData<List<Books>>> {
private BooksDao mAsyncTaskDao;
getHomeBooksAscAsyncTask(BooksDao dao) {
mAsyncTaskDao = dao;
}
#Override
protected LiveData<List<Books>> doInBackground(Void... voids) {
return mAsyncTaskDao.getHomeBooks();
}
}
LiveData<List<Books>> getallBooks() {
try {
return new getAllBooksAsyncTask(mBooksDao).execute().get();
} catch (ExecutionException e) {
e.printStackTrace();
return null;
} catch (InterruptedException e) {
e.printStackTrace();
return null;
}
}
private static class getLibraryBooksAsyncTask extends AsyncTask<Void, Void, LiveData<List<Books>>> {
private BooksDao mAsyncTaskDao;
getLibraryBooksAscAsyncTask(BooksDao dao) {
mAsyncTaskDao = dao;
}
#Override
protected LiveData<List<Books>> doInBackground(Void... voids) {
return mAsyncTaskDao.getLibraryBooks();
}
}
public double getBookSum() {
try {
return new getBookSumAsyncTask(mBookDao).execute().get();
} catch (ExecutionException e) {
e.printStackTrace();
return 0;
} catch (InterruptedException e) {
e.printStackTrace();
return 0;
}
}
private static class getBookSumAsyncTask extends AsyncTask<Void, Void, Double> {
private BookDao mAsyncTaskDao;
getBookSumAsyncTask(BookDao dao) {
mAsyncTaskDao = dao;
}
#Override
protected Double doInBackground(Void... voids) {
return mAsyncTaskDao.getBookSum();
}
}
// Dao:
#Query("SELECT * FROM books WHERE type = 1 ")
LiveData<List<Books>> getAllBooks();
#Query("SELECT * FROM books WHERE type = 2 ")
LiveData<List<Books>> getHomeBooks();
#Query("SELECT * FROM books WHERE type = 3 ")
LiveData<List<Books>> getLibraryBooks();
#Query("SELECT SUM(pages) FROM books ")
double getBookSum();
// Recycler View:
#Override
public void onBindViewHolder(#NonNull booksRecyclerAdapter.BookViewHolder holder, int position) {
if (mBookss != null) {
Books current = mBooks.get(position);
String name = current.getName();
holder.nameTextView.setText(name);
}
}
void setBooks(List<Books> book){
mBooks = book;
notifyDataSetChanged();
}
#Override
public int getItemCount() {
if (mBooks != null)
return mBooks.size();
else return 0;
}
public Books getBookAtPosition (int position) {
return mBooks.get(position);
}
I have tried adding adapter.notifyDataSetChanged() and adapter.notifyItemRemoved(position); but it does not work.Also,if there is something wrong in my codes then why it does not happen always,it happens sometimes usually after deleting five or six items continuously.
Any help is highly appreciated.
After much trying I figured out that the problem was because of the adapter.The adapter was loading previously selected books list e.g. if a user first selects homeBooks and then selects allBooks and perform a delete query on any one book in allBooks list then after the delete operation instead of keeping the user on allBooks list the adapter was showing him homeBooks list. As I was using same adapter for all three cases.I think this may be a problem with Room Database .So,when I used different adapters for different cases everything worked as expected.I don't know whether this is the correct way to do it but for now it is working.So the code now becomes
public void loadBooks(){
if(booksType==1){
bookRecyclerAdapter adapter1=new bookRecyclerAdapter(this);
recyclerView.setAdapter(adapter1);
mBookViewModel.getAllBooks().observe(this, new Observer<List<Books>>() {
#Override
public void onChanged(#Nullable final List<Books>books) {
adapter1.setBooks(books);
}
});
}
if(booksType==2){
bookRecyclerAdapter adapter2=new bookRecyclerAdapter(this);
recyclerView.setAdapter(adapter2);
mBookViewModel.getHomeBooks().observe(this, new Observer<List<Books>>() {
#Override
public void onChanged(#Nullable final List<Books>books) {
// Update the cached copy of the words in the adapter.
adapter2.setBooks(books);
}
});
}
if(booksType==3){
bookRecyclerAdapter adapter3=new bookRecyclerAdapter(this);
recyclerView.setAdapter(adapter3);
mBookViewModel.getLibrarayBooks().observe(this, new Observer<List<Books>>() {
#Override
public void onChanged(#Nullable final List<Books>books) {
// Update the cached copy of the words in the adapter.
adapter3.setBooks(books);
}
});
}
calculateSum();// calculating sum of values of a column.
}
Related
I have this methods
private void changeContacts() {
if (mOnlyDisplayContacts) {
listContact = fetchContactResponse(mView);
} else {
// Other code
}
contactAdapter = new ContactsAdapter(context, listContact, this);
mContactsList.setAdapter(mContactAdapter);
mContactAdapter.notifyDataSetChanged();
}
private List<Contact> fetchContactResponse(final String view) {
AsyncContactSearch mLoadContactTask = new AsyncContactSearch(context, limit, offset, view, search);
try {
listContacts = mLoadContactTask.execute().get();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return listContacts;
}
Class Task
public class AsyncContactSearch extends AsyncTask<Void, Void, List<LinphoneContact>> {
private Context context;
private int limit, offset;
private String view, search;
public AsyncContactSearch(Context context, int limit, int offset, String view, String search) {
this.context = context;
this.limit = limit;
this.offset = offset;
this.view = view;
this.search = search;
}
#Override
protected List<Contact> doInBackground(Void... voids) {
String domain = SharedPreferencesManager.getDomain(context);
String authToken = SharedPreferencesManager.getAuthtoken(context);
final List<Contact> listContact = new ArrayList<>();
RestAPI RestAPI = RetrofitHelper.create(RestAPI.class, domain);
Call<ContactList> searchWithTerms =
userRestAPI.searchWithTerms(authToken, "", limit, offset);
searchWithTerms.enqueue(
new Callback<ContactList>() {
#Override
public void onResponse(Call<ContactList> call, Response<ContactList> response) {
ContactList contactList = response.body();
if (contactList == null) {
return;
}
List<Contact> contacts = contactList.getRows();
for (Contact c : contacts) {
listContact.add(
ContactsManager.getInstance().addFromAPI(c));
}
}
#Override
public void onFailure(Call<ContactList> call, Throwable throwable) {}
});
Collections.sort(
listContact,
new Comparator() {
public int compare(Object o1, Object o2) {
String x1 = ((LinphoneContact) o1).getCompany();
String x2 = ((LinphoneContact) o2).getCompany();
int sComp = x1.compareTo(x2);
if (sComp != 0) {
return sComp;
}
String x3 = ((LinphoneContact) o1).getFirstName();
String x4 = ((LinphoneContact) o2).getFirstName();
return x3.compareTo(x4);
}
});
return listContact;
}
}
The problem is (debugging the code) that while the search task is still running, the method is triggered immediately contactAdapter = new ContactsAdapter(context, listContact, this);listContact is empty,then the execution goes on assigns the Adapter to the ListView, while the recovery task goes on and inserts the elements into the List, on the screen the ListView remains empty
You are using the retrofit for API call so no need to use AsyncTask. The retrofit will make the API call asynchronously and deliver the result in callback onResponse(). Just move your logic inside callback onResponse().
I'm trying to build an app to fetch list of feed from server and display in Recyclerview. I am trying out basic implementation of LiveData like this.
I have set up an observer in my Fragment as follows:
viewModel = ViewModelProviders.of(getActivity()).get(SellViewModel.class);
viewModel.getSellItemList(19).observe(this, new Observer<List<LambdaSellRequestClass>>() {
#Override
public void onChanged(#Nullable List<LambdaSellRequestClass> sellItems) {
adapter.setSellEntities(sellItems);
}
});
My SellViewModel clas like this:
public class SellViewModel extends AndroidViewModel {
private SellRepository repository;
private MutableLiveData<List<LambdaSellRequestClass>> sellItems;
public SellViewModel(#NonNull Application application) {
super(application);
repository = new SellRepository(application);
try {
if (sellItems == null) {
sellItems = new MutableLiveData<>();
sellItems.postValue(repository.getSellItemList(user_id));
}
}catch (Exception e) {
Log.d("SELLFRAGMENT", "Error: " + e.getLocalizedMessage());
}
}
public MutableLiveData<List<LambdaSellRequestClass>> getSellItemList(int userId) throws ExecutionException, InterruptedException {
return sellItems;
}
}
My SellRepository like this:
public class SellRepository {
public SellRepository(Application application) {
}
public List<LambdaSellRequestClass> getSellItemList(int userId) throws ExecutionException, InterruptedException {
return new SellRepository.GetSellItemListAsync(SellRepository.this).execute(userId).get();
}
private static class GetSellItemListAsync extends AsyncTask<Integer, Void, List<LambdaSellRequestClass>> {
List<LambdaSellRequestClass> list = new ArrayList<>();
public GetSellItemListAsync() {
}
#Override
protected List<LambdaSellRequestClass> doInBackground(Integer... integers) {
final int userID = integers[0];
list =
lambdaFunctionsCalls.getSellItemByUser_lambda(requestClass).getSellItems();
return list;
}
}
My problem is when I add new sell items to database its not update mobile app.
In my program a number of values are stored on the server.
I read these data using of the AsyncTask class from the server.
This is my code:
public class TestActivity extends AppCompatActivity {
private static List<String> mPackName;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPackName = new ArrayList<>();
try {
boolean check = new GetDataAsyncTask().execute("1234567").get();
} catch (InterruptedException e) {
} catch (ExecutionException e) {
e.printStackTrace();
e.printStackTrace();
}
}
private class GetDataAsyncTask extends AsyncTask<String, Void, Boolean> {
#Override
protected Boolean doInBackground(String... params) {
final String mCode = params[0];
APIGettingPosts apiGettingPosts = new APIGettingPosts(TestActivity.this, "get_off_code.php");
apiGettingPosts.getOffCode(new APIGettingPosts.OnOffCodeReceived() {
#Override
public void onReceived(List<Posts> posts) {
if (!(posts == null || posts.isEmpty()))
for (int i = 0; i < posts.size(); ++i) {
mPackName.add(posts.get(i).getTitle());
Log.e("mPackName["+String.valueOf(i)+"]",mPackName.get(i));
}
}
});
Log.e("Size of mPackName: ", String.valueOf(mPackName.size()));
for (int i = 0; i < mPackName.size(); ++i)
if (mCode.equals(mPackName.get(i))) {
Log.e("Is Equal: ", mPackName.get(i));
return true;
}
return false;
}
}
}
The program correctly receives the data from the server and stores it in the mPackName list. At the end of the doInBackground function, the program checks if the input value in the GetDataAsyncTask().execute("1234567") function exists in the mPackName list, returns the true value.
Although the input value of the GetDataAsyncTask().execute("1234567") function is in the mPackNamelist, the program returns the false value.
The Log cat output is as follows:
08-28/com.green E/Size of mPackName:: 0
08-28/com.green E/mPackName[0]: 1234567
08-28/com.green E/mPackName[1]: QAZXSWE
08-28/com.green E/mPackName[2]: QWERTYU
The size of the mPackName list is also zero in Log cat , although it has three values {'1234567','QAZXSWE','QWERTYU'}.
The question is: How do I search '1234567' value in the mPackName list to return the true value in check = new GetDataAsyncTask().execute("1234567").get();
code?
Edited Answer
Looks like you even don't need AsyncTask as getOffCode method already runs in background thread.
Remove GetDataAsyncTask class and create a method like below.
private void search(final SearchCallback callback) {
APIGettingPosts apiGettingPosts = new APIGettingPosts(TestActivity.this, "get_off_code.php");
apiGettingPosts.getOffCode(new APIGettingPosts.OnOffCodeReceived() {
#Override
public void onReceived(List<Posts> posts) {
if (!(posts == null || posts.isEmpty())) {
for (int i = 0; i < posts.size(); ++i) {
mPackName.add(posts.get(i).getTitle());
Log.e("mPackName[" + String.valueOf(i) + "]", mPackName.get(i));
if (mCode.equals(mPackName.get(i))) {
callback.onSearchFound(true);
break;
}
}
}
callback.onSearchFound(false);
}
});
}
public interface SearchCallback{
void onSearchFound(boolean success);
}
Then call from onCreate method like below
search(new SearchCallback(){
#Override
public void onSearchFound(boolean success) {
}
});
Try placing a switch in the onPostExecute() method.
EG.
...
private class GetDataAsyncTask extends AsyncTask<String, Void, Boolean> {
#Override
void onPostExecute(Object o){
handleResults()
}
...
void handleResults(){
// Insert your check here
}
I am creating an app where user can upload images, I am uploading images one after another using retrofit. Right now I am running a for loop for it, but it is not a good way to do it. I cannot use service because I need progress dialog as well on main screen to let user know upload is happening. Is there a way to maintain some kind of queue to handle this?
You can use the AsyncTask and Retrofit to do it it can be done with the retrofit alone but as I have already done it with AsyncTask have a look.
public class AsyncBulkUpload extends AsyncTask<Boolean, Integer, Boolean> {
private ApiInterface mApiInterface;
private Call<ResponseBody> mResponseBodyCall;
private Response<ResponseBody> mResponseBody;
private RequestBody mRequestBody;
private Service mService;
private Bitmap mItemBitmap;
public int mTotalCount = 0;
public AsyncBulkUpload(Service service) {
mService=service;
mApiInterface = ApiClient.getClient(mService.getApplicationContext()).create(ApiInterface.class);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
mTotalCount = sClosetList.size();
//Show you dialog
}
#Override
protected Boolean doInBackground(Boolean... itsRetry) {
/**
*Check if its retry or not
* if yes don't get the placeholder ids.
* or else hit and get place holder ids
*/
//Run your loop here.
return upload();
}
private Boolean upload() {
if (isCancelled())
return false;
if (sClosetList.size() > 0) {
//Item image
try {
mItemBitmap = Glide.with(mService.getApplicationContext())
.load(sClosetList.get(0).mItemImage)
.asBitmap()
.into(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
.get();
} catch (InterruptedException e) {
//Coudnt get the image so cant go further
LogPrint.printError("WHILE GETTING BITMPAP");
return false;
} catch (ExecutionException e) {
//Coudnt get the image so cant go further
LogPrint.printError("WHILE GETTING BITMPAP");
return false;
}
FormBody.Builder bodyBuilder = new FormBody.Builder();
bodyBuilder.add("image", mItemBitmap);
/**
*Label image can or can not be available
*/
mRequestBody = bodyBuilder.build();
mResponseBodyCall = mApiInterface.uploadProducts(mRequestBody);
try {
mResponseBody = mResponseBodyCall.execute();
} catch (IOException e) {
e.printStackTrace();
return false;
}
if (!mResponseBody.isSuccessful()) {
/**
*Some server error try again
*/
return false;
}
}
return true;
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
//Update your progressbar
}
#Override
protected void onPostExecute(Boolean aBoolean) {
super.onPostExecute(aBoolean);
//Dismiss the dialog
if (aBoolean) {
Toast.makeText(mService, R.string.uploaded_successful, Toast.LENGTH_LONG).show();
}
}
}
I store data with sqlite database from remote server with AsyncTask..
I have used Retrofit to fetch data, and now I want to store that data into sqlite... I already have DatabaseHelper.class , Model Class and NavigationDrawer in that i am performing AsynckTask in MainActivity.
private class getDataToSqlite extends AsyncTask<Post, Void, Void>{
#Override
protected Void doInBackground(Post... params) {
apiInterface.getContacts().enqueue(new Callback<List<Post>>() {
#Override
public void onResponse(Call<List<Post>> call, Response<List<Post>> response) {
if (response.isSuccessful()){
contacts = response.body();
for (int i=0; i < contacts.size(); i++){
Post post = contacts.get(i);
SaveToDatabase task = new SaveToDatabase();
task.execute(post);
adapter.addPost(post);
}
}else {
}
}
#Override
public void onFailure(Call<List<Post>> call, Throwable t) {
Toast.makeText(getApplicationContext(), "Error" + t.toString(), Toast.LENGTH_SHORT).show();
}
});
return null ;
}
}
private class SaveToDatabase extends AsyncTask<Post, Void , Void> {
#Override
protected Void doInBackground(Post... params) {
Post post = params[0];
try {
myDb.addData(post);
} catch (Exception e) {
Log.d(TAG, e.getMessage());
}
return null;
}
}
That class present in MainActivity
and i call the class in onCreate
new getDataToSqlite();
where i doing wrong please tell me
You can do something like this that I have already Done :
public boolean SyncCityMasterToDevice() {
try {
DatabaseHandler db = new DatabaseHandler(mContext);
db.dbDelete(TableCityMaster.TABLE);
List<CityMaster> cityMasterList = ServerRepo.getCities();
db.dbAddCity(cityMasterList);
Log.d(TAG, "SyncCityMasterToDevice: ");
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
ServerRepo.getCities(); is a Retrofit Call.
I have called SyncCityMasterToDevice() method in an Async task
`DatabaseHandler` is the Database Helper Class.