Xia
Xia

Reputation: 43

Non Recycler Fragment calling method on Recycler Adapter? Is this even possible?

Sincere apologies for no code, I'm leaving for a wedding and it was either post code or explain my situation.

I've searched Stack and see many posts for Recycler Adapter to Fragment (that created the adapter) interfaces.

A minor few for Fragment(created the adapter) to Adapter posts but they are not nearly as clear.

My situation is this:

On Main Activity, when App is running:

1) Fragment Lyrics (created the REcycler ADapter that is set into a Lyric Recycler View)

2) Fragment Microphone ( speech recognition microphone functionality and XML icon).

What I want to happen is:

user activates Microphone and speaks, that resulting data is passed to the ADAPTER java file and activates a method on the ADAPTER, causing a visual change to RecyclerView Viewholder on the screen.

Yes, I know this is probably bad architecture. It's for a school project, I'm learning, and I've run out of time.

* What I can do so far *

I have activated the pre-made OnClick listerner for the Adapter (when a user clicks on a View) and OnScroll for the RecyclerView (user scrolls, it fires a method in the Adapter that causes the current View to change).

I have made interface for Passing Speech data from Microphone Fragment, through the Main Activity, to the Lyrics Fragment.

On Main, I simply create an instance of the Lyrics Fragment, then call a custom method on Lyrics Fragment that takes the speech data. Something like this.

LyricsFragment.TakeSpeechData(speech data);

* What my plans was...*

When the speech data arrives on Lyrics Fragment, I thought I could just write something like:

MyRecyclerAdapter.SomeMethodOnAdapter (speech data);

I would be home free at this point.

It doesn't work

No go. I get a null pointer exception here. The MyRecyclerAdapter part of the method call is null. I've looked that up and not sure how to fix it.

I'm assuming I'm referencing the original Adapter that was created when the Fragment layed down the RecyclerView and set everything. It's the same global variable for the Adapter on Fragment Lyrics and I'm assuming it "lives on".

I'm sure I'm missing on fundamental Java principles but i don't know what.

I've spent hours and hours on this trying , reading, researching. I'm totally stuck. Please help.

