RecyclerView.Adapter在ViewPager Fragment中为null

时间:2018-06-09 12:20:35

标签: android android-recyclerview android-viewpager recycler-adapter android-pageradapter

public class MainLibraryFragment extends Fragment implements PlaylistChangedInterface {

AudioItemSelectedListener mCallback;

// Container Activity must implement this interface
public interface AudioItemSelectedListener {
    //        public void onAudioItemSelected(int position);
    public void onAudioItemSelected(Audio audioSelected);
}

private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
private Context context;

private ArrayList<Audio> listToDisplay;

private String TAG = "MainLibraryFragment";

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    context = getActivity();

    MemoryManagement memoryManagement = new MemoryManagement(context);
    listToDisplay = memoryManagement.loadAudioList(MemoryManagement.MAIN_LIST_KEY);
    try {
        //Expression is meaningless but tests if null.
        //TODO, should catch this in loadAudioList.
        if (listToDisplay.isEmpty()){}
    } catch (NullPointerException e){
        defaultList();
    }

    View rootView = inflater.inflate(R.layout.fragment_top_rated, container, false);

    mRecyclerView = (RecyclerView) rootView.findViewById(R.id.my_recycler_view);
    // use this setting to improve performance if you know that changes
    // in content do not change the layout size of the RecyclerView
    mRecyclerView.setHasFixedSize(true);
    // use a linear layout manager
    mLayoutManager = new LinearLayoutManager(getContext());
    mRecyclerView.setItemAnimator(new DefaultItemAnimator());
    mRecyclerView.addItemDecoration(new DividerItemDecoration(getContext(), LinearLayoutCompat.VERTICAL));
    mRecyclerView.setLayoutManager(mLayoutManager);
    mRecyclerView.addOnItemTouchListener(new CustomTouchListener(context, new onItemClickListener() {
        @Override
        public void onClick(View view, int index) {

            mCallback.onAudioItemSelected(listToDisplay.get(index));

        }
    }));

    mAdapter = new SongListAdapter2(listToDisplay, context);
    mRecyclerView.setAdapter(mAdapter);

    return rootView;
}

private void defaultList(){
    listToDisplay = new ArrayList<>();
    listToDisplay.add(new Audio("You need to add some songs!"));
}

@Override
public void playListChanged(ArrayList<Audio> arrayList) {
    Log.d(TAG, "updateTop: in.");
    if (!arrayList.isEmpty()) {
        listToDisplay = arrayList;
    }else {
        defaultList();
    }

    updateListView();
    Log.d(TAG, "updateTop: out.");
}


@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    context = getContext();
    // This makes sure that the container activity has implemented
    // the callback interface. If not, it throws an exception
    try {
        mCallback = (AudioItemSelectedListener) activity;
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString()
                + " must implement AudioItemSelectedListener");
    }
}

@Override
public void onDetach() {
    super.onDetach();
    mCallback = null;
}

private void updateListView(){
    Log.d(TAG, "updateTop: in.");

    ((SongListAdapter2) mAdapter).refreshList(listToDisplay);
    Log.d(TAG, "updateTop: out.");
}
}

我添加了refreshList():

    public void refreshList(ArrayList<Audio> list) {
    this.list = list;
    notifyDataSetChanged();
    }

然后是错误消息:

    --------- beginning of crash
06-09 15:14:24.275 9114-9114/com.bteq.audia E/AndroidRuntime: FATAL 
EXCEPTION: main
Process: com.bteq.audia, PID: 9114
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.bteq.audia.SongListAdapter2.refreshList(java.util.ArrayList)' on a null object reference
    at com.bteq.audia.MainLibraryFragment.updateListView(MainLibraryFragment.java:128)
    at com.bteq.audia.MainLibraryFragment.playListChanged(MainLibraryFragment.java:100)
    at com.bteq.audia.MainActivity.onDialogPositiveClick(MainActivity.java:195)
    at com.bteq.audia.AddSongDialog$2.onClick(AddSongDialog.java:47)
    at android.support.v7.app.AlertController$ButtonHandler.handleMessage(AlertController.java:166)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6753)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:482)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
06-09 15:14:24.281 9114-9114/com.bteq.audia W/OPDiagnose: 
getService:OPDiagnoseService NULL

包含寻呼机的MainActivity。我试图尽可能多地删除那些不相关的代码。

public class MainActivity extends AppCompatActivity implements MainLibraryFragment.AudioItemSelectedListener, AddSongDialog.NoticeDialogListener, ShowQueueDialog.ShouldClearAll {

private MemoryManagement memoryManagement;
private ViewPager viewPager;
private com.bteq.audia.PagerAdapter adapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    memoryManagement = new MemoryManagement(this);

    setContentView(R.layout.activity_main);
    Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
    setSupportActionBar(myToolbar);

    initialiseViews();
}

public void initialiseViews() {

    //Fills the titles of all the tabs.
    String[] tabTitles = getTabTitles();
    TabLayout tabLayout = (TabLayout) findViewById(R.id.tabLayout);

    for (int i = 0; i < tabTitles.length; i++) {
        tabLayout.addTab(tabLayout.newTab().setText(tabTitles[i]));
    }
    tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);

    //Sets up the ViewPager and creates the functionality to make them changeable.
    viewPager = (ViewPager) findViewById(R.id.pager);
    adapter = new PagerAdapter(getSupportFragmentManager(), tabLayout.getTabCount());
    viewPager.setAdapter(adapter);
    viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
    tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
        @Override
        public void onTabSelected(TabLayout.Tab tab) {
            viewPager.setCurrentItem(tab.getPosition());
        }

        @Override
        public void onTabUnselected(TabLayout.Tab tab) {

        }

        @Override
        public void onTabReselected(TabLayout.Tab tab) {

        }
    });

    setupBottomView();
}

