0

I am trying to insert data in RoomDb but at the the time of data insertion app is crashing even if I am writing insertion operation in thread.I have a recycler view adapter class in which I have a click listener based on that I want to add data in RoomDb.

Here is my logcat error:

java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.

Below is my code:

ProductAdapter.class

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

List<Product> productList;
Context context;

public ProductAdapter(List<Product> productList, Context context) {
    this.productList = productList;
    this.context = context;
}

@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.product_row,parent,false);
    return new ViewHolder(v);
}

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

    Product product = productList.get(position);

    holder.productName.setText(product.getName());
    holder.productPrice.setText(product.getPrice());
    Glide.with(context).load(product.getProduct_image()).placeholder(R.color.teal_200).into(holder.productImage);

    holder.productCard.setAnimation(AnimationUtils.loadAnimation(context,R.anim.recycler_anim));

    holder.addToCart.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            holder.tick.setVisibility(View.VISIBLE);
            holder.addToCart.setVisibility(View.INVISIBLE);

            ((AppCompatActivity)context).runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    ProductDb db = ProductDb.getInstance(context);
                    CartProduct  cartProduct = new CartProduct(product.get_id(),product.getName(),product.getProduct_image(),
                                               product.getPrice(),"1");
                    db.productDao().insert(cartProduct);
                }
            });
         }
    });
}

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

public class ViewHolder extends RecyclerView.ViewHolder {

    ImageView productImage,addToCart,tick;
    TextView productName,productPrice;
    CardView productCard;

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

        productImage = itemView.findViewById(R.id.productImage);
        productName = itemView.findViewById(R.id.productName);
        productPrice = itemView.findViewById(R.id.productPrice);
        productCard = itemView.findViewById(R.id.productCard);
        tick = itemView.findViewById(R.id.tick);
        addToCart = itemView.findViewById(R.id.addToCart);
    }
  }
}

How can I overcome this issue?

halfer
  • 19,824
  • 17
  • 99
  • 186
Digvijay
  • 2,887
  • 3
  • 36
  • 86
  • Does this answer your question? [Android Room - simple select query - Cannot access database on the main thread](https://stackoverflow.com/questions/44167111/android-room-simple-select-query-cannot-access-database-on-the-main-thread) – a_local_nobody Jan 14 '21 at 09:15
  • the point of getting a stack trace is to identify the cause of the exception. once you have the exception, you can do research on that, so try to find others who have had exactly that same problem, in this case, the problem you're facing has occurred numerous times, so you should be able to find a solution without having to ask the same question again – a_local_nobody Jan 14 '21 at 09:17
  • `even if I am writing insertion operation in thread` -> `.runOnUiThread` -> `Cannot access database on the main thread ` – a_local_nobody Jan 14 '21 at 09:18

1 Answers1

1

This exception is thrown when you try to access the database on main thread without declaring allowMainThreadQueries() in database builder. if you want to access database on main thread then construct your database object like following Room.databaseBuilder(App.getInstance().getApplicationContext(), AppDatabase.class, DB_NAME).allowMainThreadQueries()

But that is not recommended. Use async task or any other background thread for database operations to have a smooth user experience

Updates:

Async task is deprected. you can check more alternatives to async task on this

A sample code that i use for database operations with RxJava is

Single.fromCallable(new Callable<Long>() {
        @Override
        public Long call() throws Exception {
            return getProductDao().insert(product);
        }
    }).observeOn(Threads.ui())
            .delaySubscription(1000, TimeUnit.MILLISECONDS)
            .subscribeOn(Threads.io())
            .subscribe(new RxGenListener<Long>() {
                @Override
                public void onSuccess(Long aLong) {
                    listener.onCallback(aLong);
                }
            });
Bilal Bangash
  • 207
  • 2
  • 8