EDIT: Here is my code for VerseFragment (I'm referring to it as "Lyrics" Fragment in my post). Note this Fragment is loaded, created, and functional with recyclerView on screen. Before the user uses the micrphone fragment, which is also on screen, this has already been created.

public class VersesList extends Fragment {
    @BindView(R.id.versesRecycleView) RecyclerView versesRecycleView;
    @BindView(R.id.songNameTextView) TextView songName;
    @BindView(R.id.artistTextView)TextView artistName;
    private SharedPreferences mSharedPreferences;
    LinearLayoutManager llm;
    List verseList;
    List finalModVerseList;
    public VerseAdapter verseAdapter;
    // temporary
    private SharedPreferences.Editor editor;
    public VersesList() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment

        View view = inflater.inflate(R.layout.fragment_verses_list, container, false);
        ButterKnife.bind(this, view);
        mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
        editor=mSharedPreferences.edit();
        displayArtistAndSongName();
        lyricsToVerseList();
        setVersesIntoRecyclerView();
        setVersesScrollListener();
        //temp
        storeAllVerseLevels();
        return view;
    }

    public static VersesList newInstance(String lyrics){
        VersesList versesListFragment = new VersesList();
        Bundle args = new Bundle();
        args.putString("lyrics", lyrics);
        versesListFragment.setArguments(args);
        return versesListFragment;

    }

    public void lyricsToVerseList(){
        String lyrics = getArguments().getString("lyrics", "");
        verseList = new ArrayList<String>();
        finalModVerseList = new ArrayList<String>();
        verseList= Arrays.asList(lyrics.split("\n"));
        int endOfFinalList=verseList.indexOf("...");
        for (int i = 0; i < endOfFinalList; i++) {
           if(!verseList.get(i).toString().equals("")){
               String addThisVerse = verseList.get(i).toString();
               //check on length of verse, if too short add next, check again
               int numberOfWords = addThisVerse.split(" ").length;
               while (numberOfWords < 10 && i < endOfFinalList) {
                   i++;
                   addThisVerse += " " + verseList.get(i).toString();
                   numberOfWords = addThisVerse.split(" ").length;
               }
               finalModVerseList.add(addThisVerse);
           }
        }
    }

    public void displayArtistAndSongName(){
        String song = '"'+mSharedPreferences.getString(SONG_NAME, null)+'"';
        String artist = "by "+mSharedPreferences.getString(ARTIST_NAME, null);
        songName.setText(song);
        artistName.setText(artist);
    }

    public void setVersesIntoRecyclerView(){
        verseAdapter = new VerseAdapter(finalModVerseList, (MainActivity)getActivity(), versesRecycleView);
        versesRecycleView.setAdapter(verseAdapter);
        llm = new LinearLayoutManager(getActivity(),LinearLayoutManager.HORIZONTAL, false);
        versesRecycleView.setLayoutManager(llm);
        PagerSnapHelper helper = new PagerSnapHelper();
        helper.attachToRecyclerView(versesRecycleView);
    }

    private void storeLevel(int indexNumber) {
        editor.putInt(String.valueOf(indexNumber), 1).apply();
    }

    private void storeAllVerseLevels(){
        for (int i=0; i< finalModVerseList.size();i++){
            storeLevel(i);
        }
        for (int j=0; j< finalModVerseList.size();j++){
            String level = String.valueOf(mSharedPreferences.getInt(String.valueOf(j), -1));
            Log.d("In Shared Preferences  ", "Verse "+j+" Level "+level);
        }
    }

    public void checkSpeech(String text){
        List<String> temp = new ArrayList<>();
        temp.add("test");

        VerseAdapter adapter = new VerseAdapter(temp, (MainActivity)getActivity(), versesRecycleView);
        try {
            adapter.resetVerse();
        }catch (NullPointerException e){
            Log.d("Null", e.toString());
        }
    }

    public void setVersesScrollListener(){
        versesRecycleView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);

                if (newState == 0) {
                    verseAdapter.resetVerse();
                }
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
            }
        });
    }
}

When you are calling the method from your adapter, is MyRecyclerAdapter an instance or the class? To call someMethodOnAdpater(speechData), you must use an instance . Xia is using an instance.

If you need to call an adapter method from within the fragment in which it was created, you can store it in a variable like this.

MyRecyclerAdapter adapter;

@Override
public View onCreateView(...) {
    ...
    adapter = new MyRecyclerAdapter();
    myRecyclerView.setAdapter(adapter);
    ...
}

public void takeSpeechData(String data) {
    adapter.someMethodAdapter(data);
}

Edit:

I'm not sure why the same adapter used by your recyclerview is null after being set. Calling an adapter from is definitely possible (I tested a basic example). The code in my example doesn't differ from what you said you had previously, though. I have upvoted your question for visibility.

**Edit: Add Mic Fragment, it has the interface **

package com.blueoxgym.javainthedark.Fragments;


/**
 * A simple {@link Fragment} subclass.
 */
public class MicFragment extends Fragment implements  View.OnClickListener {
    @BindView(R.id.progressBarMic)
    ProgressBar micLevels;
    @BindView(R.id.btn_mic)
    ImageButton btnMicrophone;
    private SpeechRecognizer speech = null;
    private Intent recognizerIntent;
    public final static String TAG = "In speech mode";
    public FragmentManager fragmentManager;
    private SharedPreferences mSharedPreferences;
    private SharedPreferences.Editor mEditor;
    private String trackName;
    private String artistName;
    private CallMainLoadVerseFragment loadVerseFragment;
    private CheckSpeech checkSpeechOnVerse;


    public MicFragment() {
        // Required empty public constructor
    }

