AIR UrlMonitor doesn't dispatch StatusEvent.STATUS - actionscript-3

As the title says, I've got a air.net.URLMonitor that sometimes doesn't dispatch a StatusEvent in case the specified site cannot be reached.
Let me show you my code:
_serverURL = "http://192.168.0.20:8080/"
_monitor = new URLMonitor(new URLRequest(_serverURL));
_monitor.pollInterval = 1000;
_monitor.addEventListener(StatusEvent.STATUS, serverStatusResult);
_monitor.start();
And here is my problem, when my iPad (this is a mobile AIR application btw) is in the correct network, so the one where the specified server is available, the StatusEvent is correctly dispatched. When I'm not in that network, nothing happens and I really don't know why.
Shouldn't it dispatch the event anyway?
This isn't an isolated issue, when our production environment server gets updated and isn't online, the same issue appears, however when the iPad is in offline mode and cannot reach the server because of that, the StatusEvent fires.
Is there a reasonable explanation for that, and if so, how can I correctly implement this?
Should I use a standard HTTPService instead and simply listen for ResultEvent and FaultEvent?
As usual, any help would be greatly appreciated!
Cheers.

What do you have in your serverStatusResult function?
Something like:
public function serverStatusResult(e:StatusEvent):void {
if (! monitor.available) {
//connection has dropped so do something
}
}
I also found that setting a poll interval has a very detrimental effect on iPad CPU usage.

The solution is very simple:
StatusEvent has a parameter called code.
Variable code is a string and it can be :
"Service.available"
"Service.unavailable"
Ok, now let's see an implementation:
public function serverStatusResult(e:StatusEvent):void {
switch(e.code)
{
case "Service.available":online();break;
case "Service.unavailable":offline();break;
}
}
Hope it helps :)

Related

App Widget getting hijacked by Google Sound Search?

So I'm seeing some bizarre behavior in an appwidget that I wrote.
The widget itself is quite simple - it reads a few values from persistent storage and then displays them as text. Nothing fancy in the layout - just a FrameLayout root element with some Linear Layout and TextView children.
The widget has a simple configuration activity associated with it.
The bizarre behavior is that the widget will initially show "Problem Loading Widget" after the user closes the configuration activity, and then after a few seconds it shows a "Google Sound Search" button (and clicking on the button actually does launch Google Sound Search). Then, after a few more seconds, it finally shows the expected display.
I am away from my code right now, so I'll have to wait until tonight to post code snippets. However, in the meantime, can anyone provide some insight into how such a thing could happen? Has anyone else ever experienced this? How could another widget "hijack" mine?
Thanks,
-Ron
Here are some screenshots:
There are a couple of issues with your widget and there are answers to all of them (although you didn't post any code so some of my statements are based on assumptions):
"Problem loading widget": this is the default view Android uses before the widget is initialized and the layout updated. Simply add the following line to your widget xml configuration (to show a loading message instead of the problem message):
android:initialLayout="#layout/my_cool_widget_loading_message"
If the widget shows the wrong layout then you probably have an issue in the widget's onReceive method. onReceive is called for all the widgets no matter whether the broadcast is for that specific widget. Android's AppWidgetProvider filters the broadcasts by appwidget Id and dispatches to the other methods (like onUpdate).
See also: https://developer.android.com/reference/android/appwidget/AppWidgetProvider.html#onReceive(android.content.Context, android.content.Intent).
If you override onReceive (which I assume you do), you need to call through to super.onReceive(Context, Intent) to make sure your other methods don't get calls meant for other widgets.
Now for the configuration of the widget. If you follow the Google documentation then it will all work nicely. The only improvement I'd do is what my other answer that you reference suggests (https://stackoverflow.com/a/14991479/534471). This will NOT send out two broadcasts. The setResult()/finish() part does only terminate the config Activity and let Android know whether to actually add the widget or not (depending on whether the result is RESULT_CANCELED or RESULT_OK.
From your own answer I can see why your code wouldn't work. The code is:
Intent intent = new Intent();
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] {mAppWidgetId});
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, intent);
sendBroadcast(intent);
finish();
First of all there's no need to add the appWidgetId twice, use the AppWidgetManager.EXTRA_APPWIDGET_IDS version and you're good. Second you're using the same Intent to return as a result for the Activity. AFAIK it's not documented what happens when you do set an action on that Intent but my experience with Android widgets is that you need to stick exactly to the documentation or you'll end up having strange issues (like the ones you encounter). So please use two different Intents.
Activity result:
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, resultValue);
finish();
Broadcast:
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE, null, this, MyWidget.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] {mAppWidgetId});
sendBroadcast(intent);
ok, so I figured it out. Posting here in case anyone else runs into this. I think that the Android Developer docs are a little misleading here.
The problem was that in my configuration Activity, I had this code at the end:
Intent intent = new Intent();
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] {mAppWidgetId});
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, intent);
sendBroadcast(intent);
finish();
Providing an intent with the extra EXTRA_APPWIDGET_ID is recommended by the documentation provided by google.
However, that same document says that you have to update the widget's view by creating a RemoteView and calling AppWidgetManager.updateAppWidget() like so:
RemoteViews views = new RemoteViews(context.getPackageName(),
R.layout.example_appwidget);
appWidgetManager.updateAppWidget(mAppWidgetId, views);
I didn't like the idea of placing the presentation logic in both the configuration activity and the widget class, so I instead decided to broadcast an intent at the end of the configuration activity to tell the widget to redraw itself. That's why I have setResult() AND sendBroadcast() at the end of the activity. The documentation further states that the onUpdate() callback will not be called when using a configuration activity. So this seemed neccessary. I added the ACTION_APPWIDGET_UPDATE and the EXTRA_APPWIDGET_IDS to the intent so that it would trigger the onUpdate() method. This practice was recommended by this SO answer (albeit without being included in the activity result intent - but I tried separating the two and it had no effect).
Now I'm not certain exactly how the "Google Sound Search" widget got in there, nor do I fully understand the mechanics of how the intents interacted to produce the observed results. However, as soon as I replaced my code above with the code stated in the docs, the widget was updated properly.
Intent resultIntent = new Intent();
resultIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, resultIntent);
finish();
This seems to contradict the documentation's statement that the configuration activity must update the widget's view. Simply providing the configuration activity result as below triggers the onUpdate() method in the widget, thus allowing the widget to redraw itself. I confirmed the behavior on an emulator running API 23 and also on a Samsung device running Samsung's android flavor.

