Async web service call in custom list adapter - xamarin.android

I have a problem when calling web service asynchronously in Monodroid. The call seems to work correctly, but the application crashes everytime when I process the response. Program behaves differently when I run it in emulator and when I run it on my phone (Samsung Galaxy S w 2.2.1 FROYO.XWJS8). I am thinking of creting the Threads by myself, but don't know if it solves the problem. The same code works fine when used in Windows Phone 7 application.
The code for Async method call is (note: in reality ShowMessage calls write to Android.Util.Log.Debug)
private void callws(string _input)
{
MessageBox.GetInstance().ShowMessage("Search async started, input: " + _input);
m_waitingrequest = new RequestStatus() { Waiting = true, NewestInput = _input, OriginalInput = _input };
connectormobile.UserInformation ui = new connectormobile.UserInformation()
{ UserName = m_appsettings.GetValue<string>(AppSettings.WS_USERNAME_NAME), Password = m_appsettings.GetValue<string>(AppSettings.WS_PASSWORD_NAME) };
MessageBox.GetInstance().ShowMessage("Username: " + ui.UserName + " Password: " + ui.Password);
m_client.SearchAsync(ui, _input);
MessageBox.GetInstance().ShowMessage("After search async call, input: " + _input);
}
Search Async result function starts with:
void m_client_SearchCompleted(object sender, connectormobile.SearchCompletedEventArgs e)
{
MessageBox.GetInstance().ShowMessage("Search async completed");
SearchCache.CacheElement element = new SearchCache.CacheElement();
element.SearchCriteria = m_waitingrequest.OriginalInput;
element.PartialResponse = e.Result.PartialResponse;
if (e.Result.CompanyNameInfoArray == null)
element.Rows = new List<connectormobile.CompanyNameInfo>();
else
element.Rows = e.Result.CompanyNameInfoArray.ToList();
MessageBox.GetInstance().ShowMessage("Search async returned, partial response: " + e.Result.PartialResponse
+ " row count: " + element.Rows.Count + " return value: " + e.Result.ReturnValue.ErrorDescriptionFi);
}
This is where the program behaves differently. In emulator the code never reaches the first line of SearchCompleted. But in my phone the SearchCompleted function seems goes through (at least all my debug lines are in trace), but after that the user interface freezes. (and after minute it says process not responding)

You are likely trying to modify the UI from the background thread instead of the UI thread. Use RunOnUIThread () to do your UI logic on the correct thread:
http://mono-android.net/Documentation/Guides/Writing_Responsive_Applications

Related

Twilio Functions Error 20429 - Too many requests multiple sms messages

