1

I am creating an app where there is a vocabulary list, when the user click on an item it should say the word using text-to-speech.

I figured it out how to initialize it and call the method from MainActivity, but It doesn't seem to work in any other class.

I'm new at android development, and new to coding, so if there are useless lines or not properly written you can point it to me, so I can remove/fix.

Thanks in advance!

public class MainActivity extends ActionBarActivity

    implements NavigationDrawerFragment.NavigationDrawerCallbacks, TextToSpeech.OnInitListener/*, TextToSpeech.OnUtteranceCompletedListener*/{ //The 2nd and 3rd implements are part of a test

//private Speaker speaker;
TextToSpeech tts;
public boolean ready = false;

@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main); // this is the original one

    tts = new TextToSpeech(this, this);
    //tts.setLanguage(Locale.US);


//these methods below are for TTS
@Override
public void onInit(int status) {  //for TTS
    if (status == TextToSpeech.SUCCESS) {
        // Change this to match your
        // locale
        tts.setLanguage(Locale.US);
        ready = true;
    } else {
        ready = false;
    }

}

@Override
protected void onDestroy() { //for TTS
    super.onDestroy();
}


public void textToSpeech(String text){

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        ttsGreater21(text);
    } else {
        ttsUnder20(text);
    }
}

@SuppressWarnings("deprecation")
private void ttsUnder20(String text) {
    HashMap<String, String> map = new HashMap<>();
    map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "MessageId");
    tts.speak(text, TextToSpeech.QUEUE_FLUSH, map);
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void ttsGreater21(String text) {
    String utteranceId=this.hashCode() + "";
    tts.speak(text, TextToSpeech.QUEUE_FLUSH, null, utteranceId);
    //tts.speak(text, TextToSpeech.QUEUE_FLUSH, null, null);
}


public void ttsExample(View y) {

    Button myButton = (Button) y;
    textToSpeech("Random joke");

}

}

This is the method I use to call it in another class, I'm sure the problem is here, since I have no idea how to get this working, I've tried various different ways.

MainActivity mainActivity = new MainActivity();
mainActivity.textToSpeech(clickedVocab); //<--here

This is the full class where the list is (and the 2 lines above too):

public class VocabularyFragment extends Fragment implements View.OnClickListener {
//initialize vocab list
private ArrayList<String> vocabsList;
private ArrayAdapter<String> itemsAdapter;
private ListView vocabListView;
private String clickedVocab;
private View rootview;
private Speaker speaker;
private final int CHECK_CODE = 0x1;




@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    rootview = inflater.inflate(R.layout.fragment_vocab_list,container, false); //this works!
    initialVocabList(rootview);

    Button b = (Button) rootview.findViewById(R.id.BtnAddVocab);
    b.setOnClickListener(this);


    return rootview;

}

void initialVocabList(View view) {

    // ADD HERE
    vocabListView = (ListView)view.findViewById(R.id.vocabList);
    //vocabsList = new ArrayList<String>();
    //retrieve from SharedPreferences

    TinyDB tinydb = new TinyDB(getActivity());
    vocabsList = tinydb.getListString("vocabs");
    //itemsAdapter = new ArrayAdapter<String>(this, R.layout.vocab_notes_item, items);
    itemsAdapter = new ArrayAdapter<String>(getActivity(), R.layout.vocab_notes_item, vocabsList);

    vocabListView.setAdapter(itemsAdapter);

    // Setup remove listener method call
    setupListViewListener();
    // Setup Onclick method call
    setOnClickListener();

}

private void setupListViewListener() {
    vocabListView.setOnItemLongClickListener(
            new AdapterView.OnItemLongClickListener() {
                @Override
                public boolean onItemLongClick(AdapterView<?> adapter,
                                               View item, int pos, long id) {
                    // Remove the item within array at position
                    /* createDelVocDialog();
                   if (confirmDelete){          //if boolean is true
                        items.remove(pos);
                    }*/
                    noteDeletedToast(vocabsList.get(pos));
                    vocabsList.remove(pos);

                    // Refresh the adapter
                    itemsAdapter.notifyDataSetChanged();
                    // Return true consumes the long click event (marks it handled)
                    return true;
                }

            });

}

private void setOnClickListener() {
    vocabListView.setOnItemClickListener(
            new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> adapter,
                                        View view, int pos, long id) {
                    //System.out.println("entrei");   //anderson's test "dividir para conquistar"

                    Context context = view.getContext();
                    clickedVocab = vocabsList.get(pos);

                    MainActivity mainActivity = new MainActivity();
                    mainActivity.textToSpeech(clickedVocab);            //<--  HERE!

                    Toast.makeText(context, "Item: " + clickedVocab, Toast.LENGTH_SHORT).show();
                }
            });
}