Error -999 when loading multiple webViews

The iOS app I am making can have multiple webViews loading the same url at the same time. Resulting in this error:
Error Domain=NSURLErrorDomain Code=-999 "The operation couldn’t be completed.
(NSURLErrorDomain error -999.)" UserInfo=0x176b7bc0 {NSErrorFailingURLKey=https://example.com,
NSErrorFailingURLStringKey=https://example.com}
I read this happens when a new request is started before the old request has been completed. How do I prevent this from happening? Thanks
I spent weeks worrying about this error. I was getting it randomly while accessing web pages. In my case I put it down to pages being requested too quickly back to back as the web access was driven by a state machine in code and not by a user.
After much searching, in the end I found a few discussions which could not explain why the error was occuring, but it was felt that it was feature of UIWebView rather than something you should worry about. The guidance was to ignore it. I will see if I can find the article and update this answer later if I can find it.
I updated my code as follows, and so far have seen no ill effects at all since adding it. This would suggest it is almost a notification and anything which causes it seems to get corrected inside UIWebView. Hopefully this is the same in your case.
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
VSSLog(#"Entry: error = %#",error);
// Added this based on net advice. Its a bogus error.
if ([error code] == NSURLErrorCancelled) {
return;
}
... Normal error handling code for proper errors.
}
I am not one for out of sight out of mind, but this I believe is one of those cases where it is ok.
Finally if you are using iOS8 only, you could try moving to use the new WKWebView rather than UIWebView.
Use the delegate methods. Determine which view fired the method then fire the next if you're looking to run them sequentially.
- (void) webViewDidFinishLoad:(UIWebView *)webview{
if ( webview == self.wView1 )
{
// stuff
} else if ( webview == self.wView2 ) {
// stuff 2
}
}
UITableViewDelegate Protocol Reference

IMobileServiceSyncTable PullAsync doesn't return