I am using Twilio functions and Programable SMS to send SMS Messages to a list of numbers form my iOS App. There are just over 100 mobile numbers (113 on the time of this error) in the list. Most of these messages send but then the function says that it timed out after 502ms.
I am using the example code from Twilio to send to group messages (that I have copied below) and making a URLSession request from my iOS app.
Is there a way that I can fix this issue so that I can send to this fairly large list of phone numbers or make the function run for longer?
Thank you very much for your help.
Tom
Request:
let messagesPhoneNumberString = [+447987654321abc,+447123789456def,+447123456789ghi]
"https://myfunction.twil.io/send-messages?phoneAndID=\(messagesPhoneNumberString)&globalID=\(current globalID)"
My Twilio Function Code:
exports.handler = function(context, event, callback) {
let phoneAndIDString = event['phoneAndID'];
let globalID String = event['globalID'];
let numbersArray = phoneAndIDString.split(",");
Promise.all(
numbersArray(number => {
let phoneNumberSplit = "+" + number.slice(1, 13);
let idSplit = number.slice(13);
console.log('Send to number: ' + phoneNumberSplit + ' - with ID: ' + idSplit);
return context.getTwilioClient().messages.create({
to: phoneNumberSplit,
from: 'Example',
body: 'Hello World: ' + idSplit
});
})
)
.then(messages => {
console.log('Messages sent!');
callback(null, response);
})
.catch(err => console.error(err));
};
Twilio developer evangelist here.
Twilio Functions has a timeout of 5 seconds, so it is likely not the best idea to use a Twilio Function to send that many messages in one go.
You have some options though.
If you are sending all those numbers the same message then you could use the Twilio Notify passthrough API. Check out the details in this blog post about sending mass messages with Node.js.
Otherwise, if you have to send different messages then you could split up the numbers into batches and use the same function multiple times.
Finally, you could use a different platform to send the messages that doesn't have a 5 second limit.
In addition to the options provided in Phil's answer you could use recursion.
You could trigger the process from your app and pass all numbers in the initial function call just like you do now.
Then, the idea is to send just one message per function call and let the Twilio function call itself after it receives the response from .create(). This means no concurent calls to send messages, messages are sent one after another though the order in which they are received is not necessary the order in which the numbers are passed in the query string.
You'll need to add axios in the function dependencies configuration (https://www.twilio.com/console/runtime/functions/configure).
Axios is used to make the HTTP request to the function from within the function.
Each function run, tests for the stop condition which happens when the phone numbers query string length is zero. Then, uses .shift() to remove the first element from the numbers array to work with it. The remaining array is passed to the next function call.
This is the code I've tried, and it worked for me, but you'll have to change (the 11 length on .slice() method) for +44 because I've tested with US numbers +1 which are shorter in length.
exports.handler = function(context, event, callback) {
const axios = require("axios");
let phoneAndIDString = event["phoneAndID"].trim();
console.log(phoneAndIDString);
let globalIDString = event["globalID"].trim();
// stop condition for recursive call
if (phoneAndIDString.length === 0) {
return callback(null, true);
}
let numbersArray = phoneAndIDString.split(",");
console.log(numbersArray);
// take the first item of array
let number = numbersArray.shift();
console.log(number);
// the remaining array will be passed to the next function call
phoneAndIDString = numbersArray.join();
console.log(phoneAndIDString);
let phoneNumberSplit = "+" + number.slice(0, 11);
let idSplit = number.slice(11);
console.log("Send to number: " + phoneNumberSplit + " - with ID: " + idSplit);
context
.getTwilioClient()
.messages.create({
to: phoneNumberSplit,
from: "+17775553333",
body: "Hello World: " + idSplit
})
.then(msg => {
console.log("Message sent: " + msg.sid);
axios
.get(
"https://foo-bar-1234.twil.io/send-messages?globalID=baz&phoneAndID=" +
phoneAndIDString
)
.then(function(response) {
// handle success
console.log(response.status);
return callback(null, true);
})
.catch(function(err) {
// handle error
console.error(err);
});
})
.catch(function(err) {
console.error(err);
});
};
Try to go step by step with it while testing, console log things and then return early with return callback(null, true) as you go from top to bottom so you make sure you don't go in a loop.

In a Service Worker install listener, why does fetch return TypeError: Failed to fetch?

Using the sw-precache utility, I created a service worker that works if I refresh the page. But initially, the fetch call returns TypeError: Failed to fetch on a file which seems to cancel the rest. Refresh gets a few more files, refresh a few more times until all are fetched and then the service worker works fine. Each url loads fine, every time, even with the cache buster. All the calls are to https://localhost:9001 and are straight get calls. There are 17 total files.
Here is a code snippet:
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(cacheName).then(function(cache) {
return setOfCachedUrls(cache).then(function(cachedUrls) {
return Promise.all(
Array.from(urlsToCacheKeys.values()).map(function(cacheKey) {
// If we don't have a key matching url in the cache already, add it.
if (!cachedUrls.has(cacheKey)) {
var request = new Request(cacheKey, {credentials: 'same-origin'});
return fetch(request).then(function(response) {
// Bail out of installation unless we get back a 200 OK for
// every request.
if (!response.ok) {
throw new Error('Request for ' + cacheKey + ' returned a ' +
'response with status ' + response.status);
}
return cleanResponse(response).then(function(responseToCache) {
return cache.put(cacheKey, responseToCache);
});
}).catch(function(e) {
throw new Error('fetch error: ' + e);
});
}
})
);
});
}).then(function() {
})
);
});
I tried adding keepalive:true,headers:{"Access-Control-Allow-Origin": "*"} to the Request but get the same result.
It seems the requests fail very soon, and I have seen the requests take a little more than a second to respond. Perhaps there is a way to set a timeout?
In the chrome dev tools network tab, it shows the failed attempts in red with a (canceled) status and the little service worker icon to the left.
It seems to work fine in FireFox. Chrome is having the trouble.

