I'm using Titanium SDK 3.4.0 GA, developing an Android app that load remote images from my web server to an ImageView.
The problem comes when the device lost connectivity during the load of that images, so, what I need is a way to catch that error (timeout, 404...) and set an "imageNotAvailable".
I'm using Network Link Conditioner for MacOSX to reproduce that scenario, with low latency, lost of packets...
To prove this I use the following code in my test.js (Alloy Controller) and a simple view with an ImageView with id='imageView' in my test.xml.
Sometimes, throws an exception:
TiDownloadManager: (pool-4-thread-1) [45929,118581] Exception downloading http://...
but not always (remote connection timeout seems infinite), anyway with this exception and without this I can't catch this (probably due to the asynchronous request) nor fires the ERROR event.
function imageNotAvailable(e)
{
Ti.API.info('Error loading image:'+JSON.stringify(e));
$.imageView.image = "/imageNotAvailable.png";
}
function onLoad(e)
{
Ti.API.info('Image Loaded:'+JSON.stringify(e));
}
function setImageAndroid(image)
{
try{
$.imageView.image = 'http://....';
}catch(e){
$.imageView.fireEvent("error");
}
$.imageView.addEventListener("error", imageNotAvailable);
$.imageView.addEventListener("load", onLoad);
}
Excuse my bad English! Thanks!
Have you tried adding your event listeners before setting the imageView's image property?
i can suggest a way around using http request
create a function in some library class which accepts the url that you are supposed to hit
Connection.getImage = function(link){
var xhr = Titanium.Network.createHTTPClient({
onload : function(e) {
var responseResult = this.responseText;
callback(responseResult);
},
// function called when an error occurs, including a timeout
onerror : function(e) {
callback("fail");
// Ti.API.info('IN ERROR ' + e.error);
},
timeout : 5000
});
xhr.open("GET", link);
xhr.send();
};
// ps you will receive a blob in response which you can attach to imageView.blob property , an it would suggest using a default image which will act as placeholder until you get the success response.
Related
maybe you can give me a hand, I've been looking for all information, in order to solve this problem of mine, but nothing, I can't use the player with cordova ...
in practice I can't load mp3 files, whether they are both locally and remotely, I always get this error: "Error: buffer is either not set or not loaded", the files in the path are there.
I tried using Tone's oscilloscope to see if I was having trouble loading Tone, but this works fine.
Could it depend on some authorization, particular that I might be missing ?.
For example using cordova media plugin I can reproduce the audio, but I need to use Tonejs.
Do you have any ideas, what this might depend on. or what could I try to do? ...
even this simple example, after the device ready does not go:
const player = new Tone.Player("https://tonejs.github.io/audio/berklee/gong_1.mp3") .toDestination();
Tone.loaded().Then(() => {
player.start ();
});
You who have already worked with Tone and Cordova, give me hope that it can be used in some way, let me know if you have any ideas thanks in advance!
--- UPDATE:
Currently when the app starts, I behave like this (I state that it is a porting of the code developed for a website and that everything works correctly loading it, etc.):
let myLoader_File = function functionOne(test) {
var androidFixPath = cordova.file.applicationDirectory
console.log("Entered function");
return new Promise((resolve, reject) => {
let CaricatorePlayers = new Tone.Players({
Beep: androidFixPath + "sample/Beep.mp3",
Clave: androidFixPath + "sample/Clave.mp3",
}).toDestination();
resolve(
CaricatorePlayers
//"ok tutti i file sono stati caricati!"
);
reject("si รจ verificato un errore!");
});
};
function onDeviceReady() {
$('#fade-wrapper-flash').fadeOut(1000);
$('#fade-wrapper').fadeIn();
//attach a click listener to a start button
document.querySelector('#fade-wrapper').addEventListener('click', async () => {
await Tone.start();
console.log('audio is ready');
myLoader_File().then((res) => {
console.log(`The function recieved with value ${res}`)
MultiPlayers = res;
console.log(MultiPlayers)
try {
// Play
MultiPlayers.player("Beep").start();
$('#fade-wrapper').fadeOut();
preLoad();
} catch (error) {
console.log(error);
console.log("IN ERRORE RICARICO");
}
}).catch((error) => {
console.log(`Handling error as we received ${error}`);
console.log("IN ERRORE RICARICO");
$('#fade-wrapper').fadeIn();
});
});
}
I posted an answer, here, which also solves this problem.
I don't know if the solution is the only possible way, or the best,
in order to access the folders locally, I made these changes to the call. Using an XMLHttpRequest object
which can be used, to request data from a web server, I got a Blob object, which I then passed to the Tone player.
What I'm trying to achieve is basically something like android web view's shouldOverrideUrlLoading. I'm loading a specific URL into the web view which in turn have a series of redirects. The goal is to intercept the last URL and handle it by the application instead of the WebView component. It seems that something similar is available for the ios platform (onShouldStartLoadWithRequest) but didn't get to the android yet (https://github.com/facebook/react-native/pull/6478).
The workaround I've tried is to use onNavigationStateChange, parsing the URL and stopping the web view loading if needed:
onNavigationStateChange = (navState) => {
const url = new URL(navState.url);
const lastSegment = url.pathname.substr(url.pathname.lastIndexOf('/') + 1);
// Handle the get token ourselvs
if (lastSegment === GETTOKEN) {
this.refs[WEBVIEW_REF].stopLoading();
this.getToken()
}
this.setState({
url: navState.url,
backButtonEnabled: navState.canGoBack
});
}
The problem is that the stopLoading function is not really working in my case. I see that while executing the async function getToken() the browser continues the loading of the last URL.
Any suggestion would be appreciated.
I'm making an ajax call that repeatedly calls an api for json data. I've never had it fail with other browsers, but something weird is happening to the response within the Android Browser. I put a console log using weinre that catches the returned data. Can anyone make sense of it and how to handle it?
Screenshot:
Everything is running along smoothly until the last one causes an error like this: Uncaught TypeError: Cannot read property 'Requests' of undefined
Why is it not returning like the previous json return from the ajax calls?
I couldn't find anyway to handle this other than wrap the whole result in a try catch. If it does catch something then it just tries again to get the batch and has thus far always been successful on the second attempt.
try {
//ajax returned result
} catch (error) {
console.error(error);
window.setTimeout(function() {
getBatch();
}, 2000);
}
While creating an Android app in Appcelerator's Titanium that involves both webView and background calls, I ran into a problem / bug where the cookies were getting corrupted on multiple createHTTPClient calls.
Cookies were originally obtained from the webView:
var webview = Ti.UI.createWebView();
webview.url = 'http://www.example.com';
window.add(webview);
webview.addEventListener('load', function(e) {
cookies = e.source.evalJS("document.cookie");
Titanium.App.Properties.setString('cookies',cookies);
}
window.open({modal:true});
and then later used with a background call:
var loader = Titanium.Network.createHTTPClient();
loader.open("GET",base_url + url);
loader.onload = function() {
// process response
}
loader.setRequestHeader('Cookie',Titanium.App.Properties.getString("cookies"));
loader.send();
The first time the above createHTTPClient chunk of code was called, everything worked, but subsequent runs of the above code would send corrupted cookies. In Google App Engine (gae), printing out the request headers would look like this (broken):
logging.info('Request:\n%s' % self.request)
broken response (only the cookie portion of the request header is shown)
Cookie: auth="eyJfdXNlciI6WzYsMSwiVmRoZEtnYWZRMnNxazFjaVM0U1lKdCIsMTM1NzIyMzcwOSwxMzU3MjIzNzA5XX0\075|1357223709|4f622167f477a8c82cab196af4b0029af1a966d7", auth=eyJfdXNlciI6WzYsMSwiVmRoZEtnYWZRMnNxazFjaVM0U1lKdCIsMTM1NzIyMzcwOSwxMzU3MjIzNzA5XX0\075|1357225569|7a469fab7a38a437649c25620729e07c4607f617
Cookie2: $Version=1
working response
Cookie: auth="eyJfdXNlciI6WzYsMSwiVmRoZEtnYWZRMnNxazFjaVM0U1lKdCIsMTM1NzIyMzcwOSwxMzU3MjIzNzA5XX0\075|1357223709|4f622167f477a8c82cab196af4b0029af1a966d7"
...
I suspect the issue has something to do with unicode characters or something inside createHTTPClient. Two auth= statements are shown in the corrupted cookie.
In summary, when the app first launches, the background Titanium.Network.createHTTPClient call works, and any calls after that appear to send corrupted cookies.
The HTTPClient documentation says "object is intended to be used for a single request," so I assumed everything would reset after multiple calls. But something was different after the first call.
Adding loader.clearCookies(base_url); to the code before setting the cookies seems to fix the issue.
var loader = Titanium.Network.createHTTPClient();
loader.open("GET",base_url + url);
loader.onload = function() {
// process response
}
loader.clearCookies(base_url); // THE FIX.
loader.setRequestHeader('Cookie',Titanium.App.Properties.getString("cookies"));
loader.send();
I want user to wait for specified time(4seconds) to get connected to server. If it cannot connect within the specified time period, application should get closed.
Here is what I have coded:
var downloadDataReq = Titanium.Network.createHTTPClient({timeout :4000});
downloadDataReq.onload = function() { //some code }
downloadDataReq.onerror = function(event) { //some code }
var urlToDownloadData = 'http://www.google.com';
downloadDataReq.open("POST", urlToDownloadData);
downloadDataReq.send();
The Problem is that app waits for fix time (timeout parameter does not effect at all).
P.S.: making an app for android using Titanium.
Try to use method like this:
downloadDataReq.setTimeout(4000);
For me, timeout on HTTP requests aren't working as it should. I had very weird issues, such as:
If I put 1000ms timeout, it'll be called on 2 or 3 seconds.
If I put 2000ms timeout or above, it'll never be called.
I'm using Android ICS and JB, and on both I get the issues above. Seems that timeout parameter is buggy.
As a workaround, I'm doing checks inside onload (example: if I'm downloading a file, I compare the checksum of local file, with the checksum of the same file on the server), and I'm simulating timeouts with JavaScript's setTimeout. It's working to an extend.
The code below demonstrate how to simulate a request timeout, with JS's setTimeout command:
var downloadDataReq = Titanium.Network.createHTTPClient();
downloadDataReq.onload = function() {
clearTimeout(timeout);
alert('loaded');
}
downloadDataReq.onerror = function(e) {
clearTimeout(timeout);
alert('error: ' + e.error);
}
var urlToDownloadData = 'http://10.1.1.183/maquina_local/arquivos/FirefoxPortable_12.0_PortugueseBR.paf.exe';
downloadDataReq.open("GET", urlToDownloadData);
var timeout = setTimeout(function(){
downloadDataReq.onload = function(){
downloadDataReq.onerror({'error': 'timeout'});
};
downloadDataReq.abort();
}, 4000);
downloadDataReq.send();
On timeout, I'm changing onload event to onerror one, because if you try aborting a running request, it'll trigger 'onload' event, not 'onerror'. If you don't do it, this issue can give you corrupted files (ex: a 20mb file that, when request is aborted, file will be incomplete, with a size smaller than 20mb).
I'm still testing this solution, but at least for now, it solved a few bugs for me.
Try this.
Ti.App.timeOut = 99000; //declare in app.js
then use anyWhere in your project.But make Sure every time when you create a httpClient.
dont recreate or redefine in Code or through out the page.
this works fine for me.
//HAVE A LOOK OVER THE USE OF THIS
var xhr = Titanium.Network.createHTTPClient({timeout:Ti.App.timeOut});