通知 RecyclerView 适配器数据库改变
Notify RecyclerView adapter database changed
我的MainActivity
调用一个片段,
@Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container, PlaceholderFragment.newInstance(position + 1),
"placeHolderFragmentTag")
.commit();
}
placeholderFragment
用适配器填充 RecyclerView
,
public static PlaceholderFragment newInstance(int sectionNumber) {
PlaceholderFragment fragment = new PlaceholderFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dbHelper = new DatabaseHelper(getActivity().getApplicationContext());
dbHelper.getWritableDatabase();
dbHelper.openDataBase();
adapterUpcomingGames = new AdapterUpcomingGames(retrieveGames(dbHelper.getUpcomingGames()));
}
adapterUpcomingGames
。适配器从用户输入的数据库中获取数据,即即将举行的体育赛事的列表。
@Override // still placeholderFragment
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity().getApplicationContext()));
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
switch(getArguments().getInt(ARG_SECTION_NUMBER))
{
case 1: // This will be upcoming games
mRecyclerView.setAdapter(adapterUpcomingGames);
break;
case 2: // This will be past games
AdapterPastGames adapterPastGames;
adapterPastGames = new AdapterPastGames(retrieveGames(dbHelper.getPastGames()));
mRecyclerView.setAdapter(adapterPastGames);
break;
default: // Default is, well, anything that will work.
adapterUpcomingGames1 = new AdapterUpcomingGames(retrieveGames(dbHelper.getGames()));
mRecyclerView.setAdapter(adapterUpcomingGames1);
}
newGame.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0){
Intent createGame = new Intent(getActivity(),
ActivityCreateGame.class);
startActivity(createGame);
adapterUpcomingGames.notifyDataSetChanged();
}
});
setRetainInstance(true);
}
在这个视图中,有一个添加游戏的按钮,即修改数据库。我通过调用一个新的 activity、activityCreateGame
来实现这一点,它承载了一个片段,
@Override // activityCreateGame
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_create_game);
fragmentCreateGame = new FragmentCreateGame();
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.attach(fragmentCreateGame)
.replace(R.id.newGameContainer, fragmentCreateGame)
.commit();
restoreActionBar();
}
fragmentCreateGame
,允许用户输入所需的信息,然后将其附加到数据库中。用户使用 activity.
中导航栏上的选项保存此信息
@Override // activityCreateGame
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case android.R.id.home:
finish();
break;
case R.id.action_save:
// check if an error has occured
if (fragmentCreateGame.CreateNewGame())
{
Toast toast = Toast.makeText(this, R.string.toast_success_game_create,
Toast.LENGTH_SHORT);
toast.show();
finish();
}
else{
Toast toast = Toast.makeText(this, R.string.toast_failed_game_create,
Toast.LENGTH_SHORT);
toast.show();
}
break;
}
return super.onOptionsItemSelected(item);
}
该操作完成 activityCreateGame
。现在,我该如何通知适配器,回到 placeholderFragment
数据库已经更新,从而更新 RecyclerView
以更新自身?
通过查看您的代码,我可以为您想到三种解决方案。按照(我认为)解决方案的质量从最低到最好的顺序。
- 移动你的片段
fragmentCreateGame
先由你托管activity
- Start Activity For Result
- 使用Otto Event Bus。我会推荐奥托。特别是如果您可能有多个对象监听一个事件。
首先将 Otto 添加到您的项目中。在您的 build.gradle
中,将其添加到您的依赖项中。
dependencies {
....
compile 'com.squareup:otto:1.3.6'
....
}
在需要通知的 activity 中,在 onCreate 的开头添加:
Bus bus = new Bus();
bus.register(this);
然后,创建一个"event" class。它只是您传递给订阅者的一个对象。您也可以向这些添加信息,以传递更多信息。
public class SomeCoolEvent{
private String yourWisdom;
public SomeCoolEvent(String yourWisdom){
this.yourWisdom = yourWisdom;
}
public String getWisdom(){
return yourWisdom;
}
}
然后,在你的 class 中正在做一些事情来通知其他 classes,这样做:
Bus bus = new Bus();
bus.post(new SomeCoolEvent(yourWisdomStringFromThisClass));
现在,返回到您的第一个 activity,添加一个用 @Subscribe
注释的方法
@Subscribe
public void onAnyMethodNameYouWantCauseItDoesntMatter(SomeCoolEvent event){
//this will be called when ANY class calls bus.post(SomeCoolEvent)
String boomYouAreNotified = event.getWisdom();
}
关于您的 @Subscribe
方法,有几点需要注意。
* 方法名称无关紧要,所以给它一些对你有意义的东西。我喜欢用“on
”作为前缀,因为它就像一个回调。
* 方法必须是public
和returnvoid
。
* 您没有明确调用此方法,因此某些 IDE 可能看起来未被使用。 Android studio 将允许您使用 "ALT + ENTER" 然后 select “_ignore warnings for methods annotated with Subscribe”来解决这个问题。
* 你应该在销毁时调用 bus.unregister(this)
。
* 您可以让多个 class 听一个 post。
现在,如果您在不同的线程上启动 运行,事情会变得更加复杂。如果这样做,我提供的 Otto 页面底部有解决方案。
我的MainActivity
调用一个片段,
@Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container, PlaceholderFragment.newInstance(position + 1),
"placeHolderFragmentTag")
.commit();
}
placeholderFragment
用适配器填充 RecyclerView
,
public static PlaceholderFragment newInstance(int sectionNumber) {
PlaceholderFragment fragment = new PlaceholderFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dbHelper = new DatabaseHelper(getActivity().getApplicationContext());
dbHelper.getWritableDatabase();
dbHelper.openDataBase();
adapterUpcomingGames = new AdapterUpcomingGames(retrieveGames(dbHelper.getUpcomingGames()));
}
adapterUpcomingGames
。适配器从用户输入的数据库中获取数据,即即将举行的体育赛事的列表。
@Override // still placeholderFragment
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity().getApplicationContext()));
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
switch(getArguments().getInt(ARG_SECTION_NUMBER))
{
case 1: // This will be upcoming games
mRecyclerView.setAdapter(adapterUpcomingGames);
break;
case 2: // This will be past games
AdapterPastGames adapterPastGames;
adapterPastGames = new AdapterPastGames(retrieveGames(dbHelper.getPastGames()));
mRecyclerView.setAdapter(adapterPastGames);
break;
default: // Default is, well, anything that will work.
adapterUpcomingGames1 = new AdapterUpcomingGames(retrieveGames(dbHelper.getGames()));
mRecyclerView.setAdapter(adapterUpcomingGames1);
}
newGame.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0){
Intent createGame = new Intent(getActivity(),
ActivityCreateGame.class);
startActivity(createGame);
adapterUpcomingGames.notifyDataSetChanged();
}
});
setRetainInstance(true);
}
在这个视图中,有一个添加游戏的按钮,即修改数据库。我通过调用一个新的 activity、activityCreateGame
来实现这一点,它承载了一个片段,
@Override // activityCreateGame
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_create_game);
fragmentCreateGame = new FragmentCreateGame();
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.attach(fragmentCreateGame)
.replace(R.id.newGameContainer, fragmentCreateGame)
.commit();
restoreActionBar();
}
fragmentCreateGame
,允许用户输入所需的信息,然后将其附加到数据库中。用户使用 activity.
@Override // activityCreateGame
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case android.R.id.home:
finish();
break;
case R.id.action_save:
// check if an error has occured
if (fragmentCreateGame.CreateNewGame())
{
Toast toast = Toast.makeText(this, R.string.toast_success_game_create,
Toast.LENGTH_SHORT);
toast.show();
finish();
}
else{
Toast toast = Toast.makeText(this, R.string.toast_failed_game_create,
Toast.LENGTH_SHORT);
toast.show();
}
break;
}
return super.onOptionsItemSelected(item);
}
该操作完成 activityCreateGame
。现在,我该如何通知适配器,回到 placeholderFragment
数据库已经更新,从而更新 RecyclerView
以更新自身?
通过查看您的代码,我可以为您想到三种解决方案。按照(我认为)解决方案的质量从最低到最好的顺序。
- 移动你的片段
fragmentCreateGame
先由你托管activity - Start Activity For Result
- 使用Otto Event Bus。我会推荐奥托。特别是如果您可能有多个对象监听一个事件。
首先将 Otto 添加到您的项目中。在您的 build.gradle
中,将其添加到您的依赖项中。
dependencies {
....
compile 'com.squareup:otto:1.3.6'
....
}
在需要通知的 activity 中,在 onCreate 的开头添加:
Bus bus = new Bus();
bus.register(this);
然后,创建一个"event" class。它只是您传递给订阅者的一个对象。您也可以向这些添加信息,以传递更多信息。
public class SomeCoolEvent{
private String yourWisdom;
public SomeCoolEvent(String yourWisdom){
this.yourWisdom = yourWisdom;
}
public String getWisdom(){
return yourWisdom;
}
}
然后,在你的 class 中正在做一些事情来通知其他 classes,这样做:
Bus bus = new Bus();
bus.post(new SomeCoolEvent(yourWisdomStringFromThisClass));
现在,返回到您的第一个 activity,添加一个用 @Subscribe
@Subscribe
public void onAnyMethodNameYouWantCauseItDoesntMatter(SomeCoolEvent event){
//this will be called when ANY class calls bus.post(SomeCoolEvent)
String boomYouAreNotified = event.getWisdom();
}
关于您的 @Subscribe
方法,有几点需要注意。
* 方法名称无关紧要,所以给它一些对你有意义的东西。我喜欢用“on
”作为前缀,因为它就像一个回调。
* 方法必须是public
和returnvoid
。
* 您没有明确调用此方法,因此某些 IDE 可能看起来未被使用。 Android studio 将允许您使用 "ALT + ENTER" 然后 select “_ignore warnings for methods annotated with Subscribe”来解决这个问题。
* 你应该在销毁时调用 bus.unregister(this)
。
* 您可以让多个 class 听一个 post。
现在,如果您在不同的线程上启动 运行,事情会变得更加复杂。如果这样做,我提供的 Otto 页面底部有解决方案。