Timeout Notification for Asynchronous Request

I am sending SPARQL queries as asynchronous requests to a SPARQL endpoint, currently DBpedia using the dotNetRDF library. While simpler queries usually work, more complex queries sometimes result in timeouts.
I am looking for a way to handle the timeouts by capturing some event when they occur.
I am sending my queries by using one of the asynchronous QueryWithResultSet overloads of the SparqlRemoteEndpoint class.
As described for SparqlResultsCallback, the state object will be replaced with an AsyncError instance if the asynchronous request failed. This does indicate that there was a timeout, however it seems that it only does so 10 minutes after the request was sent. When my timeout is, for example, 30 seconds, I would like to know 30 seconds later whether the request was successful. (35 seconds are ok, too, but you get the idea.)
Here is a sample application that sends two requests, the first of which is very simple and likely to succeed within the timeout (here set to 120 seconds), while the second one is rather complex and may easily fail on DBpedia:
using System;
using System.Collections.Concurrent;
using VDS.RDF;
using VDS.RDF.Query;
public class TestTimeout
{
private static string FormatResults(SparqlResultSet results, object state)
{
var result = new System.Text.StringBuilder();
result.AppendLine(DateTime.Now.ToLongTimeString());
var asyncError = state as AsyncError;
if (asyncError != null) {
result.AppendLine(asyncError.State.ToString());
result.AppendLine(asyncError.Error.ToString());
} else {
result.AppendLine(state.ToString());
}
if (results == null) {
result.AppendLine("results == null");
} else {
result.AppendLine("results.Count == " + results.Count.ToString());
}
return result.ToString();
}
public static void Main(string[] args)
{
Console.WriteLine("Launched ...");
Console.WriteLine(DateTime.Now.ToLongTimeString());
var output = new BlockingCollection<string>();
var ep = new SparqlRemoteEndpoint(new Uri("http://dbpedia.org/sparql"));
ep.Timeout = 120;
Console.WriteLine("Server == " + ep.Uri.AbsoluteUri);
Console.WriteLine("HTTP Method == " + ep.HttpMode);
Console.WriteLine("Timeout == " + ep.Timeout.ToString());
string query = "SELECT DISTINCT ?a\n"
+ "WHERE {\n"
+ " ?a <http://www.w3.org/2000/01/rdf-schema#label> ?b.\n"
+ "}\n"
+ "LIMIT 10\n";
ep.QueryWithResultSet(query,
(results, state) => {
output.Add(FormatResults(results, state));
},
"Query 1");
query = "SELECT DISTINCT ?v5 ?v8\n"
+ "WHERE {\n"
+ " {\n"
+ " SELECT DISTINCT ?v5\n"
+ " WHERE {\n"
+ " ?v6 ?v5 ?v7.\n"
+ " FILTER(regex(str(?v5), \"[/#]c[^/#]*$\", \"i\")).\n"
+ " }\n"
+ " OFFSET 0\n"
+ " LIMIT 20\n"
+ " }.\n"
+ " OPTIONAL {\n"
+ " ?v5 <http://www.w3.org/2000/01/rdf-schema#label> ?v8.\n"
+ " FILTER(lang(?v8) = \"en\").\n"
+ " }.\n"
+ "}\n"
+ "ORDER BY str(?v5)\n";
ep.QueryWithResultSet(query,
(results, state) => {
output.Add(FormatResults(results, state));
},
"Query 2");
Console.WriteLine("Queries sent.");
Console.WriteLine(DateTime.Now.ToLongTimeString());
Console.WriteLine();
string result = output.Take();
Console.WriteLine(result);
result = output.Take();
Console.WriteLine(result);
Console.ReadLine();
}
}
When I run this, I reproducibly get an output like the following:
13:13:23
Server == http://dbpedia.org/sparql
HTTP Method == GET
Timeout == 120
Queries sent.
13:13:25
13:13:25
Query 1
results.Count == 10
13:23:25
Query 2
VDS.RDF.Query.RdfQueryException: A HTTP error occurred while making an asynchron
ous query, see inner exception for details ---> System.Net.WebException: Der Rem
oteserver hat einen Fehler zurückgegeben: (504) Gatewaytimeout.
bei System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
bei VDS.RDF.Query.SparqlRemoteEndpoint.<>c__DisplayClass13.<QueryWithResultSe
t>b__11(IAsyncResult innerResult)
--- Ende der internen Ausnahmestapelüberwachung ---
results == null
Obviously, the exact times will be different, but the crucial point is that the error message based on the second query is received approximately 10 minutes after the request was sent, nowhere near the 2 minutes set for the timeout.
Am I using dotNetRDF incorrectly here, or is it intentional that I have to run an additional timer to measure the timeout myself and react on my own unless any response has been received meanwhile?
No you are not using dotNetRDF incorrectly rather there appears to be a bug that the timeouts set on an endpoint don't get honoured when running queries asynchronously. This has been filed as CORE-393
By the way even with this bug fixed you won't necessarily get a hard timeout at the set timeout. Essentially the value you set for the Timeout property of the SparqlRemoteEndpoint instance that value is used to set the Timeout property of the .Net HttpWebRequest. The documentation for HttpWebRequest.Timeout states the following:
Gets or sets the time-out value in milliseconds for the GetResponse
and GetRequestStream methods.
So you could wait up to the time-out to make the connection to POST the query and then up to the time-out again to start receiving a response. Once you start receiving a response the timeout becomes irrelevant and is not respected by the code that processes the response.
Therefore if you want a hard timeout you are better off implementing it yourself, longer term this may be something we can add to dotNetRDF but this is more complex to implement that simply fixing the bug about the timeout not getting honoured for the HTTP request.