//method used as main control to the service from this activity.
private void audioActionDo(String audioAction) {
    Intent intent = new Intent("audio_control_intent");
    intent.putExtra("button_pressed", audioAction);
    LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}

/*
Method tells the activity which item in the shown playlist has been selected. This should then cause that item to play if possible.
//TODO, fill in body of method.
 */
@Override
public void onAudioItemSelected(Audio audio) {
    songSelected(audio);

    Log.d("MainActivity", "onAudioItemSelected: At end");
}

@Override
public void onDialogPositiveClick(String titleString, String artistString, String albumString, String genreString) {
    Audio audioToAdd = new Audio(genreString, titleString, albumString, artistString);

    memoryManagement.addAudioToList(audioToAdd, MemoryManagement.MAIN_LIST_KEY);

    Fragment fragment = adapter.getItem(0);
    PlaylistChangedInterface playlistChangedInterface = (PlaylistChangedInterface) fragment;
    playlistChangedInterface.playListChanged(memoryManagement.loadAudioList(MemoryManagement.MAIN_LIST_KEY));
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu_top, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.action_settings:
            //TODO, take the user to the app settings page.
            // User chose the "Settings" item, show the app settings UI...
            return true;

        case R.id.action_favorite:
            //TODO, make this favourite the current Audio.
            // User chose the "Favorite" action, mark the current item
            // as a favorite...
            memoryManagement.clearPrefsValue(MemoryManagement.MAIN_LIST_KEY);
            return true;

        case R.id.action_add_new_song:
            showAddSongDialog();
            return true;

        case R.id.action_show_queue:
            showQueueDialog();
            return true;

        case R.id.action_add_from_internal:

            return true;

        default:
            // If we got here, the user's action was not recognized.
            // Invoke the superclass to handle it.
            return super.onOptionsItemSelected(item);

    }
}

public void showAddSongDialog() {
    DialogFragment newFragment = new AddSongDialog();
    newFragment.show(getSupportFragmentManager(), "missiles");
}

public void showQueueDialog() {
    DialogFragment newFragment = new ShowQueueDialog();
    newFragment.show(getSupportFragmentManager(), "showQueue");
}

//Should immediately play a song then be able to continue with the queued audio.
public void songSelected(Audio audioToAdd) {

}

//clears the entire queue but completes playback of current audio.
private void clearCurrentQueue() {
    memoryManagement.clearPrefsValue(MemoryManagement.QUEUE_KEY);
}

//   Utility method. Returns the locale titles for the tabs in the viewpager.
private String[] getTabTitles() {
    return getResources().getStringArray(R.array.tab_titles);
}

@Override
public void clearAllPressed() {
    clearCurrentQueue();
}

private void setupBottomView() {
    ImageView playButton = (ImageView) findViewById(R.id.bottom_play);
    ImageView replayButton = (ImageView) findViewById(R.id.bottom_replay);
    ImageView skipBackButton = (ImageView) findViewById(R.id.bottom_skip_back);
    ImageView skipForwardButton = (ImageView) findViewById(R.id.bottom_skip_next);
    ImageView shuffleButton = (ImageView) findViewById(R.id.bottom_shuffle);

    playButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
//                playAudio(storageUtility2.loadAudioIndex());

audioActionDo(getResources().getString(R.string.broadcast_action_playpause));
        }
    });
    replayButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            audioActionDo(getResources().getString(R.string.broadcast_action_loop));
        }
    });
    skipBackButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            audioActionDo(getResources().getString(R.string.broadcast_action_skip_back));
        }
    });
    skipForwardButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            audioActionDo(getResources().getString(R.string.broadcast_action_skip_forward));
        }
    });
    shuffleButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            audioActionDo(getResources().getString(R.string.broadcast_action_shuffle));
        }
    });
}

}

每当调用方法updateListView时,我都会得到空指针异常。片段最初显示没有问题,但是当一个新条目被添加到ArrayList并且调用updateListView时 - 它会停止。日志显示mAdapter为null。我还不太清楚知道android之前为什么mAdapter在之前使用后变为null。

很抱歉代码很多,但我完全被难倒了。感谢。

2 个答案:

答案 0 :(得分:0)

我认为这是因为您的变量mAdapter被声明为类型RecyclerView.Adapter,这是一个没有声明您的方法refreshList()的接口。因此,如果您打算使用RecyclerView.Adapter类型,则只能使用引用变量来调用接口中声明的方法。如果您打算调用自己实现的方法而不是从接口重写的方法,则必须使用引用类型SongListAdapter2

简单的解决方法是在RecyclerView.Adapter的声明中将SongListAdapter2更改为mAdapter

Ps。检查android docs来查看RecyclerView.Adapter声明的方法。

答案 1 :(得分:0)

这取决于您如何在RecyclerView中访问适配器。如果查看此行Fragment fragment = adapter.getItem(0),则您正在尝试访问ViewPager适配器中的第一个片段。在ViewPager对其片段进行布局之后,通常不会再次调用getItem,这意味着即使该片段可能存在,您访问ViewPager中第一个片段中的RecyclerView适配器的调用仍将指向空适配器(甚至您可能调用错误的片段)。使用此Fragment fragment = getChildFragmentManager().getFragments().get(0)访问正确的片段,这将确保RecyclerView适配器不会为空。如果您的ViewPager在活动中,请将getChildFragmentManager()更改为getFragmentManager()。