RecyclerView.Adapter 在 ViewPager 片段中为空


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.");
}
}

我添加了刷新列表((:

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

包含寻呼机的主活动。我试图删除尽可能多的不相关的代码。

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));
}
});
}

}

每当调用方法更新列表视图时,我都会收到空指针异常。片段最初显示没有问题,但是当将新条目添加到 ArrayList 并调用 updateListView 时 - 它会停止。日志显示 mAdapter 为空。我对 android 还不够了解,无法理解为什么 mAdapter 在之前使用后变为空。

很抱歉有大量代码,但我完全被难住了。谢谢。

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

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

Ps. 查看 android 文档以查看 RecyclerView.Adapter 声明的方法。

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

最新更新