iOS / Phonegap : using FileTransfer response

first, sorry if my english is bad.
Then, here is my issue:
I try to make an app for iOS with PhoneGap 2.8.1 . Evrything is going well on Android, now I just want to move my code on Xcode to compile on iPad or iPhone.
The probleme I have is with FileTransfer, when I upload an image. The transfer itself has no problem, as it finishes with a response code 200, so it's a success.
Then, my serve is supposed to return back an XML file, handled by the javascript code. The server works fine, because I have absolutly no problem with Android devices.
So, I made a lot of tests, and it appears that the app has a problem with the success callback or the FileTransfer.upload(). When I just put a simple console.log('success') in this callback function, it's fine. But when I try to use the FileUploadResult object, nothing happens.
And the weirdest thing is, that when I press the main button of the iPad or iPhone, in order to close my app, I see all my logs displayed in the debug window, such as console.log("Code = " + r.responseCode);, like in the PhoneGap example. And here, I can finally see that I actually receive the server response, but it's like something blocks it until I close the app.
Here is that part of the code :
function onPhotoDataSuccess(imageURI) {
console.log("---> Image: "+imageURI);
// File Transfer
var options = new FileUploadOptions();
options.fileKey="file";
options.chunkedMode = false;
options.fileName=imageURI.substr(imageURI.lastIndexOf('/')+1);
options.mimeType="image/jpeg";
var ft = new FileTransfer();
ft.upload(imageURI, encodeURI(window.localStorage.getItem("wsURL")), win, fail, options);
// Transfer succeeded
function win(r) {
console.log("Code = " + r.responseCode);
console.log("Response = " + r.response);
console.log("Sent = " + r.bytesSent);
// Handle the XML response
}
else {
alert("No response. Please retry");
}
}
// Transfer failed
function fail(error) {
alert("An error has occurred: Code = " + error.code);
console.log("upload error source " + error.source);
console.log("upload error target " + error.target);
}
}
Thanks for your help

