I'm developing some application using Xamarin Forms that has a function of route following. When it is used in real conditions on a vehicle it crashes whithout any logs in spite of the fact that I'm using AppCenter, i.e. in App.xaml.cs OnStart I added
protected async override void OnStart()
{
AppCenter.Start("android=__mycode___" +
"uwp={Your UWP App secret here};" +
"ios={Your iOS App secret here}",
typeof(Analytics), typeof(Crashes));
bool hadMemoryWarning = await Crashes.HasReceivedMemoryWarningInLastSessionAsync();
ErrorReport crashReport = await Crashes.GetLastSessionCrashReportAsync();
if (crashReport != null)
{
Analytics.TrackEvent(crashReport.StackTrace);
}
}
In fact I tested my app in AppCenter by using Crashes.GenerateTestCrash() and got a test crash report. Besides I caught some errors using this approach. But now there is at least one reason that makes my app crash without any messages to AppCenter. Are there any clues how to resolve this problem?
Try using an actual asynchronous event handler.
private event EventHandler onStart = delegate { };
protected override void OnStart() {
onStart += handleStart; //subscribe
onStart(this, EventArgs.Empty); //raise event
}
private async void handleStart(object sender,EventArgs args) {
onStart -= handleStart; //unsubscribe
try {
AppCenter.Start("android=__mycode___" +
"uwp={Your UWP App secret here};" +
"ios={Your iOS App secret here}",
typeof(Analytics), typeof(Crashes));
bool hadMemoryWarning = await Crashes.HasReceivedMemoryWarningInLastSessionAsync();
ErrorReport crashReport = await Crashes.GetLastSessionCrashReportAsync();
if (crashReport != null) {
Analytics.TrackEvent(crashReport.StackTrace);
}
} catch (Exception ex) {
//...handle exception or log as needed
}
}
OnStart is a simple void method and not an actual event handler. This mean that when made async it will become a fire and forget function which wont allow you to catch any exceptions that may have occurred within it.
If it is not caught at startup then it probably means that you are doing something similar somewhere within the app using a non event async void that goes uncaught and is crashing the application.
Start by doing a search for any async void in your code and checking to make sure that it is an actual event handler.
Related
I have a Xamarin.Forms app and I am using FreshMvvm framework.
If I do this from ViewIsAppearing method of FirstPageModel:
CoreMethods.PushPageModel<SecondPageModel>();
I go the "SecondPageModel". Then, when I am in the "SecondPageModel" if I do:
CoreMethods.PopPageModel();
or press hard back button, or press title bar back button not works in Android (anything happens). I am using FreshMasterDetailNavigationContainer.
In iOS it works OK, I get back to FirstPageModel.
This is because ViewIsAppearing will always be called when the page starts displaying on the screen. When you pop the second page then go to the first page, the first page's ViewIsAppearing will fire again. It caused a dead cycle and prohibited your app from returning to the first page.
Add a property to avoid that:
bool isInitialized;
public FirstPageModel()
{
// ...
isInitialized = true;
}
protected async override void ViewIsAppearing(object sender, EventArgs e)
{
base.ViewIsAppearing(sender, e);
if (isInitialized)
{
await Task.Delay(100);
await CoreMethods.PushPageModel<SecondPageModel>();
isInitialized = false;
}
}
iOS may optimize this process, but I still recommend you to add this judgment statement.
Update:
Call it when your app has reached the main thread.
protected override void ViewIsAppearing(object sender, EventArgs e)
{
base.ViewIsAppearing(sender, e);
if (isInitialized)
{
Device.BeginInvokeOnMainThread(() =>
{
CoreMethods.PushPageModel<SecondPageModel>();
isInitialized = false;
});
}
}
I'm tryng to implement in-app-billing.
When i follow the tutorial and add the lines bellow to my app:
public void onDestroy() {
super.onDestroy();
if (mHelper != null) mHelper.dispose();
mHelper = null;
i receive the following error:
Error:(216, 45) error: unreported exception IabAsyncInProgressException; must be caught or declared to be thrown
The strange thing is when i replace mHelper.dispose() for mHelper.disposeWhenFinished() it works.
I'm worried cause the same error appears again in
mHelper.launchPurchaseFlow(this,ITEM_SKU,1001,mPurchaseFinishedListener,hpacote);
Thanks
Yes, i'm also waste a lot of time in this because in the Google Tutorial on https://developer.android.com/training/in-app-billing/preparing-iab-app.html the sample is old and buggy. If you want a right sample you have to download TrivialDrive from github https://github.com/googlesamples/android-play-billing/tree/master/TrivialDrive that has right corrections.
From TrivialDrive MainActivity:
try {
mHelper.launchPurchaseFlow(this, mSelectedSubscriptionPeriod, IabHelper.ITEM_TYPE_SUBS,oldSkus, RC_REQUEST, mPurchaseFinishedListener, payload);
} catch (IabAsyncInProgressException e) {
complain("Error launching purchase flow. Another async operation in progress.");
setWaitScreen(false);
}
and this is the onDestroy()
#Override
public void onDestroy() {
super.onDestroy();
// very important:
Log.d(TAG, "Destroying helper.");
if (mHelper != null) {
mHelper.disposeWhenFinished();
mHelper = null;
}
}
i've implemented this without error! ;)
To avoid users clicking repetitively on the same button and by the same token send multiple requests to server, I have used the following pattern:
In button ClickHandler.onClick, disable the button.
In call back, re-enable the button.
See pattern in code below. The "rpcCall" function below basically is the core implementation of the Button onClick(final ClickEvent event).
private void rpcCall(final ClickEvent event)
{
final AsyncCallback<Void> callback = new AsyncCallback<Void>()
{
#Override
public void onSuccess(Void result)
{
final Button source = (Button) event.getSource(); // Dev mode isLive assertion failure.
source.setEnabled(true);
// Process success...
}
#Override
public void onFailure(Throwable caught)
{
final Button source = (Button) event.getSource();
source.setEnabled(true);
// Process error...
}
};
// Disable sender.
final Button source = (Button) event.getSource();
source.setEnabled(false);
// RPC call.
final RpcAsync rpcAsync = getRpcAsync();
RpcAsync.rpcCall(..., callback);
}
I just noticed a "This event has already finished being processed by its original handler manager, so you can no longer access it" exception caused by an isLive assertion failure in dev mode when the onSuccess async function calls event.getSource().
It seems to work in production/javascript mode though.
This dev mode assertion failure makes me question this pattern.
Is it a good pattern? Why do I get the exception only in dev mode? What would be a better pattern?
Obviously, I could bypass the call to event.getSource() by passing the source Button as an argument of the rpc wrapper call function, but it seems redundant with the event object already carrying such a reference.
Historically, the way you got the event object in IE was to use window.event, which only lasted the time to process the event. GWT's Event object therefore had to put guards so you're discouraged to keep a hold on an event instance, as it could suddenly reflect another event being processed, or no event at all (weird!)
Fortunately, Microsoft has since fixed their browser, and this is why it works when you test it (I bet you didn't test in IE6 ;-) ).
The correct way to handle that situation is to extract all the data you need from the event and keep them in final variables:
private void rpcCall(final ClickEvent event)
{
final Button source = (Button) event.getSource();
final AsyncCallback<Void> callback = new AsyncCallback<Void>()
{
#Override
public void onSuccess(Void result)
{
source.setEnabled(true);
// Process success...
}
#Override
public void onFailure(Throwable caught)
{
source.setEnabled(true);
// Process error...
}
};
// Disable sender.
source.setEnabled(false);
// RPC call.
final RpcAsync rpcAsync = getRpcAsync();
RpcAsync.rpcCall(..., callback);
}
My code seems to crash on Android with NullPointer exception. But works on ios simulator.
private void CallFBInit()
{
if(!FB.IsLoggedIn){
FB.Init(OnInitComplete, OnHideUnity);
}else{
shareDialog();
}
}
private void OnInitComplete()
{
FB.Login("email,publish_actions",fbLoginCallBack);
}
private void fbLoginCallBack(FBResult result){
shareDialog();
}
#region FB.Feed() example
public bool IncludeFeedProperties = false;
private Dictionary<string, string[]> FeedProperties = new Dictionary<string, string[]>();
private void CallFBFeed(FBResult result)
{
shareDialog();
}
private void shareDialog(){
Dictionary<string, string[]> feedProperties = null;
if (IncludeFeedProperties)
{
feedProperties = FeedProperties;
}
FB.Feed(
toId: FB.UserId,
link: ConfigCS.FeedLink,
linkName: ConfigCS.FeedLinkName,
linkCaption: ConfigCS.FeedLinkCaption,
linkDescription: ConfigCS.FeedLinkDescription,
picture:ConfigCS.FeedPicture,
mediaSource: ConfigCS.FeedMediaSource,
actionName: ConfigCS.FeedActionName,
actionLink: ConfigCS.FeedActionLink,
reference: ConfigCS.FeedReference,
properties: feedProperties,
callback: CallbackForFeed
);
}
#endregion
void CallbackForFeed(FBResult result)
{
if(result.Error!=null){
errorMessage=ConfigCS.fbError+result.Text;
showError=true;
return;
}else{
Debug.Log ("FB Feed error");
}
return;
}
private void OnHideUnity(bool isGameShown)
{
Debug.Log("Is game showing? " + isGameShown);
}
#endregion
I coul'dnt figure out why. When the login dialog is shown, and returns to the app, the app crashes. But if i try again, (since the user is considered logged in), it works without a hiccup. Can somebody see any error in my code?
edit:
To be more precise
1. when user clicks share, fb login dialog opens
2. Once the user successfully logs in, and returns the app, the app crashes with nullpointer exception
I open the app again, and click share (at this point the user is already logged in before the crash) and it works.
I coul'dnt pin point the error since adb log just says NullPointException in facebook.loginActivity.
My initiating function is CallFBInit();
Edit:
One more thing i have noticed is, i have installed facebook sdk 4.3.3 but it shows 4.2.5 in the console
and in the editor
This seems to be a problem with the new 4.3.3 SDK
I have downgraded to 4.2.4 and it works fine.
Is this a known problem?
I need to do method interception for the onSuccess method in GWT.
I need to add some code before and after the calling of the onSuccess method in GWT? (I have many calls to the onSuccess method and I need to do this dynamically)
EDIT:
I need to add a progress bar in the right corner of the screen, that appears when the code enters the onsuccess method and disappears on the exit of onsuccess method.
From a visual perspective
void onSuccess(Value v) {
showProgressBar();
doLotsOfWork(v);
hideProgressBar();
}
will be a no-op. Browsers typically wait for event handlers to finish executing before re-rending the DOM. If the doLotsOfWork() method takes a noticeable amount of time to execute (e.g. >100ms) the user will notice the browser hiccup due to the single-threaded nature of JavaScript execution.
Instead, consider using an incrementally-scheduled command to break the work up. It would look roughly like:
void onSuccess(Value v) {
showProgressBar();
Scheduler.get().scheduleIncremental(new RepeatingCommand() {
int count = 0;
int size = v.getElements().size();
public boolean execute() {
if (count == size) {
hideProgressBar();
return false;
}
processOneElement(v.getElements().get(count++));
setProgressBar((double) count / size);
return true;
}
});
}
By breaking the work across multiple pumps of the browser's event loop, you avoid the situation where the webapp becomes non-responsive if there's a non-trivial amount of work to do.
Well, it is a generic non-functional requirement, I have done some research on this item, I have implemented a solution that Thomas Broyer has suggested on gwt group.. This solution has distinct advantage over other suggested solutions, You dont have to change your callback classes, what you have to do is just add a line of code after creation of async gwt-rpc service...
IGwtPersistenceEngineRPCAsync persistenceEngine = GWT.create(IGwtPersistenceEngineRPC.class);
((ServiceDefTarget) persistenceEngine).setRpcRequestBuilder(new ProgressRequestBuilder());
import com.allen_sauer.gwt.log.client.Log;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.Response;
import com.google.gwt.user.client.rpc.RpcRequestBuilder;
public class ProgressRequestBuilder extends RpcRequestBuilder {
private class RequestCallbackWrapper implements RequestCallback {
private RequestCallback callback;
RequestCallbackWrapper(RequestCallback aCallback) {
this.callback = aCallback;
}
#Override
public void onResponseReceived(Request request, Response response) {
Log.debug("onResposenReceived is called");
// put the code to hide your progress bar
callback.onResponseReceived(request, response);
}
#Override
public void onError(Request request, Throwable exception) {
Log.error("onError is called",new Exception(exception));
// put the code to hide your progress bar
callback.onError(request, exception);
}
}
#Override
protected RequestBuilder doCreate(String serviceEntryPoint) {
RequestBuilder rb = super.doCreate(serviceEntryPoint);
// put the code to show your progress bar
return rb;
}
#Override
protected void doFinish(RequestBuilder rb) {
super.doFinish(rb);
rb.setCallback(new RequestCallbackWrapper(rb.getCallback()));
}
}
You cant do that. The rpc onSuccess() method runs asynchronously (in other words, depends on the server when it completes, the app doesnt wait for it). You could fire code immediately after the rpc call which may/ may not complete before the onSuccess for RPC calls.
Can you explain with an eg why exactly do u want to do that? Chances are you might have to redesign the app due to this async behavior, but cant say till you provide a use case. Preferably any Async functionality should be forgotten after the rpc call, and actioned upon only in the onSuccess.