private void noteDeletedToast (String note) {
    Toast.makeText(getActivity(), "Vocab note deleted: " + note , Toast.LENGTH_SHORT).show();
}


private void onAddVocab(View v) {
    EditText vocabTextBox = (EditText) v.findViewById(R.id.edTextVocab);


    if (vocabTextBox.getText().toString().equals("")) {         //Check if the EditText is not empty
        Toast.makeText(getActivity(), "You forgot to write in the box!", Toast.LENGTH_SHORT).show();
        return;

    } else {
        String itemText = vocabTextBox.getText().toString();
        itemsAdapter.add(itemText.trim());  //This also performs "trim" on text
        vocabTextBox.setText("");
        Toast.makeText(getActivity(), "Note added", Toast.LENGTH_SHORT).show();

        //save to SharedPreferences
        TinyDB tinydb = new TinyDB(getActivity());
        tinydb.putListString("vocabs", vocabsList);

    }
}


@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.BtnAddVocab:
            onAddVocab(rootview);
            break;
    }

}
}

Finally, this is the error message:

     java.lang.NullPointerException: Attempt to invoke virtual method 'int android.speech.tts.TextToSpeech.speak(java.lang.CharSequence, int, android.os.Bundle, java.lang.String)' on a null object reference

Any help is appreciated =)

Falko
  • 17,076
  • 13
  • 60
  • 105
Tiago Colombo
  • 33
  • 1
  • 8
  • Here's a hint: triple check that `vocabsList.get(pos)` is not returning a null value. – Makoto May 14 '15 at 20:22
  • It can't be returning a null value, because it shows perfectly in the toast below:`Toast.makeText(context, "Item: " + clickedVocab, Toast.LENGTH_SHORT).show();` – Tiago Colombo May 14 '15 at 20:27
  • @Makoto, this question is not a duplicate, I searched for a solution here for 2 days and no other case helps me here. could you remove the duplicate flag? – Tiago Colombo May 14 '15 at 20:47
  • From what I can see it reads like one. The main thing that I did was trace back the logical execution of your application from where the exception was noted to where there was a possibility of a `null` value making its way into the system. There are a decent number of android-specific questions which also relate to the same issue. Have you attached a debugger to this code and actually stepped through it? – Makoto May 14 '15 at 20:50
  • From the error that's what I get too =/ this variable works perfectly inside this class, didn't get anything useful from the debugger about this. I even tried `this: mainActivity.textToSpeech("test");` and the error doesn't change, What makes me believe the problem is in the method call... what else could be returning `null` in your opinion? – Tiago Colombo May 14 '15 at 21:06
  • Why are you explicitly passing `null` to the method call? `tts.speak(text, TextToSpeech.QUEUE_FLUSH, null, utteranceId);` – Makoto May 14 '15 at 21:10
  • That's a snippet I found here to set textToSpeech to either API 21 or previous versions, the `null` value was the only one I couldn't figure out what to do, and `null` worked fine until this point. It should be "Bundle params" according to my notes, any suggestion? – Tiago Colombo May 14 '15 at 21:41
  • I solved this problem, using a completely different approach, thanks @Makoto, for the suggestions. Is there any way I can delete this post to not pollute this website too much? – Tiago Colombo May 15 '15 at 02:56
  • @TiagoColombo Could you please write how you solved the problem in the end? – hexicle Aug 31 '17 at 08:46
  • 1
    @hexicle I'm not sure how to answer my own question, but I'm commenting what I did. The problem is that the Activities are not like normal classes you can create a new instance and access their methods. The MainActivity is already running so you can call i like this: `((MainActivity)getActivity()).textToSpeech(clickedVocab);` If you still have doubts I can try to provide you with more details. – Tiago Colombo Aug 31 '17 at 16:31
  • 1
    To clarify, `getActivity()` is actually any context you have available. In this snippet I was calling it from a fragment. – Tiago Colombo Aug 31 '17 at 16:39
  • @TiagoColombo I ended up asking it and got a [solution](https://stackoverflow.com/questions/45978089/calling-texttospeech-from-a-different-class/45978177#45978177) that worked. Yes the challenge was accessing the context. – hexicle Aug 31 '17 at 22:24

0 Answers0