通知 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 以更新自身?

通过查看您的代码,我可以为您想到三种解决方案。按照(我认为)解决方案的质量从最低到最好的顺序。

  1. 移动你的片段fragmentCreateGame先由你托管activity
  2. Start Activity For Result
  3. 使用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 页面底部有解决方案。