I want to create a separate class within my application to handle error reporting and send specific errors to a database. However, I'm unable to figure out what the Context should be and how this should be properly coded. I assume it should still be possible, I just need to code it differently, if that is not the case, what is the best solution for me?
public class SendError implements Runnable
{
private String url;
public SendError(String errors, String form, String database, String SQL)
{
url = string;
Handler handler = new Handler();
handler.post(new Runnable() {
public void run() {
Toast toast = Toast.makeText(getContext, msg, Toast.LENGTH_LONG);
toast.show();
}
});
}
}
EDIT:
What I'm trying to do is create one class for my entire application that handles recording of SQL errors when submitting data to the database. The class needs to do 2 simple things. Submit information based on what form, database, time submitted, and the SQL code that created the error. The other thing I would like this class to do is to display a toast giving basic error information back to the user. I have the data submission portion of this worked out properly (hence the reason for the Runnable), but am still getting errors for the Toast.
Shouldn't do the work in your constructor, this makes your separate class useless.
public class SendError implements Runnable
{
private final Context context;
private final String url;
public SendError(Context context, String string) {
this.context = context;
this.url = string;
}
public void makeToast(String msg, String errors, String form, String database, String SQL) {
Handler handler = new Handler();
handler.post(new Runnable() {
public void run() {
Toast toast = Toast.makeText(context, msg, Toast.LENGTH_LONG);
toast.show();
}
});
}
}
Your context needs to be the relevant context, from using a Toast the Context is usually an Activity which can take the form of:
this (in an Activity)
ActivityName.this (in a inner class of an Activity)
getActivity (in a Fragment inside an Activity)
For example:
new SendError(YourActivity.this, "something").makeToast("Hello", "errors", "form", "database", "sql");
Just need to pass Context in the constructor when you create this class.
I would advise you rethink this class though - it's called "SendError" which sounds like a method name, it implements Runnable for some reason, and it's notifying the user with Toasts - sounds like too much for one class.
Toast toast = Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
or
Toast toast = Toast.makeText(SendError.this, msg, Toast.LENGTH_LONG).show();
Related
I am using the quickstart-android code provided by google but after many attempts I cam unable to find a context that is not returning null. The BarcodeScannerProcessor is not itself an Activity, so I have attempted to create an instance of the LivePreviewActivity and use that as the context in the intent, but it's null.
The goal is to once a valid barcode is recognized I want to open a new activity that allows a user to verify value and on the push of a button call a webservice to post the barcode to a database via API. I am having a hard time finding a valid context and the app is crashing when it trys to execute the Intent.
Starting at line 97-107:
https://github.com/jamiekeefer/quickstart-android/blob/master/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/barcodescanning/BarcodeScanningProcessor.java
for (int i = 0; i < barcodes.size(); ++i) {
FirebaseVisionBarcode barcode = barcodes.get(i);
BarcodeGraphic barcodeGraphic = new BarcodeGraphic(graphicOverlay, barcode);
graphicOverlay.add(barcodeGraphic);
System.out.println(barcode.getRawValue());
if (!barcode.getRawValue().equals("") ) {
System.out.println("Got the number:" + barcode.getRawValue() + " Context: " + mContext); //OLD SCHOOL DEBUG OUTPUT
//enter code to start activity
Intent intent = new Intent(mContext, SendScannedBarcode.class);
String message = scannedBarcode;
intent.putExtra(EXTRA_MESSAGE, message);
mContext.startActivity(intent);
}
}
You can back up in the repo to see the instance of the LivePreviewActivity where I trying to get context.
I have tried a number of things and read about Context, Views and Activities and basically have completely confused myself. The only tuts I can find are using Kotlin, which is not helping clarify things.
I appreacite any help in indentifying or contruting a valid Intent from this Context. Thank you.
So I am assuming that in your LivePreviewActivity you are creating an object of the class BarcodeScanningProcessor. What you can do is change the constructor in the BarcodeScanningProcessor class to accept a context and then you pass in your LivePreviewActivity's context.
This is what the code should look like:
In BarcodeScanningProcessor:
public BarcodeScanningProcessor(Context context) {
// Note that if you know which format of barcode your app is dealing with, detection will be
// faster to specify the supported barcode formats one by one, e.g.
// new FirebaseVisionBarcodeDetectorOptions.Builder()
// .setBarcodeFormats(FirebaseVisionBarcode.FORMAT_QR_CODE)
// .build();
detector = FirebaseVision.getInstance().getVisionBarcodeDetector();
this.mContext = context;
}
Then in LivePreviewActivity:
In the particular case of your activity you would do:
case BARCODE_DETECTION:
Log.i(TAG, "Using Barcode Detector Processor");
cameraSource.setMachineLearningFrameProcessor(new BarcodeScanningProcessor(getApplicationContext()));
break;
Or if you just wanted to create an object of the class you could do:
BarcodeScanningProcessor bsp = new BarcodeScanningProcessor(getApplicationContext());
This should now give your BarcodeScanningProcessor class the context of your activity. Now, in BarcodeScanningProcessor, mContext should not be null and will have the context of your activity. I hope this answers your question.
try this create Application class
import android.app.Application;
public class MyApplication extends Application {
static MyApplication instance;
#Override
public void onCreate() {
super.onCreate();
instance=this;
}
public static MyApplication getInstance() {
return instance;
}
}
Register in manifest file
<application
..
android:name="com.yourpackage.MyApplication"
..>
.
.
.
</application>
start activity using this MyApplication.
Intent intent = new Intent(MyApplication.getInstance(), SendScannedBarcode.class);
String message = scannedBarcode;
intent.putExtra(EXTRA_MESSAGE, message);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MyApplication. getInstance().startActivity(intent);
Another way of handling the issue is create new constructor of BarcodeScanningProcessor which takes interface call back and once processing is done pass back result to caller.
public interface BarcodeUpdateListener {
#UiThread
void onBarcodeDetected(Barcode barcode);
}
private BarcodeUpdateListener callback;
public BarcodeScanningProcessor(BarcodeUpdateListener callback){
this.callback = callback;
detector = FirebaseVision.getInstance().getVisionBarcodeDetector();
}
Once you get the result pass result to caller
callback.onBarcodeDetected(<Barcode>)
You can get the context from graphicOverlay:
Context context = graphicOverlay.getContext();
So I'm following this example in Android developers:
http://developer.android.com/training/run-background-service/create-service.html
Creating a background service with IntentService.
Note that we define the class RSSPullService in the first code example:
public class RSSPullService extends IntentService {
#Override
protected void onHandleIntent(Intent workIntent) {
// Gets data from the incoming Intent
String dataString = workIntent.getDataString();
...
// Do work here, based on the contents of dataString
...
}
}
In the following page, Reporting Work Status:
http://developer.android.com/training/run-background-service/report-status.html
I'm confused, are we defining the same class again to get the status?
public final class Constants {
...
// Defines a custom Intent action
public static final String BROADCAST_ACTION =
"com.example.android.threadsample.BROADCAST";
...
// Defines the key for the status "extra" in an Intent
public static final String EXTENDED_DATA_STATUS =
"com.example.android.threadsample.STATUS";
...
}
public class RSSPullService extends IntentService {
...
/*
* Creates a new Intent containing a Uri object
* BROADCAST_ACTION is a custom Intent action
*/
Intent localIntent =
new Intent(Constants.BROADCAST_ACTION)
// Puts the status into the Intent
.putExtra(Constants.EXTENDED_DATA_STATUS, status);
// Broadcasts the Intent to receivers in this app.
LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
...
}
Dont get confused,
both the classes are same
First one is to show how we create a service extending IntentService
Then they gave a example to send data to this IntentService
At last they gave example to shows how the same IntentService is returning result back.
Second code is just another example they changed the content of old intent service class
That's two separate examples, no need to define it twice, just use one definition. The code from first example (creating Intent Service) is just merged with code from Reporting Work example.
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.
So, everybody knows that we make a Class extending CordovaPlugin and override the execute() and then creates a bridge between the JS and native Java (for Android). Further we use PluginResult to return the result back to the JS.
So, all of this happens when there is a request fired from the JS to the Java Plugin. My question is, how to send a result back to JS (and therefore to HTML) asynchronously ? I don't know if the word asynchronous is right here. The thing is I want to send something back to the JS out of the blue (say, when wifi becomes enable/disable).
I have already researched on this but haven't got anything which suits to my case.
The thing I've tried is -
Created a BroadcastReceiver listening to the WiFi events using the WifiManager class.
Registered the receiver.
And finally, popping a Toast when WiFi is enabled/disabled, and sending the result using CallbackContextcallbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, "Wifi
Connected")) and for disconnected with a different message.
MyPlugin.java
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
...
public class MyPlugin extends CordovaPlugin {
private WifiReceiver wifiBroadcastReceiver = null;
private CallbackContext callbackContext = null;
...
public MyPlugin() {
wifiBroadcastReceiver = new WifiReceiver();
...
}
...
public boolean execute(String action, final JSONArray args,
final CallbackContext callbackId) throws JSONException {
IntentFilter wifiFilter = new IntentFilter(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
cordova.getActivity().registerReceiver(wifiBroadcastReceiver, wifiFilter);
this.callbackContext = callbackId;
...
}
public class WifiReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
if (intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false)) {
Toast.makeText(cordova.getActivity(), "Wifi Connected", Toast.LENGTH_SHORT).show();
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, "Wifi Connected"));
} else {
Toast.makeText(cordova.getActivity(), "Wifi Disconnected", Toast.LENGTH_SHORT).show();
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, "Wifi Disconnected"));
}
}
}
}
The Toast pops but the PluginResult isn't sent to the JS.
PS : Listening to WiFi events isn't my actual problem, I want to replicate the Android Bluetooth Chat app in Phonegap. So, it has to be asynchronous in nature.
You are almost there but you need to setKeepCallback to true on your PluginResult. If you don't the subsequent results from the Java side will not have a callback on the JavaScript side. The best example of this type of coding is the Network plugin in Cordova core. Here is a link to the source:
https://git-wip-us.apache.org/repos/asf?p=cordova-plugin-network-information.git;a=blob;f=src/android/NetworkManager.java;h=e2ac500ccc885db641d5df6dab8eae23026a5828;hb=HEAD
So you should update your code to:
public boolean execute(String action, final JSONArray args,
final CallbackContext callbackId) throws JSONException {
IntentFilter wifiFilter = new IntentFilter(
WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
cordova.getActivity().registerReceiver(wifiBroadcastReceiver,
wifiFilter);
this.callbackContext = callbackId;
PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT);
result.setKeepCallback(true);
this.callbackContext.sendPluginResult(result);
return true;
}
public class WifiReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
PluginResult result;
if (intent.getBooleanExtra(
WifiManager.EXTRA_SUPPLICANT_CONNECTED, false)) {
Toast.makeText(cordova.getActivity(), "Wifi Connected",
Toast.LENGTH_SHORT).show();
result = new PluginResult(PluginResult.Status.OK,
"Wifi Connected");
} else {
Toast.makeText(cordova.getActivity(), "Wifi Disconnected",
Toast.LENGTH_SHORT).show();
result = new PluginResult(PluginResult.Status.ERROR,
"Wifi Disconnected");
}
result.setKeepCallback(false);
if (callbackContext != null) {
callbackContext.sendPluginResult(result);
callbackContext = null;
}
}
}
}
Answer to 'second callback' warning...
The Cordova source-code which triggers this warning can be found on line 57 here:
https://github.com/apache/cordova-android/blob/master/framework/src/org/apache/cordova/CallbackContext.java
Thus - warning is caused because your CallbackContext object has 'finished=true'.
Most likely cause of this is you called: callbackContext.sendPluginResult(pluginResult);
Without first calling: pluginResult.setKeepCallback(true);
If not... most likely you are unintentionally caching the CallbackContext object.
Your execute() function should assign CallbackContext each time it is called. See lines 125-127 in the code Simon linked to:
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
if (action.equals("getConnectionInfo")) {`
this.connectionCallbackContext = callbackContext;
...
The proper sequence of events in full:
Make initial call to plugin.
Plugin saves reference to passed in CallbackContext object.
Keep CallbackContext object reference, while returning results with setKeepCallback(true).
When the sequence is finished, return with setKeepCallback(false) (the default)
Then later...
Make another call to plugin.
Plugin overwrites saved CallbackContext reference, replace with passed in object.
Then steps 3-4 same as above.
Hope that helps :)
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.