RecyclerView.Adapter является нулевым во фрагменте ViewPager - PullRequest
0 голосов
/ 09 июня 2018
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 становится нулевым после того, как его использовали раньше.

Извините за большой объем кода, но я полностью озадачен.Спасибо.

Ответы [ 2 ]

0 голосов
/ 22 ноября 2018

Это зависит от того, как вы обращаетесь к адаптеру в RecyclerView.Если вы посмотрите на эту строку Fragment fragment = adapter.getItem(0), вы пытаетесь получить доступ к первому фрагменту в адаптере вашего ViewPager.getItem обычно не вызывается снова после того, как ViewPager имеет макет своих фрагментов, что означает, что ваш вызов для доступа к адаптеру RecyclerView в первом фрагменте ViewPager будет указывать на нулевой адаптер, даже если фрагмент может существовать (и вы можете даженеправильный фрагмент).Используйте это Fragment fragment = getChildFragmentManager().getFragments().get(0) для доступа к нужному фрагменту, который гарантирует, что адаптер RecyclerView не будет нулевым.Измените getChildFragmentManager () на getFragmentManager (), если ваш ViewPager находится в Activity.

0 голосов
/ 07 июля 2018

По моему мнению, это потому, что ваша переменная mAdapter объявлена ​​как тип RecyclerView.Adapter, который является интерфейсом, который не объявляет ваш метод, refreshList().Поэтому, если вы намереваетесь использовать тип RecyclerView.Adapter, только методы, объявленные в интерфейсе, могут быть вызваны с помощью ссылочной переменной.Если вы намереваетесь вызывать методы, реализованные вами самостоятельно, кроме тех, которые переопределяются из интерфейса, следует использовать ссылочный тип SongListAdapter2.

Простое исправление - изменить RecyclerView.Adapter на SongListAdapter2 при объявлении mAdapter.

Ps.Проверьте android docs , чтобы увидеть методы, объявленные RecyclerView.Adapter.

...