Blackberry: Make a iterative HTTP GET petition using Comms API

I want to store position coords (latitude, longitude) in a table in my MySQL DB querying a url in a way similar to this one: http://locationstore.com/postlocation.php?latitude=var1&longitude=var2 every ten seconds. PHP script works like a charm. Getting the coords in the device ain't no problem either. But making the request to the server is being a hard one. My code goes like this:
public class LocationHTTPSender extends Thread {
for (;;) {
try {
//fetch latest coordinates
coords = this.coords();
//reset url
this.url="http://locationstore.com/postlocation.php";
// create uri
uri = URI.create(this.url);
FireAndForgetDestination ffd = null;
ffd = (FireAndForgetDestination) DestinationFactory.getSenderDestination
("MyContext", uri);
if(ffd == null)
{
ffd = DestinationFactory.createFireAndForgetDestination
(new Context("MyContext"), uri);
}
ByteMessage myMsg = ffd.createByteMessage();
myMsg.setStringPayload("doesnt matter");
((HttpMessage) myMsg).setMethod(HttpMessage.POST);
((HttpMessage) myMsg).setQueryParam("latitude", coords[0]);
((HttpMessage) myMsg).setQueryParam("longitude", coords[1]);
((HttpMessage) myMsg).setQueryParam("user", "1");
int i = ffd.sendNoResponse(myMsg);
ffd.destroy();
System.out.println("Lets sleep for a while..");
Thread.sleep(10000);
System.out.println("woke up");
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("Exception message: " + e.toString());
e.printStackTrace();
}
}
I haven't run this code to test it, but I would be suspicious of this call:
ffd.destroy();
According to the API docs:
Closes the destination. This method cancels all outstanding messages,
discards all responses to those messages (if any), suspends delivery
of all incoming messages, and blocks any future receipt of messages
for this Destination. This method also destroys any persistable
outbound and inbound queues. If Destination uses the Push API, this
method will unregister associated push subscriptions. This method
should be called only during the removal of an application.
So, if you're seeing the first request succeed (at least sometimes), and subsequent requests fail, I would try removing that call to destroy().
See the BlackBerry docs example for this here
Ok so I finally got it running cheerfully. The problem was with the transport selection; even though this example delivered WAP2 (among others) as an available transport in my device, running the network diagnostics tool showed only BIS as available. It also gave me the connection parameters that I needed to append at the end of the URL (;deviceside=false;ConnectionUID=GPMDSEU01;ConnectionType=mds-public). The code ended up like this:
for (;;) {
try {
coords.refreshCoordinates();
this.defaultUrl();
this.setUrl(stringFuncs.replaceAll(this.getUrl(), "%latitude%", coords.getLatitude() + ""));
this.setUrl(stringFuncs.replaceAll(this.getUrl(), "%longitude%", coords.getLongitude() + ""));
cd = cf.getConnection(this.getUrl());
if (cd != null) {
try {
HttpConnection hc = (HttpConnection)cd.getConnection();
final int i = hc.getResponseCode();
hc.close();
} catch (Exception e) {
}
}
//dormir
Thread.sleep(15000);
} catch (Exception e) {
} finally {
//cerrar conexiones
//poner objetos a null
}
Thanks for your help #Nate, it's been very much appreciated.

Resources