Android programming: ANDROID_CONTEXT parameter is not passed in error - java

I'm programming an app with that Nuance SpeechKit that performs TTS. It requires the context (called from getApplicationContext()) to be passed into some functions. Unfortunately, I'm getting this error in my log: ANDROID_CONTEXT parameter is not passed in!!!
Let me give more background: There in a main activity, and it opens a dialog from a button. The dialog invokes the text-to-speech functionality. As a result, I call getApplicationContext() in the main activity and pass it to my DialogFragment as a parameter using setters. Unfortunately, I'm getting this error even though I am calling the setters. So what could be going wrong? Here's a bit of code:
In my main activity:
// Instance variables...
private SpeechKit speechKit;
private Context context;
protected void onCreate(Bundle savedInstanceState) {
...
context = getApplicationContext();
...
this.speechKit = SpeechKit.initialize(context,
"CORRECT_API_KEY",
"sslsandbox.nmdp.nuancemobility.net",
443,
true,
SpeechKitAPIKey);
speechKit.connect();
}
public void invokeDialog() {
...
dialogueFragment.setContext(context);
dialogueFragment.setSpeechKit(speechKit);
...
}
And here's my code for the dialog fragment:
public void setSpeechKit(SpeechKit speechKit) {
this.speechKit = speechKit;
}
private SpeechKit speechKit;
private Context context;
public void setSpeechKit(SpeechKit speechKit) {
this.speechKit = speechKit;
}
public void setContext(Context context) {
this.context = context;
}
// Called when a button is pushed...
public void narrateText(String voice, String phrase) {
Vocalizer vocalizer = speechKit.createVocalizerWithVoice(voice, this, handler);
vocalizer.speakString(phrase, context);
}
Now I have no idea why this error is called. The code compiles fine. Any suggestions please?

I had the same issue, turned out to be that my free account expired (it lasts 90 days).
You probably send the login that is not valid anymore.

Related

FLutter Android Plugin, onDestroy function is not attached to the plugin class

i am creating a plugin with the onAttachedToEngine function that i use to assign context and mediaPlayer session to variables, exactly like the docs say so nothing special is being done. The problem is that when my plugin throws an error and it's time for the onDestroy function to be called, the onDestroy function doesn't seem to see the variables i set during the usage of the current object.
so if i set a variable X to "hello" in the onAttachedToEngine, onDestroy will keep seeing it as null and creates nullPointer exceptions which crashes my plugin and app.
here is a sample code i am using :
public class flutterPlugin extends MediaBrowserService implements FlutterPlugin, MethodCallHandler {
private String randomString = "lowercase";
private void initInstance(BinaryMessenger binaryMessenger, Context context) {
this.channel = new MethodChannel(binaryMessenger, ID);
this.channel.setMethodCallHandler(this);
am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mContext=context;
mNotificationManager = (NotificationManager) mContext
.getSystemService(Context.NOTIFICATION_SERVICE);
setupBroadcastReceiver();
startSession(mContext);
this.randomStirng = "UPPERCASE";
}
#Override
public void onAttachedToEngine(#NonNull FlutterPluginBinding binding) {
this.initInstance(binding.getBinaryMessenger(), binding.getApplicationContext());
}
#Override
public void onDestroy() {
this.randomStirng // here the random string i initialized is equal to "lowercase"
// and the same goes for all the variables initialized in initInstance, they are alll treated an null
(...)
}
(...)
}
what could the issue be ? is onDestroy being called from a child process ? when getting the parent of super it returns the same class name as the plugin

Change TextView text from another class using interface