    public static MicFragment newInstance (){
        MicFragment micFragment = new MicFragment();
        return micFragment;
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_mic, container, false);
        ButterKnife.bind(this, view);
        this.loadVerseFragment = (CallMainLoadVerseFragment) getActivity();
        this.checkSpeechOnVerse = (CheckSpeech) getActivity();
        btnMicrophone.setOnClickListener(this);
        fragmentManager = getFragmentManager();
        mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
        mEditor = mSharedPreferences.edit();
        return view;
    }

    @Override
    public void onClick(View v) {
        if (v == btnMicrophone) {
            startSpeechToText();
        }

    }

    class listener implements RecognitionListener {
       ...


    @Override
        public void onResults(Bundle results) {
            String str = new String();
            Log.d(TAG, "onResults " + results);
            ArrayList<String> data = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
            String text = data.get(0).toLowerCase().replace("by","");
            Fragment currentFragment = fragmentManager.findFragmentById(R.id.content_frame);
            if (currentFragment.toString().contains("LyricSearch")){
                searchForSong(text);
            } else if (currentFragment.toString().contains("VersesList")){
 -----------> Here it is called  checkSpeechOnVerse.checkingSpeech(text);
            }

        }

    }

    public void startSpeechToText(){
        btnMicrophone.setBackgroundResource(R.drawable.circle_green);
        speech=SpeechRecognizer.createSpeechRecognizer(getContext());
        speech.setRecognitionListener(new listener());
        recognizerIntent= new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
        recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE, "en-US");
        recognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, getActivity().getPackageName());
        recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
        recognizerIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 5);
        speech.startListening(recognizerIntent);
    }

 ...
...

    public interface CheckSpeech {
        void checkingSpeech (String text);
    }
}

MainActivity, implements CheckSpeech Interface

public class MainActivity extends AppCompatActivity
        implements NavigationView.OnNavigationItemSelectedListener, MicFragment.CallMainLoadVerseFragment, MicFragment.CheckSpeech {
....
...
@Override
    public void checkingSpeech(String text) {
       VersesList versesList = new VersesList();
 --------> Now, I'm pass data from Main to VersesList Fragment(it has the original Adapter)     
     versesList.checkSpeech(text);
    }

VersesList Fragment, where I try to call Adapter

public class VersesList extends Fragment {
  ....
        private VerseAdapter verseAdapter;
setVersesIntoRecyclerView();
....
<---ADAPTER IS MADE AND SET HERE----.
public void setVersesIntoRecyclerView(){
        verseAdapter = new VerseAdapter(finalModVerseList, (MainActivity)getActivity(), versesRecycleView);
        versesRecycleView.setAdapter(verseAdapter);
        llm = new LinearLayoutManager(getActivity(),LinearLayoutManager.HORIZONTAL, false);
        versesRecycleView.setLayoutManager(llm);
        PagerSnapHelper helper = new PagerSnapHelper();
        helper.attachToRecyclerView(versesRecycleView);
    }


public void checkSpeech(String text){
-------> NPE NPE 
versesAdapter.someMethodOnAdapter(text);

    }

    public void setVersesScrollListener(){
        versesRecycleView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);

                if (newState == 0) {
BUT THIS WORKS!!! No NPE. --------> verseAdapter.resetVerse();

                }
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
//                VerseAdapter.VerseViewHolder view = versesRecycleView.findViewHolderForAdapterPosition(llm.findFirstVisibleItemPosition());
            }
        });
    }

Upvotes: 1

Views: 241

Answers (1)

Adam Piziak
Adam Piziak

Reputation: 461

If you need to call an adapter method from within the fragment in which it was created, you can store it in a variable within that fragment.

MyRecyclerAdapter adapter;

@Override
public View onCreateView(...) {
    ...
    adapter = new MyRecyclerAdapter();
    myRecyclerView.setAdapter(adapter);
    ...
}

public void takeSpeechData(String data) {
    adapter.someMethodAdapter(data);
}

Then you can call that method directly from another fragment. (link to accessing fragments)

VersesList versesList = (VersesList) getActivity().getSupportFragmentManager.findFragmentById(containerId);
versesList.takeSpeechData("data");

gif of example

Upvotes: 0

Related Questions