I currently use Azure Mobile Services with Offline Sync and I it has been working fine. However I now have come to a problem I can't seem to debug. On the PullAsync it never returns, never goes to the Web API, it never errors, it just seems to be stuck somewhere and I don't know where.
IMobileServiceSyncTable<ResponseType> responseTypeTable = MobileService.GetSyncTable<ResponseType>();
await responseTypeTable.PullAsync(responseTypeTable.Where(c => c.CompanyId == companyId));
I use identical code elsewhere with a different type and it works well.
The only thing that happens is the Windows Phone emulator UI locks up, I can press buttons on the keyboard but the input or buttons are all frozen.
I get this on the Debug Output
The thread 0xb80 has exited with code 259 (0x103).
After a 5 seconds and that's about it. Breakpoints everywhere, nothing happening.
The method was in a Command (I'm using MVVMLight). When I call the function on the class initialization and just hold the value it works fine. There is obviously some bug that occurs when calling PullAsync on an event, in an async RelayCommand but getting the call out of there solves the issue.
I'll leave it at that unless anyone comes back with why it is actually happening. This is just a workaround at the moment.

Actionscript services stop functioning

I have built a complex AIR application which has been successfully running for quite some time of many PCs. Unfortunately, I have a plaguing problem with internet connectivity and I was wondering if anyone had encountered this issue before.
Every once in a while, the program will completely stop talking to the internet (all services start faulting). I wrote special code in my program to monitor the situation in which I use two different services to contact the same server.
The first service:
var req:URLRequest = new URLRequest("myURL.com");
this.urlMonitor = new URLMonitor(req, [200, 304]); // Acceptable status codes
this.urlMonitor.pollInterval = 60 * 1000; // Every minute
this.urlMonitor.addEventListener(StatusEvent.STATUS, onStatusChange);
this.urlMonitor.start();
private function onStatusChange(e:StatusEvent):void
{
if (this.urlMonitor.available)
{
pollStatusOnline = true;
Online = true;
}
else
{
pollStatusOnline = false;
Online = false;
}
}
The secondary method is a normal HTTP Service call:
checkInService = new HTTPService();
checkInService.method = "POST";
checkInService.addEventListener(ResultEvent.RESULT,sendResult);
checkInService.addEventListener(FaultEvent.FAULT, faultResult);
checkInService.addEventListener(InvokeEvent.INVOKE, invokeAttempt);
checkInService.url = "myURL.com";
checkInService.concurrency = Concurrency.LAST;
checkInService.send(params);
These two services point to the same location and work 98% of the time. Sometimes, after a few hours, I have noticed that both services no longer can connect to the website. The HTTP Service returns a StatusCode 0. I am able to open command prompt and ping the server directly with no problem from the PC which is failing. The services will not function again until the program is restarted.
I have been working on this issue for many months now without resolution. If anyone is able to even point me in a somewhat possible, maybe this might be the problem, possibly, direction, I would really appreciate it.
Thank you in advance.
Check the code value of the StatusEvent you receive from the URLMonitor - this might give more info than the HTTPService (you might also want to try passing a null value to URLMonitor constructor, to widen the acceptable status codes).
If you have access to the server(s?) in question, check their logs. Could the server config have changed such that it might now consider such frequent requests as flooding?
You should also be able to use an HTTP debugger like Fiddler or Charles on the client machine to see more information about the requests going out of your application.

AS3 Shared Object slows swf down and makes webpage unressponsive

I have a swf that I would like to cookie to control the frame the user see's depending on whether it is a first time site visit or returned visit. My code is below - it works, it doesn't bring back any out messages however when I load the swf into my site that uses this technique the page becomes extremely slow and unresponsive - can anyone help out with any reasons why this may occur?
var my_so:SharedObject = SharedObject.getLocal("visited", "/");
if (my_so.data.newVisitor != undefined) {
//object exists: return user
this.gotoAndPlay(2);
} else {
//object doesn't exist: new user
my_so.data.newVisitor = "no";
this.gotoAndStop(1);
}
Many thanks in advance
Rachel
SharedObjects in general are extremely slow in Flash. That being said, there is no reason why it should be slowing down your entire site after it has been used.
When writing to a SO, you have to use flush() to tell Flash to actually write the data.
my_so.data.newVisitor = "no";
// Write the data to disk
my_so.flush();
Another thing to try would be to actively close the connection after you are done with it. So after the else statement you would add:
// Close the connection
my_so.close();
// Clear pointer for GC
my_so = null;
If that doesn't work, the next steps would be to put trace statements in and around the SOs and make sure they aren't being accessed while the program is running.