For few days now i got SIGSEGV errors at random points in my app. It crashed when i do nothing.
I started taking apart code to see which line was causing this segmentation, and was most shocked when i found out that it was: ( drum roll, please )
Activity.setResult(Activity.OK,intent)
WHAT? This still doesn't make ANY sense to me at all! In the line below i will show you my code before and after and can anyone tell me WHY the SIGSEGV was happening?
Before
CommentActivity:
val comments = ArrayList<Comment>()
comments.add(comment)
/*Set the results*/
val intent = Intent()
intent.putExtra("comment_result", Utils.General.serializeToJson(comments))
this.setResult(Activity.RESULT_OK, intent)
this.finish()
MainActivity:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
switch (requestCode) {
//catch data from CommentActivity
case (INTENT_COMMENT): {
if (resultCode == RESULT_OK) {
String comments = intent.getExtras().getString("comment_result");
if (comments != null && !comments.isEmpty()) {
/*Save the instance to the database and expect the database observable to call the upload thread*/
Type type = new TypeToken<ArrayList<Comment>>() {}.getType();
ArrayList<Comment> list = Utils.General.Companion.deserializeFromJson(comments, type);
/*Save the instance to the database and expect the database observable to call the upload thread*/
DataSource.INSTANCE.saveComments(list);
} else {
showToast(getResources().getString(R.string.picture_lost), Toast.LENGTH_SHORT);
}
}
break;
}
==== This crashed in MainActivity after between 10secs and 1 minute =====
After - No Crash
CommentActivity:
/*Set the results*/
DataSource.saveComments(comments)
this.finish()
Related
I have two separate applications written using Xamarin.Android; for the sake of discussion, let's call them "Tristan" and "Isolde". Tristan has some state information that Isolde sometimes needs to know. Complication: Tristan may or may not be running at the moment Isolde develops the need to know his state.
I've got kludge working now where Isolde sends a special launch intent to Tristan, who then uses a broadcast intent to send information back to Isolde. (See my earlier question for details.)
"But wait!" I hear you cry, "Is this not a perfect use case for StartActivityForResult()?" Indeed it is! The code is a whole lot simpler, and everything I've read implies that this is how Android wants you to do stuff like this.
Unfortunately, I can't get it to work (despite trying many variations and reading the dozen-or-so related questions on this very site). My specific problem is that in Isolde's OnActivityResult() callback, the resultCode is always Result.Canceled and the data is always null.
Here is the code for Tristan (where commented-out bits represent variations I've tried):
using Android.App;
using Android.Content;
namespace com.example.Tristan.Android
{
[Activity(Name ="com.example.Tristan.Android.IsoldeQueryActivity")]
public class IsoldeQueryActivity : Activity
{
protected override void OnStart()
{
// base.OnStart();
var rtn = new Intent();
rtn.PutExtra("Test", "test");
//rtn.SetAction("TestAction");
SetResult(Result.Ok, rtn);
Finish();
//FinishActivity(1234);
}
}
}
And here is the relevant code from the Activity where Isolde needs to ask for Tristan's state:
private TaskCompletionSource<bool> TristanStateCompletion;
public async Task GetTristanState()
{
TristanStateCompletion = new TaskCompletionSource<bool>();
var req = new Intent("com.example.Tristan.Android.IsoldeQueryActivity");
//req.PutExtra(Intent.ExtraReturnResult, true);
StartActivityForResult(req, 1234);
var rtn = await TristanStateCompletion.Task;
if (!rtn) bomb("can't get state");
TristanStateCompletion = null;
}
protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if(requestCode == 1234) {
DoStuffWith(data);
TristanStateCompletion?.TrySetResult(true);
}
}
Diagnostics -- or rather, a specific lack of them -- leads me to believe that Tristan's IsoldeQueryActivity.OnStart() is never actually being called.
Ideas, requests for additional information and/or useful experiments to try are all welcome. (If your idea is "Put <thing> in the manifest", remember this is Xamarin.Android and I have to do that by putting <relatedThing> in the attribute decorating the Activity.)
Edited to add: In Isolde's code, DoStuffWith(data) was crashing because data was null. When I changed that method to avoid that, I found that I got a (slightly later) exception thrown in StartActivityForResult():
Android.Content.ActivityNotFoundException No Activity found to handle Intent { act=com.example.Tristan.Android.IsoldeQueryActivity }
This leads me to believe I'm not creating the Intent properly in Isolde. Do I need to be using one of the other Intent constructors? If so, how specifically?
Okay, I think I have this figured out. The code in my original question had three major problems:
I was building the Intent incorrectly in Isolde.
I didn't export the IsoldeQueryActivity in Tristan.
The call to base.OnStart() in Tristan's OnStart override is mandatory.
Here is the working version of Tristan:
using Android.App;
using Android.Content;
namespace com.example.Tristan.Android
{
[Activity(Name ="com.example.Tristan.Android.IsoldeQueryActivity", Exported=true)]
public class IsoldeQueryActivity : Activity
{
protected override void OnStart()
{
base.OnStart();
var rtn = new Intent();
rtn.PutExtra("Test", "test");
SetResult(Result.Ok, rtn);
Finish();
}
}
}
And here is the fixed code from Isolde:
private TaskCompletionSource<bool> TristanStateCompletion;
public async Task GetTristanState()
{
TristanStateCompletion = new TaskCompletionSource<bool>();
var req = new Intent();
req.SetComponent(new ComponentName("com.example.Tristan.Android", "com.example.Tristan.Android.IsoldeQueryActivity"));
StartActivityForResult(req, 1234);
var rtn = await TristanStateCompletion.Task;
if (!rtn) bomb("can't get state");
TristanStateCompletion = null;
}
protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if(requestCode == 1234) {
if(resultCode != Result.Ok) bomb("bad resultCode {0}", resultCode);
if(data == null) bomb("null data from Tristan");
DoStuffWith(data);
TristanStateCompletion?.TrySetResult(true);
}
}
So I'm making a Speech to Text app using the voice assistant. I'm trying to make a phone call feature so the user can speak a number and it will call it.
I'm almost there but the number only rings the second time I speak it. The first time it says "Call not sent".
I figured out the reason for this is; when the user speaks the number it's not updating the variable first and then calling the "call" function. I've tried almost everything but it doesn't update the variable correctly.
I.e.
private TextView txtSpeechInput;
public String num = "123";
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case REQ_CODE_SPEECH_INPUT: {
if (resultCode == RESULT_OK && null != data) {
ArrayList<String> result = data
.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
txtSpeechInput.setText(result.get(0).replaceAll("\\s+", ""));
num = txtSpeechInput.getText().toString();
}
break;
}
}
}
public void dialPhoneNumber(String phone) {
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:" + phone));
if (intent.resolveActivity(getPackageManager()) != null) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) {
startActivity(intent);
}
return ;
}
}
private void processResult(String command) {
command = command.toLowerCase();
if(command.indexOf("time") != -1) {
Date now = new Date();
String time = DateUtils.formatDateTime(this, now.getTime(), DateUtils.FORMAT_SHOW_TIME);
speak("The time is " + time);
}
if(command.indexOf("date") != -1) {
String date = DateFormat.getDateInstance().format(new Date());
speak("The date is " + date);
}
else if (command.indexOf("open") != -1) {
if(command.indexOf("browser") != -1) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.google.co.uk/"));
startActivity(intent);
}
}
if(command.indexOf("call") != -1) {
promptSpeechInput();
try {
Thread.sleep(18000);
} catch (InterruptedException e) {
e.printStackTrace();
}
dialPhoneNumber(num);
}
}
In this code, wen the use says "make a call" it opens another prompt to take the speech input. Stores it in txtSpeechInput (Where it says results.get0) and then at that stage I update the "num" variable and convert it to a string.
It then runs dialPhoneNumber
Now let's say I run it the first time and speak "07123456789", it will say call not sent because its trying to call the default 123, if i speak it again or a different number then it will ring the 07123456789.
How and why does it not update before calling the phone feature?
Based on danny117's comment...
promptSpeechInput();
try {
Thread.sleep(18000);
} catch (InterruptedException e) {
e.printStackTrace();
}
dialPhoneNumber(num);
promptSpeechInput starts a new activity, and the result from that activity is the spoken text? If that's right, then why are you prompting for input, sleeping for 18 seconds (never sleep on the main thread by the way), and then assuming your input is ready? As danny says, prompting for input should be the last thing that if block does. Dialing the number should be initiated from onActivityResult.
Also, why is there a default phone number of "123"? That will never be correct, so is not a sensible default. And to reiterate, if you are putting the thread to sleep for a fixed amount of time waiting for something else to happen, you're almost certainly approaching it the wrong way. And if you're putting the main thread to sleep in Android you're absolutely doing it the wrong way.
Intro
I am writing class that provides me current localization only once if its able to, and returns default coordinats if can not do it for any reason. Class will be used in many places so I wanted to make it as simple to implement for others as it can be. So code would look like
LocationFinder locationFinder = new LocationFinder(this);
locationFinder.setLocationResolvedCallback(new LocationFinder.LocationResolvedCallback() {
#Override
public void onLocationFound(double latitude, double longitude) {
Log.e("Activity", latitude + " " + longitude);
}
});
locationFinder.findCurrentLocation();
but there is a case when locations settings are turned off, and I have to request user to turn them on.
task.addOnFailureListener(activity, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
int statusCode = ((ApiException) e).getStatusCode();
switch (statusCode) {
case CommonStatusCodes.RESOLUTION_REQUIRED:
try {
// Show the dialog and check result
ResolvableApiException resolvable = (ResolvableApiException) e;
resolvable.startResolutionForResult(activity, REQUEST_LOCATION_SETTINGS);
} catch (IntentSender.SendIntentException sendEx) {}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
break;
}
}
});
So now I have to go into activity and #Override onActivityResult(), handle it from activity level which makes my class less independent.
I wrote method that handle result code within my LocationFinder
public void onActivityResult(int requestCode, int resultCode) {
if (REQUEST_LOCATION_SETTINGS == requestCode) {
if (resultCode == Activity.RESULT_OK) {
requestCurrentLocation();
} else {
locationResolvedCallback.onLocationFound(DEFAULT_LAT, DEFAULT_LONG);
}
}
}
but I still have to #Override any activity that uses this class and call this method from it.
So my question is.
Why does android architects did not provide onActivityResult(...) callback as they did in case of permissions? So i could handle any request from within a class by just having reference to activity like
activity.onActivityResultCallback(...){///code}
There must be a reason but I may be missing something very obvious.
Activities have a lifecycle, and are therefore instantiated in a different way from an ordinary class.
However the functionality you are looking for can be provided by startActivityForResult(Intent). After the started activity is finished or removed from the stack, an intent is passed hack to the calling activity with a bundle you can use to pass back information
onActivityResult() called when you start activity for the result from the current Activity.
if you set the onActivityResult callback somewhere else following will happen.
Your fragments which are hosted in the activity can't get onActivityResult callback.
If you call multiple activities for the result you can't get a result properly (in one place).
For your reference see the below code. This will be never executed if you not called super.onActivityResult().
FragmentActivity onActivityResult:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
mFragments.noteStateNotSaved();
int requestIndex = requestCode>>16;
if (requestIndex != 0) {
requestIndex--;
String who = mPendingFragmentActivityResults.get(requestIndex);
mPendingFragmentActivityResults.remove(requestIndex);
if (who == null) {
Log.w(TAG, "Activity result delivered for unknown Fragment.");
return;
}
Fragment targetFragment = mFragments.findFragmentByWho(who);
if (targetFragment == null) {
Log.w(TAG, "Activity result no fragment exists for who: " + who);
} else {
targetFragment.onActivityResult(requestCode & 0xffff, resultCode, data);
}
return;
}
Due to this factors android not provided anonymous callback of onActivityResult()
Suggestion: In my case, I have used BroadcastReceiver to get onActivityResult on my class.
Hope it helps:)
I am trying to have the app recognize certain words said by the user using the code below, but for some reason it isn't working at all. Please review this and tell me what is wrong with it. Thank you
The app is simply suppose to display a toast message if the words "orange" or "apple" is said but nothing happens when using the code below.
//button onclick to trigger RecognizerIntent
public void OnClick_Speed_Detector(View v)
{
Intent i = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
i.putExtra(RecognizerIntent.EXTRA_LANGUAGE, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
i.putExtra(RecognizerIntent.EXTRA_PROMPT, "speak up");
startActivityForResult(i, 1);
}
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if(requestCode == 1 && resultCode == RESULT_OK)
{
ArrayList<String> result =
data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
if(((result).equals("orange")))
{
Toast.makeText(getApplicationContext(), "orange", Toast.LENGTH_LONG).show();
}
else
if (((result).equals("apple")))
{
Toast.makeText(getApplicationContext(), "apple", Toast.LENGTH_LONG).show();
}
}
}
Your issue is that you are testing if an ArrayList == a String, when it can't possibly (an ArrayList of type String contains multiple strings)
Instead of:
if ((result).equals("orange")) {}
Try:
if ((result).contains("orange")) {}
This code will look through every index of the ArrayList and determine if any of the indexes of it equal "orange". If any do then it will return
true
...and it will execute the if statement!
Hope this helps!
i am facing problem since two day, i get response RESULT_OK but how can i check it into activity. after this i have to go to download window function, it is not showing dialog.please help me out thanks in advance...:(
ResponseHandler rep = new ResponseHandler();
String ecase=rep.responsecheck;
rep.register(mDungeonsPurchaseObserver);
System.out.println(ecase);
if(ecase!=null){
if(ecase.matches("RESULT_OK")){/
Toast.makeText(this,ecase, Toast.LENGTH_LONG).show();
}
else{
Toast.makeText(this,ecase, Toast.LENGTH_LONG).show();
}
}else{
Toast.makeText(this,ecase, Toast.LENGTH_LONG).show();
}`
but this working is in oncreate and get null.
Try this
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode)
{
case REQUEST_CONNECT_DEVICE:
//Body what ever u want to do....
}}