notifyDataSetChanged() 不适用于自定义 RecyclerView 适配器
notifyDataSetChanged() not working on custom RecyclerView adapter
我试图创建一个 recyclerView
来显示当前状态栏通知的列表。我创建了一个自定义适配器 (NotiRecyclerAdapter
),它采用 List
of NotificationItemInformation
public class NotificationItemInformation
{
int iconId,noitId;
String packageName;
Drawable notiIcon;
}
我正在使用 SQLite 数据库来存储所有通知。
每当发布或删除通知时,NotificationListenerService
从数据库中写入和删除。
我使用了一种叫做
的方法
public List<NotificationItemInformation> ReadNotilist (Context context);
(在 myDBHelper 中)将数据库的内容读取到 NotificationItemInformation
的 List
中,称为 data
(这是全局的,public 和静态的我的主要 Activity ) 。
然后我使用 adapter
(在我的 Main Activity 中也是全局的,public 和静态的)获取 data
并将其设置为 RecyclerView
onCreate
我的方法 MainActivity
.
到目前为止一切正常。我可以看到 RecyclerView
填充了当前 StatusBar
通知。
问题是列表不会更新(如果有新通知),直到我重新启动 activity。我试着打电话给...
MainActivity.data.clear();
MainActivity.data = dbh.ReadNotilist(this); // dbh is DBhelper object
MainActivity.adapter.notifyDataSetChanged();
...在我的 NotificationListenerService
的 onNotificationPosted
中(添加到数据库后)。但是在我重新启动 activity.
之前 RecyclerView
仍然没有更新
这是我的MainActivity
如果你想看的话
public class MainActivity extends AppCompatActivity
{
SQLiteDatabase db;
DBHelper dbh;
RecyclerView notificationIconRecyclerView;
public static NotiRecyclerAdapter adapter;
public static List<NotificationItemInformation> data = Collections.EMPTY_LIST;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbh = new DBHelper(this);
db = dbh.getDb();
notificationIconRecyclerView = (RecyclerView) findViewById(R.id.notificationIconRecyclerView);
data = dbh.ReadNotilist(this);
adapter = new NotiRecyclerAdapter(this,data);
notificationIconRecyclerView.setAdapter(adapter);
notificationIconRecyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,true));
}
}
这是我为 RecyclerView
定制的适配器
public class NotiRecyclerAdapter extends RecyclerView.Adapter<NotiRecyclerAdapter.MyViewHolder>
{
private LayoutInflater inflater;
List<NotificationItemInformation> data = Collections.emptyList();
NotiRecyclerAdapter(Context context, List<NotificationItemInformation> data)
{
inflater = LayoutInflater.from(context);
this.data = data;
}
@Override
public void registerAdapterDataObserver(RecyclerView.AdapterDataObserver observer)
{
super.registerAdapterDataObserver(observer);
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View view = inflater.inflate(R.layout.custom_recyclerview_item,parent,false);
MyViewHolder holder = new MyViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position)
{
NotificationItemInformation current = data.get(position);
holder.recyclerItemIcon.setImageDrawable(current.notiIcon);
}
@Override
public int getItemCount()
{
return data.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder
{
ImageView recyclerItemIcon;
public MyViewHolder(View itemView)
{
super(itemView);
recyclerItemIcon = itemView.findViewById(R.id.notiRecyclerItemIcon);
}
}
}
不重置对数据对象的引用。而是尝试这样的事情:
MainActivity.data.clear();
MainActivity.data.addAll(dbh.ReadNotilist(this));
MainActivity.adapter.notifyDataSetChanged();
在适配器的构造函数中,您编写
this.data = data;
这会将传递给构造函数的 List<NotificationItemInformation>
分配给适配器的 data
字段。您的适配器构造如下:
adapter = new NotiRecyclerAdapter(this,data);
这意味着您的 MainActivity.data
字段和 adapter.data
字段都指的是 相同的 列表。
稍后你写:
MainActivity.data.clear();
MainActivity.data = dbh.ReadNotilist(this);
MainActivity.adapter.notifyDataSetChanged();
第一行清除了 MainActivity.data
和 adapter.data
(请记住,由于适配器的构造方式,它们是相同的列表)。第二行将一个新列表分配给 MainActivity.data
,但不会以任何方式影响 adapter.data
。第三行通知适配器数据集已更改(已更改;已清除),但您的适配器不会 "see" 来自 dbh.ReadNotilist()
.
的新信息
AChez9 的答案有效,因为使用 addAll()
而不是赋值 (=
) 意味着 MainActivity.data
和 adapter.data
仍然指向相同的 List
,所以适配器将 "see" 新信息。
这就是为什么当您从外部来源接受列表时,创建副本 通常是正确的。换句话说,您的适配器的构造函数可能想要这样做:
this.data = new ArrayList<>(data);
这意味着它是 "safe" 对传递给它的列表的更改(在本例中为 MainActivity.data
)。但这意味着您还需要为 activity 公开一种正确更新适配器的方法。我推荐这样的方法:
public void updateData(List< NotificationItemInformation> data) {
this.data = new ArrayList<>(data);
notifyDataSetChanged();
}
我试图创建一个 recyclerView
来显示当前状态栏通知的列表。我创建了一个自定义适配器 (NotiRecyclerAdapter
),它采用 List
of NotificationItemInformation
public class NotificationItemInformation
{
int iconId,noitId;
String packageName;
Drawable notiIcon;
}
我正在使用 SQLite 数据库来存储所有通知。
每当发布或删除通知时,NotificationListenerService
从数据库中写入和删除。
我使用了一种叫做
的方法public List<NotificationItemInformation> ReadNotilist (Context context);
(在 myDBHelper 中)将数据库的内容读取到 NotificationItemInformation
的 List
中,称为 data
(这是全局的,public 和静态的我的主要 Activity ) 。
然后我使用 adapter
(在我的 Main Activity 中也是全局的,public 和静态的)获取 data
并将其设置为 RecyclerView
onCreate
我的方法 MainActivity
.
到目前为止一切正常。我可以看到 RecyclerView
填充了当前 StatusBar
通知。
问题是列表不会更新(如果有新通知),直到我重新启动 activity。我试着打电话给...
MainActivity.data.clear();
MainActivity.data = dbh.ReadNotilist(this); // dbh is DBhelper object
MainActivity.adapter.notifyDataSetChanged();
...在我的 NotificationListenerService
的 onNotificationPosted
中(添加到数据库后)。但是在我重新启动 activity.
RecyclerView
仍然没有更新
这是我的MainActivity
如果你想看的话
public class MainActivity extends AppCompatActivity
{
SQLiteDatabase db;
DBHelper dbh;
RecyclerView notificationIconRecyclerView;
public static NotiRecyclerAdapter adapter;
public static List<NotificationItemInformation> data = Collections.EMPTY_LIST;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbh = new DBHelper(this);
db = dbh.getDb();
notificationIconRecyclerView = (RecyclerView) findViewById(R.id.notificationIconRecyclerView);
data = dbh.ReadNotilist(this);
adapter = new NotiRecyclerAdapter(this,data);
notificationIconRecyclerView.setAdapter(adapter);
notificationIconRecyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,true));
}
}
这是我为 RecyclerView
public class NotiRecyclerAdapter extends RecyclerView.Adapter<NotiRecyclerAdapter.MyViewHolder>
{
private LayoutInflater inflater;
List<NotificationItemInformation> data = Collections.emptyList();
NotiRecyclerAdapter(Context context, List<NotificationItemInformation> data)
{
inflater = LayoutInflater.from(context);
this.data = data;
}
@Override
public void registerAdapterDataObserver(RecyclerView.AdapterDataObserver observer)
{
super.registerAdapterDataObserver(observer);
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View view = inflater.inflate(R.layout.custom_recyclerview_item,parent,false);
MyViewHolder holder = new MyViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position)
{
NotificationItemInformation current = data.get(position);
holder.recyclerItemIcon.setImageDrawable(current.notiIcon);
}
@Override
public int getItemCount()
{
return data.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder
{
ImageView recyclerItemIcon;
public MyViewHolder(View itemView)
{
super(itemView);
recyclerItemIcon = itemView.findViewById(R.id.notiRecyclerItemIcon);
}
}
}
不重置对数据对象的引用。而是尝试这样的事情:
MainActivity.data.clear();
MainActivity.data.addAll(dbh.ReadNotilist(this));
MainActivity.adapter.notifyDataSetChanged();
在适配器的构造函数中,您编写
this.data = data;
这会将传递给构造函数的 List<NotificationItemInformation>
分配给适配器的 data
字段。您的适配器构造如下:
adapter = new NotiRecyclerAdapter(this,data);
这意味着您的 MainActivity.data
字段和 adapter.data
字段都指的是 相同的 列表。
稍后你写:
MainActivity.data.clear();
MainActivity.data = dbh.ReadNotilist(this);
MainActivity.adapter.notifyDataSetChanged();
第一行清除了 MainActivity.data
和 adapter.data
(请记住,由于适配器的构造方式,它们是相同的列表)。第二行将一个新列表分配给 MainActivity.data
,但不会以任何方式影响 adapter.data
。第三行通知适配器数据集已更改(已更改;已清除),但您的适配器不会 "see" 来自 dbh.ReadNotilist()
.
AChez9 的答案有效,因为使用 addAll()
而不是赋值 (=
) 意味着 MainActivity.data
和 adapter.data
仍然指向相同的 List
,所以适配器将 "see" 新信息。
这就是为什么当您从外部来源接受列表时,创建副本 通常是正确的。换句话说,您的适配器的构造函数可能想要这样做:
this.data = new ArrayList<>(data);
这意味着它是 "safe" 对传递给它的列表的更改(在本例中为 MainActivity.data
)。但这意味着您还需要为 activity 公开一种正确更新适配器的方法。我推荐这样的方法:
public void updateData(List< NotificationItemInformation> data) {
this.data = new ArrayList<>(data);
notifyDataSetChanged();
}