I'm trying to make some utils functions to use in a bigger app later(download file from url, upload file to url etc)
So in MainActivity I have only 2 buttons that on click call static methods from Utils class.
However, I want on MainActivity to have some indicators of how things working on download/upload methods(connecting, connection success/fail, percent of download etc) so I put on MainActivity a TextView that will show that. I made an interface ICallback that contains void setConnectionStatus(String status) and from Utils class I use this to send to MainActivity the status.
Here are some parts of the code :
public class MainActivity extends AppCompatActivity implements ICallback {
Button btnDownloadDB, btnUploadDB, btnUploadPics;
TextView txtStatus;
ProgressBar pb;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Initialize stuffs
initViews();
//Setting listeners
btnDownloadDB.setOnClickListener(v -> {
txtStatus.setText(R.string.connecting);
pb.setVisibility(View.VISIBLE);
Utils.downloadFile(DOWNLOAD_DB, DB_FILE_NAME);
});
}
#Override
public void setConnectionStatus(String status) {
Log.d("MIHAI", status);
txtStatus.setText(status);
}
The interface :
public interface ICallback {
void setConnectionStatus(String status); }
And the Utils class :
public class Utils {
static ICallback callback= new MainActivity();
public static void downloadFile(String downloadURL, String fileName) {
IFileTransferClient client = ServiceGenerator.createService(IFileTransferClient.class);
Call<ResponseBody> responseBodyCall = client.downloadFile(downloadURL);
responseBodyCall.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Log.d("MIHAI", "connection ok");
callback.setConnectionStatus("Connection successful");
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d("MIHAI", "err...fail");
callback.setConnectionStatus("Connection failed. Check internet connection.");
}
});
}
The problem appear on MainActivity, when I try to set text of the txtStatus TextView getting a null reference error even if the txtStatus is initialized on initViews() method.
The Logs are working fine so I get the right status in MainActivity. I tried to initialize the TextView again in that function before seting the text and im getting : "java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.pm.ApplicationInfo android.content.Context.getApplicationInfo()' on a null object reference
at android.content.ContextWrapper.getApplicationInfo(ContextWrapper.java:183)"
Is there any chance to make this work?
Thank you for reading.
Kind regards,
Mihai
There are multiple problems with your solution but the main one is this line:
static ICallback callback= new MainActivity();
First of all, never hold a static reference to Activity, Fragment, Context or any Context related classes. These classes are either bound to a Context or represent the Context itself. You may leak memory this way. But that is the other problem.
What is the actual problem in your code is that new MainActivity() in Utils class creates an absolutely different instance of MainActivity that has nothing to do with MainActivity that is responsible for displaying your UI in the runtime.
What you should do instead is pass an instance of ICallback to the function as an argument:
public static void downloadFile(String downloadURL, String fileName, ICallback callback) {
...
}
And remove static ICallback callback= new MainActivity();.
Note: when you pass a callback object to a function make sure when it is called your Activity is not in a finished state.

android:singleton instance not garbage collected after application is closed

I have an android activity with a fragment.
In the fragment, I fetch data using retrofit and set a static flag, so that , when I again go to this fragment, I restrict fetching data again.
I also store the data in a singleton instance.
But even after I destroyed the activity/closed the application, the static flag and the instance is still available and the list is also present in the instance, which malfunctions my app.
But I want the instance to be created newly and fetch data at each run.
This is my singleton instance.
public class Utilities {
private static Utilities utils = null;
private List<Data> friendsList;
public List<Data> getDataList() {
return dataList;
}
public void setDataList(List<Data> dataList) {
this.dataList = dataList;
}
private List<Data> dataList;
public synchronized static Utilities getInstance(){
if(utils == null){
utils = new Utilities();
}
return utils;
}
}
This is my fragment:
public class DataFragment extends Fragment
{
private static boolean hasObtainedData;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if(!hasObtainedData){
getData(v);
}else{
recyclerView.setAdapter(new Adapter(utils.getDataList()));
}
}
private void getData(View v) {
//get Data using Retrofit:
hasObtainedData = true;
utils.setDataList(dataListObtainedUsingRetrofit)
recyclerView.setAdapter(new Adapter(utils.getDataList()));
}
}
This is how, I call my fragment from MainActivity:
#Override
public void onTabSelected(TabLayout.Tab tab) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragmentBox, new DataFragment()).commit();
}
I tried giving System.gc() at onDestroy() of MainActivity, but still, the singleton instance is alive.
I search many SOF posts based on this, but wasn't able to solve this issue.
Any help will be really useful.
The pointer to the Singleton is static in the Utilities-Class itself, so the Singelton can never be available for GC, unless you set utils = null on leaving MainAcitivity with something like
Utilities.reset();
Your singleton wont survive your app being terminated, and what's probably happening is that you aren't actually killing the app entirely during your tests. Run adb shell am force-stop <your-app-package> from your console and see whether that still results in the issue.
With that said, if you only want your data to run once per application launch, then I would recommend you move it into the onCreate() lifecycle callback of your Application
public class App extends Application {
#Override
public void onCreate() {
super.onCreate();
//Begin process to fetch data and cache it here
}
}
Don't forget to add the application name to your manifest too, <application android:name="your.packagename.App"
You then have no need to modify your data at all - it will only run once per application launch.
If, however, what you actually want is for your data to update every time the Activity is launched, then do the same process as before but inside onCreate() of you Activity. You can also clear it in onDestroy(), if you want it to updated when your Activity is recreated:
#Override
public void onDestry() {
super.onDestroy();
Utilities.getInstance().setDataList(null);
}
Also, if your data is bound to the lifecycle of your Activity, then you don't really need a singleton (which is bound to the lifecycle of the application).

