删除行 onclick 时房间数据库出错
Room database error while deleting row onclick
我已经将 room SQLite 数据库定义为:
@Database(entities = {PlaceSaved.class},version = 1)
public abstract class PlaceDatabase extends RoomDatabase {
public abstract DatabaseInterface databaseInterface();
@Override
protected SupportSQLiteOpenHelper createOpenHelper(DatabaseConfiguration config) {
return null;
}
@Override
protected InvalidationTracker createInvalidationTracker() {
return null;
}
}
定义在:
@Entity
public class PlaceSaved {
@PrimaryKey(autoGenerate = true)
private int id;
@ColumnInfo(name = "time")
private String time;
@ColumnInfo(name="title")
private String title;
public PlaceSaved(){
}
public PlaceSaved(String time, String title) {
this.time = time;
this.title = title;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
对应的DAO是:
@Dao
public interface DatabaseInterface {
@Query("SELECT * FROM placesaved")
List<PlaceSaved> getAllItems();
@Insert
void insertAll(PlaceSaved... todoListItems);
@Delete
public void delete(PlaceSaved... todoListItems);
@Update
public void update(PlaceSaved...todoListItems);
}
并且这些数据通过 recyclerview 显示,每个项目布局定义为:
<TextView
android:id="@+id/secondLine"/>
<TextView
android:id="@+id/firstLine"/>
<ImageButton
android:id="@+id/delicon"/>
现在,我想用这个delicon
ImageButton
删除相应的条目。
因此,我尝试将其作为(注意:已更新,请参阅末尾的更新代码):
public class PlacesAdapter extends RecyclerView.Adapter<PlacesAdapter.ViewHolder> {
//PlaceDatabase db;
List<PlaceSaved> items;
public PlacesAdapter(List<PlaceSaved> items) {
this.items = items;
}
@Override
public PlacesAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.places_list_item,parent,false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(PlacesAdapter.ViewHolder holder, final int position) {
holder.name.setText(items.get(position).getTitle());
holder.time.setText(items.get(position).getTime());
// holder.delbutton.setClickable(true);
holder.delbutton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
removeItem(items);
}
});
}
@Override
public int getItemCount() {
return items.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
public TextView name;
public TextView time;
public ImageButton delbutton;
public ViewHolder(View itemView) {
super(itemView);
name = itemView.findViewById(R.id.secondLine);
time= itemView.findViewById(R.id.firstLine);
delbutton = itemView.findViewById(R.id.delicon);
}
}
private void removeItem(PlaceSaved infoItem){
PlaceSaved placeSaved = new PlaceSaved();
placeSaved.delete(infoItem);
}
}
recyclerview 被调用为:(**注意:onCreate 已更新并在最后发布)
public class PlacesActivity extends AppCompatActivity {
FloatingActionButton fab, fab1, fab2, fab3;
LinearLayout fabLayout1, fabLayout2, fabLayout3;
boolean isFABOpen=false;
View fabBGLayout;
public static RecyclerView recyclerView;
public static RecyclerView.Adapter adapter;
List<PlaceSaved> items;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.places_layout);
//whenever the activity is started, it reads data from database and stores it into
// local array list 'items'
final PlaceDatabase db = Room.databaseBuilder(getApplicationContext(), PlaceDatabase.class, "production")
.build();
//it is very bad practice to pull data from Room on main UI thread,
// that's why we create another thread which we use for getting the data and displaying it
Runnable r = new Runnable() {
@Override
public void run() {
items = db.databaseInterface().getAllItems();
recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplication()));
adapter = new PlacesAdapter(items);
adapter.notifyDataSetChanged();
recyclerView.setAdapter(adapter);
}
};
这给出了编译时间错误:
PlacesAdapter.java
Error:(43, 22) error: incompatible types: List<PlaceSaved> cannot be converted to PlaceSaved
Error:(68, 17) error: cannot find symbol method delete(PlaceSaved)
请帮我解决这个问题。
更新
根据 Vishu 的回答,我已将我的适配器更新为:
public class PlacesAdapter extends RecyclerView.Adapter<PlacesAdapter.ViewHolder> {
private static final String TAG = "MyActivity";
List<PlaceSaved> items;
PlaceDatabase db;
public PlacesAdapter(List<PlaceSaved> items, PlaceDatabase db) {
this.items = items;
this.db = db;
}
@Override
public PlacesAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.places_list_item,parent,false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(final PlacesAdapter.ViewHolder holder, final int position) {
holder.name.setText(items.get(position).getTitle());
holder.time.setText(items.get(position).getTime());
holder.delbutton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
removeItem(items.get(holder.getAdapterPosition()));
}
});
}
@Override
public int getItemCount() {
return items.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
public TextView name;
public TextView time;
public ImageButton delbutton;
public ViewHolder(View itemView) {
super(itemView);
name = itemView.findViewById(R.id.secondLine);
time= itemView.findViewById(R.id.firstLine);
delbutton = itemView.findViewById(R.id.delicon);
}
}
private void removeItem(PlaceSaved infoItem){
// db.delete(infoItem);
Log.v(TAG, "remove Item called");
}
}
并在 PlacesActivity 中:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.places_layout);
final PlaceDatabase db = Room.databaseBuilder(getApplicationContext(), PlaceDatabase.class, "production")
.build();
Runnable r = new Runnable() {
@Override
public void run() {
items = db.databaseInterface().getAllItems();
recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplication()));
adapter = new PlacesAdapter(items, db);
adapter.notifyDataSetChanged();
recyclerView.setAdapter(adapter);
}
};
仍然给出语法错误:
Error:(71, 17) error: cannot find symbol method delete(PlaceSaved)
和 2 个警告(不是因为 Vishu 的回答,之前就出现过):
PlaceSaved.java
Warning:(11, 8) There are multiple good constructors and Room will pick the no-arg constructor. You can use the @Ignore annotation to eliminate unwanted constructors.
PlaceDatabase.java
Warning:(13, 17) Schema export directory is not provided to the annotation processor so we cannot export the schema. You can either provide `room.schemaLocation` annotation processor argument OR set exportSchema to false.
错误:更新:
添加 db.databaseInterface().delete(infoItem);
在 removeitem 中给出:
java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
at android.arch.persistence.room.RoomDatabase.assertNotMainThread(RoomDatabase.java:164)
at android.arch.persistence.room.RoomDatabase.beginTransaction(RoomDatabase.java:211)
at DatabaseInterface_Impl.delete(DatabaseInterface_Impl.java:94)
at PlacesAdapter.removeItem(PlacesAdapter.java:69)
at PlacesAdapter.access[=21=]0(PlacesAdapter.java:20)
at PlacesAdapter.onClick(PlacesAdapter.java:45)
at android.view.View.performClick(View.java:6294)
你为什么要在 removeItem()
中超过 PlaceSaved
的 ArrayList
。 removeItem()
只接受 PlaceSaved
。
所以把你的 onclick
改成
removeItem(items.get(holder.getAdapterPosition()));
在方法签名中将 holder
设置为 final final PlacesAdapter.ViewHolder holder
否则将无法编译。
您在 PlaceDatabase
中定义了 delete
并且您正在调用 PlaceSaved
这就是为什么您得到 Error:(68, 17) error: cannot find symbol method delete(PlaceSaved)
你可以从 PlacesAdapter
传递 db
就像 items
和 PlacesAdapter(items, db)
改变
adapter = new PlacesAdapter(items);
到
adapter = new PlacesAdapter(items, db);
现在您的 PlacesAdapter 将拥有 db
个实例。你可以用 db.delete(infoItem)
替换 placeSaved.delete(infoItem);
改变
List<PlaceSaved> items;
public PlacesAdapter(List<PlaceSaved> items) {
this.items = items;
}
到
List<PlaceSaved> items;
PlaceDatabase db;
public PlacesAdapter(List<PlaceSaved> items, PlaceDatabase db) {
this.items = items;
this.db = db
}
并且
改变
placeSaved.delete(infoItem);
至
db.databaseInterface().delete(infoItem);
我已经将 room SQLite 数据库定义为:
@Database(entities = {PlaceSaved.class},version = 1)
public abstract class PlaceDatabase extends RoomDatabase {
public abstract DatabaseInterface databaseInterface();
@Override
protected SupportSQLiteOpenHelper createOpenHelper(DatabaseConfiguration config) {
return null;
}
@Override
protected InvalidationTracker createInvalidationTracker() {
return null;
}
}
定义在:
@Entity
public class PlaceSaved {
@PrimaryKey(autoGenerate = true)
private int id;
@ColumnInfo(name = "time")
private String time;
@ColumnInfo(name="title")
private String title;
public PlaceSaved(){
}
public PlaceSaved(String time, String title) {
this.time = time;
this.title = title;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
对应的DAO是:
@Dao
public interface DatabaseInterface {
@Query("SELECT * FROM placesaved")
List<PlaceSaved> getAllItems();
@Insert
void insertAll(PlaceSaved... todoListItems);
@Delete
public void delete(PlaceSaved... todoListItems);
@Update
public void update(PlaceSaved...todoListItems);
}
并且这些数据通过 recyclerview 显示,每个项目布局定义为:
<TextView
android:id="@+id/secondLine"/>
<TextView
android:id="@+id/firstLine"/>
<ImageButton
android:id="@+id/delicon"/>
现在,我想用这个delicon
ImageButton
删除相应的条目。
因此,我尝试将其作为(注意:已更新,请参阅末尾的更新代码):
public class PlacesAdapter extends RecyclerView.Adapter<PlacesAdapter.ViewHolder> {
//PlaceDatabase db;
List<PlaceSaved> items;
public PlacesAdapter(List<PlaceSaved> items) {
this.items = items;
}
@Override
public PlacesAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.places_list_item,parent,false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(PlacesAdapter.ViewHolder holder, final int position) {
holder.name.setText(items.get(position).getTitle());
holder.time.setText(items.get(position).getTime());
// holder.delbutton.setClickable(true);
holder.delbutton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
removeItem(items);
}
});
}
@Override
public int getItemCount() {
return items.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
public TextView name;
public TextView time;
public ImageButton delbutton;
public ViewHolder(View itemView) {
super(itemView);
name = itemView.findViewById(R.id.secondLine);
time= itemView.findViewById(R.id.firstLine);
delbutton = itemView.findViewById(R.id.delicon);
}
}
private void removeItem(PlaceSaved infoItem){
PlaceSaved placeSaved = new PlaceSaved();
placeSaved.delete(infoItem);
}
}
recyclerview 被调用为:(**注意:onCreate 已更新并在最后发布)
public class PlacesActivity extends AppCompatActivity {
FloatingActionButton fab, fab1, fab2, fab3;
LinearLayout fabLayout1, fabLayout2, fabLayout3;
boolean isFABOpen=false;
View fabBGLayout;
public static RecyclerView recyclerView;
public static RecyclerView.Adapter adapter;
List<PlaceSaved> items;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.places_layout);
//whenever the activity is started, it reads data from database and stores it into
// local array list 'items'
final PlaceDatabase db = Room.databaseBuilder(getApplicationContext(), PlaceDatabase.class, "production")
.build();
//it is very bad practice to pull data from Room on main UI thread,
// that's why we create another thread which we use for getting the data and displaying it
Runnable r = new Runnable() {
@Override
public void run() {
items = db.databaseInterface().getAllItems();
recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplication()));
adapter = new PlacesAdapter(items);
adapter.notifyDataSetChanged();
recyclerView.setAdapter(adapter);
}
};
这给出了编译时间错误:
PlacesAdapter.java
Error:(43, 22) error: incompatible types: List<PlaceSaved> cannot be converted to PlaceSaved
Error:(68, 17) error: cannot find symbol method delete(PlaceSaved)
请帮我解决这个问题。
更新 根据 Vishu 的回答,我已将我的适配器更新为:
public class PlacesAdapter extends RecyclerView.Adapter<PlacesAdapter.ViewHolder> {
private static final String TAG = "MyActivity";
List<PlaceSaved> items;
PlaceDatabase db;
public PlacesAdapter(List<PlaceSaved> items, PlaceDatabase db) {
this.items = items;
this.db = db;
}
@Override
public PlacesAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.places_list_item,parent,false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(final PlacesAdapter.ViewHolder holder, final int position) {
holder.name.setText(items.get(position).getTitle());
holder.time.setText(items.get(position).getTime());
holder.delbutton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
removeItem(items.get(holder.getAdapterPosition()));
}
});
}
@Override
public int getItemCount() {
return items.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
public TextView name;
public TextView time;
public ImageButton delbutton;
public ViewHolder(View itemView) {
super(itemView);
name = itemView.findViewById(R.id.secondLine);
time= itemView.findViewById(R.id.firstLine);
delbutton = itemView.findViewById(R.id.delicon);
}
}
private void removeItem(PlaceSaved infoItem){
// db.delete(infoItem);
Log.v(TAG, "remove Item called");
}
}
并在 PlacesActivity 中:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.places_layout);
final PlaceDatabase db = Room.databaseBuilder(getApplicationContext(), PlaceDatabase.class, "production")
.build();
Runnable r = new Runnable() {
@Override
public void run() {
items = db.databaseInterface().getAllItems();
recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplication()));
adapter = new PlacesAdapter(items, db);
adapter.notifyDataSetChanged();
recyclerView.setAdapter(adapter);
}
};
仍然给出语法错误:
Error:(71, 17) error: cannot find symbol method delete(PlaceSaved)
和 2 个警告(不是因为 Vishu 的回答,之前就出现过):
PlaceSaved.java
Warning:(11, 8) There are multiple good constructors and Room will pick the no-arg constructor. You can use the @Ignore annotation to eliminate unwanted constructors.
PlaceDatabase.java
Warning:(13, 17) Schema export directory is not provided to the annotation processor so we cannot export the schema. You can either provide `room.schemaLocation` annotation processor argument OR set exportSchema to false.
错误:更新:
添加 db.databaseInterface().delete(infoItem);
在 removeitem 中给出:
java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
at android.arch.persistence.room.RoomDatabase.assertNotMainThread(RoomDatabase.java:164)
at android.arch.persistence.room.RoomDatabase.beginTransaction(RoomDatabase.java:211)
at DatabaseInterface_Impl.delete(DatabaseInterface_Impl.java:94)
at PlacesAdapter.removeItem(PlacesAdapter.java:69)
at PlacesAdapter.access[=21=]0(PlacesAdapter.java:20)
at PlacesAdapter.onClick(PlacesAdapter.java:45)
at android.view.View.performClick(View.java:6294)
你为什么要在 removeItem()
中超过 PlaceSaved
的 ArrayList
。 removeItem()
只接受 PlaceSaved
。
所以把你的 onclick
改成
removeItem(items.get(holder.getAdapterPosition()));
在方法签名中将 holder
设置为 final final PlacesAdapter.ViewHolder holder
否则将无法编译。
您在 PlaceDatabase
中定义了 delete
并且您正在调用 PlaceSaved
这就是为什么您得到 Error:(68, 17) error: cannot find symbol method delete(PlaceSaved)
你可以从 PlacesAdapter
传递 db
就像 items
和 PlacesAdapter(items, db)
改变
adapter = new PlacesAdapter(items);
到
adapter = new PlacesAdapter(items, db);
现在您的 PlacesAdapter 将拥有 db
个实例。你可以用 db.delete(infoItem)
placeSaved.delete(infoItem);
改变
List<PlaceSaved> items;
public PlacesAdapter(List<PlaceSaved> items) {
this.items = items;
}
到
List<PlaceSaved> items;
PlaceDatabase db;
public PlacesAdapter(List<PlaceSaved> items, PlaceDatabase db) {
this.items = items;
this.db = db
}
并且 改变
placeSaved.delete(infoItem);
至
db.databaseInterface().delete(infoItem);