In a barebones Android application, I want to call a method in the MainActivity instance, from an asynchronous callback in the instance of another class. Why does Java force me to call a static method in the class, rather than a non-static method in the instance itself?
My app has a MainActivity class and a TextToSpeech (TTS) class. From the main activity, I instantiate the class, passing a pointer to the MainActivity instance. Instantiation of the TTS engine is an asynchronous operation. I cannot interact with the TTS instance until it has triggered an onInit() method.
Below is code that works. However, I had imagined that I would be able to call a non-static method in the MainActivity instance, and this appears not to be possible. The code below uses a static call to the MainActivity class itself, so no instance variables are available.
Here are the changes I made to a basic Hello World application in Android Studio.
//MainActivity.java
package com.example.callback;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends ActionBarActivity {
private static TTS tts; // apparently this has to be static
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onResume() {
super.onResume();
tts = new TTS();
Log.d("onResume", this.toString());
// D/Main﹕ com.example.callback.MainActivity@4a014e50
tts.init(this);
}
// Apparently this method has to be static
public static void ttsReady() {
tts.speakText("Hello world");
}
}
Custom class.
// TTS.java
package com.example.callback;
import android.app.Activity;
import android.content.Context;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import java.util.HashMap;
import java.util.Locale;
public class TTS implements TextToSpeech.OnInitListener {
private TextToSpeech tts;
private Activity activity;
public void init(Activity currentActivity) {
activity = currentActivity;
Context context = activity.getApplicationContext();
tts = new android.speech.tts.TextToSpeech(context, this);
}
@Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
tts.setLanguage(Locale.UK);
Log.d("onInit", activity.toString());
// D/onInit﹕ com.example.callback.MainActivity@4a014e50
// activity.ttsReady();
// The line above does not compile. ttsReady() is not recognized as a
// method of activity, regardless of whether the tts variable and the
// ttsReady() method in the MainActivity class are made static or not,
// Making the activity variable static here has no effect either.
// The commented line below throws Error:(31, 35)
// error: non-static method toString() cannot be referenced from a static context
// So presumably MainActivity is a static variable.
// Log.d("onInit", MainActivity.toString())
// This works, if the tts variable and the ttsReady() method in the
// MainActivity class are made static. Is there a non-static alternative?
MainActivity.ttsReady();
}
}
// Deprecated signature for speak() used for compatibility with API 20
// and earlier
public void speakText(String toSpeak) {
int mode = android.speech.tts.TextToSpeech.QUEUE_FLUSH;
// Object hashMap = null; // Causes a "no suitable method error".
// How is HashMap null not the same as Object null? Using just plain null
// instead of hashMap also works with no problems.
HashMap hashMap = null;
tts.speak(toSpeak, mode, hashMap);
}
}
No comments:
Post a Comment