How to play android sounds NOT in activity class

How can I play sound from a class that DOES NOT extend activity? I've been searching for a while and in every tutorial or answers from stackoverflow I've seen that sounds are always implemented in an activity class.
But in this case I have a class thas has the logic of my game, in which I have a gameUpdate() function; and in that function I want to make a specific sound play if something happens (for example a collision). How can I possibly access the activity that is currently running, from this class? Is there any way to do that?
Thanks.
If you need to get the current Activity instance or context you need to pass it to your other classes so that you can use it. For example:
class ABC extends Activity
{
public void onCreate(Bundle b)
{
XYZ xyz=new XYZ(this); // Sending the current Activity instance
}
}
class XYZ
{
ABC activity;
public XYZ(ABC activity)
{
this.activity = activity; //Now you can use it in this class
}
}
getActivity() or if is inside a fragment getFragment().getActivity()
Or alternativelly you can make add a Context to your class and get the activity reference from the constructor of the class.
Ex:
public class MyClass {
Context mContext();
public MyClass(Context context){
this.context = context;
}
}
and in your Activity class when you call MyClass:
MyClass myClass = new MyClass(this);
Inside your custom lass you can reference activity methods using its context.
So you actually just need a Context, not specifically an Activity (which is a Context). I would recommend that the class that should play sounds has a constructor which requires a Context. Keep a reference, not directly to the Context that you receive, but to the Application context using getApplicationContext() to get a Context that is safe to retain without the risk of memory leaks.
public class MySoundPlayingClass {
private final Context mContext;
public MySoundPlayingClass(Context ctx) {
// Since ctx could be an Activity, and this class
// could exist outside of the lifecycle of the Activity,
// grab the Application context to get a safe reference.
mContext = ctx.getApplicationContext();
}
}
Have a Util class and do something similar to below one. You can pass the context (it can be Activity instance) and the resource id to play it
Usage:
Util.play(context, R.raw.soundFile);
Sample Util class:
public class Util {
public static void play(final Context context, int resource) {
MediaPlayer mp = MediaPlayer.create(context, resource);
if (null != mp) {
mp.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
mp.start();
}
}
}

Instantiating TextToSpeech inside GCMIntentService

So I have a bit of a problem. I am trying to make my app do things based on the message it receives through GCM. In this case it's supposed to make a sound by using the TextToSpeech class. It kind of works, but not the first time I send the message. I realise this is probably because TextToSpeech hasn't been instantiated, but I'm not sure how go to about and do that? I tried onInit(), but that didn't work at all.
Also, what is the best way to shut down TTS in my example?
Disclaimer: I come from a PHP background, and know very little Java. I try to learn by doing, so please forgive me if this is a silly question. Thanks in advance!
public class GCMIntentService extends GCMBaseIntentService {
private static final String TAG = "GCMIntentService";
public static TextToSpeech mtts;
public GCMIntentService() {
super(SENDER_ID);
}
#Override
protected void onMessage(Context context, Intent intent) {
Log.i(TAG, "Received message");
String message = intent.getExtras().getString("message");
mtts = new TextToSpeech(context, null);
if (message.startsWith("makeSound")) {
mtts = new TextToSpeech(context, null);
mtts.setLanguage(Locale.US);
mtts.speak(message, TextToSpeech.QUEUE_FLUSH, null);
}
}
}
It doesn't work the first time because the initialization of TextToSpeech is asynchronous. You can not simple instantiate it and use it as you are doing. You should provide a callback to be called once the TextToSpeech has been initialized if you want to use it right away.
mTextToSpeech = new TextToSpeech( this, new TextToSpeech.OnInitListener()
{
#Override
public void onInit( int status )
{
// Check for status might not be initialized due to errors
// Configure language/speed
}
} );
It does work the rest of the times, because mtts is static. This means that is a class variable and is not destroyed/initialized when creating new instances of the service. By the second time you use this service, this variable was already initialized in the first service execution.

Categories