In WP7, data is not saved immediately after writing to IsolatedStorage - windows-phone-7

I encountered this problem while polishing my WP7 application.
Though I follow Microsoft's guidelines to store game state when it's being deactivated, I'd also like to save some data in runtime.
The reason for this is that when the battery is removed from device, no deactivation / closing callbacks are triggered.
The problem with this comes when the user walks through the game and accidentally removes the battery from her device - all game progress is lost.
That's why I do save game state at some intermediate checkpoints, but I have noticed that data is not stored immediately. This is my "save" function:
public void SaveAppModelToIsolatedStorage()
{
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
using (var stream = new IsolatedStorageFileStream(APPMODEL_DATAFILE,
FileMode.Create,
FileAccess.Write,
store))
{
var serializer = new XmlSerializer(typeof(AppModel));
try
{
serializer.Serialize(stream, AppModel);
}
catch (Exception ex)
{
Debug.WriteLine("Cant serialize AppModel:" + ex.Message);
}
}
}
After it's been called, if I remove the battery within a number of seconds (not sure how many but always less than 30), the application ends up with lost game progress. If I wait before removing battery, the data would be saved successfully. This behavior is observed on various WP7 phones.
I also tried serialization into a string buffer and then writing that string buffer to the file by calling stream.Write(), but the result is the same. Also, stream.Flush() doesn't seem to have an effect.
Is this behavior a platform feature?
Is it fine in terms of Microsoft certification for Marketplace apps?
Or is there a way to save data immediately?

Just call stream.Close when you need flush your data.
Also, try calling stream.Flush(true);

This may be interesting regarding performance of Isolated Storage : forums.create.msdn.com/forums/p/71708/71708.aspx

Related

Are hot non completing database observables a Rx usecase? Side-effect writing issue

I have more of a opinions question, asi if this, what many people do, should be a Rx use case.
In apps there is usually sql database, which is queried by UI as a observable, which emits after the query is loaded + anytime data changes (Room / SqlDelight etc)
Reads sound okay, however, is it possible to have "pure" writes to the database?
Writing to the database might look like this
fun sync() = Completable.fromCallable {
// do something
database.writeSomethingSynchronously()
}
SomeUi {
init {
database.someQueryObservable()
.subscribe { show list }
}
}
Imagine you want to display progressbar while this Completable is in flight.
What is effectively happening here is sideffecting to the database. Which means the opened database observable will re-emit when the data is written, but still before the sync() returns (assuming single threaded for simplicity)
Now there is point in time where there is new data in the UI and the progressbar is shown. (and worse with multithreading timings) This is invalid state.
In imperative world, sync would provide a completion callback, in which one would reload the query manually + show/hide progressbar synchronously. (And somehow block the database change listener for duration of the sync writes?)
Is there a way around this at all?

Geolocation.GetLastKnownLocationAsync() sometimes returns null

This is on iOS 12.1.4 on an iPhone 6s. Usually Geolocation.GetLastKnownLocationAsync() works but sometimes it doesn't. It's the exact same code but if I sit here and press my "get latitude and longitude" button over and over eventually Geolocation.GetLastKnownLocationAsync() spits out a null.
Do you know why this happens and how I might handle it? Perhaps put it in a loop that tries ten times, waiting a second between each try?
var location = await Essentials.Geolocation.GetLastKnownLocationAsync(); // works most of the time but sometimes it doesn't work.
This is my proposed work around:
Essentials.Location location = null;
for(var i = 0; i < 10; i++)
{
location = await Essentials.Geolocation.GetLastKnownLocationAsync();
if(location == null)
{
Thread.Sleep(1000);
}
else
{
break;
}
}
First, it is really bad practice to use Thread.Sleep (unless you are not on the main/UI loop) as you are hanging the run loop, if you really need a delay, use await Task.Delay(.... Also CLLocationManager on iOS is running on the main loop and if you are blocking it, the message pump is hung and the location manager manager can not report back to the app.
"Spamming" CLLocationManager.Location (which Essentials is using on iOS) can (and will) result in null returns due to OS rate limiting updates (mainly a battery conservation measure) and if the OS is powering up the GPS radio to update its location, this method will timeout on from the OS, thus report nil back to GetLastKnownLocationAsync and thus you get a return of null.
CLLocationManager.Location on iOS is meant for a quick low-power return from the OS to app as is updated upon app launch, device reboot, etc... not every time you call it.
You can get the last known location of the device by calling the GetLastKnownLocationAsync method. This is often faster then doing a full query, but can be less accurate.
Otherwise you should be using GetLocationAsync in order to do a full GPS power up to obtain an updated accurate location.
To query the current device's location coordinates, the GetLocationAsync can be used. It is best to pass in a full GeolocationRequest and CancellationToken since it may take some time to get the device's location.
Typically I recommend using GetLastKnownLocationAsync as a quick way to get the general area of the user knowing that this might also return null. Then proceed to do a GetLocationAsync (passing both a GeolocationRequest and CancellationToken instance) in the background and update the app accordingly upon the more accurate and recent position.
re: https://learn.microsoft.com/en-us/xamarin/essentials/geolocation?tabs=ios

WP7 Emulator VS Device. download performance

I developed WP7 application using the emulator. Everything was great. To communicate with the server I used WebClient and RestClient. But to test the application on a real device - I threw a shock.
1)
private void LoadData()
{
var webClient = new WebClient();
webClient.DownloadStringCompleted += DownloadStringCompleted;
webClient.DownloadStringAsync(new Uri(Constants.Url1));
//Point_1
}
private void DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
//Point_2
}
On emulator between Point_1 and Point_2 0.8-1.2 seconds.
On real device (HTC Radar WP7.8) between Point_1 and Point_2 15-20 seconds.
2)
var request = new RestRequest(url) {Method = Method.POST};
//Point_3
RestClient.ExecuteAsync(request, response =>
{
//Point_4
}
On emulator between Point_3 and Point_4 0.3-0.5 seconds.
On real device (HTC Radar WP7.8) between Point_3 and Point_4 18-22 seconds.
My computer and phone in same wi-fi network.
I have three questions:
First: It's normal?
Second: Why it's happening?
Third: How can I solved it?
There are many factors however its worth remembering that emulator performance is usually lot better than device and that you should try on device.
Having said that, you should consider alternate models of data display,
e.g. make a call and then populating data as it arrives in chunks using something like ObservableCollection.
You could also implement downloading the data using background task and having it already available.
In the end, it depends on what you can and cannot do.
Like Hermit says: "There are many factors however its worth remembering that emulator performance is usually lot better than device and that you should try on device."
My solution is - do not use debug mode, when you test network performance on real device. Just create XAP file and load it on device.

MVC3 Passing ControllerContext to thread?

I am using Rotativa in my MVC3 app to generate pdfs into a memory stream which is then emailed out as an email attachment. This works fine but it is quite slow (~5-7 seconds with just 1 user) so I've been trying to put it into a separate thread so the user doesn't get stuck with a huge delay.
The problem I've been facing is that Rotativa requires the Controller Context to generate the data into the memory stream, which means that if you try to put it in a separate thread and return a notification to the user then the context is disposed and the pdf generation will fail.
Unfortunately I do an email validation check on the server-side and return a true/false where appropriate, false will prompt the user to fix it and try again. This means I can't just assume that the email is always valid (I could do it by jquery, but if they turn it off and try to submit they won't get an error message).
So far I have tried:
Creating a new thread and passing the context in
Duplicating the context by copying it to a new variable
Serializing the context, passing the stream to the new thread and de-serializing (unfortunately the context is not serializable)
Has anyone got any other ideas?
Here is what I do to run a long process in the background with context. I'm using custom sessions backed by a database. You'll need to pass whatever values you need into the "background" action.
using (var client = new WebClient())
{
var values = new NameValueCollection
{
{ "sessionid", DataSession.Id.ExtractSid() }
};
client.UploadValuesAsync(new Uri(Url.AbsoluteAction("ResultsCallback", "Quote")), values);
}

using timer in background worker in windows phone

I am develping an app which load some url, parse them, keep them into sqlite db and the UI will read the saved data and show them in controls. This progress should be done in almost an infinit loop. For having fast response i plan to read the data from db in main thread and have an other thread (background worker) to load the data and insert it into db. Is it logical and possible to run read and write process in dispatchertimer, one timer in main thread and the other inside the background worker? and how? Or does anyone have better idea?
main thread:
DispatcherTimer _Timer1 = new DispatcherTimer();
_Timer1.Interval = _Interval;
_Timer1.Tick += _Timer1_Tick;
void _Timer1_Tick(object sender, EventArgs e)
{
// read data from db and show in controls
}
secondary thread:
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
DispatcherTimer _Timer2 = new DispatcherTimer();
_Timer2.Interval = _Interval;
_Timer2.Tick += _Timer2_Tick;
}
void _Timer2_Tick(object sender, EventArgs e)
{
// write data into db
}
}
What you're planning to do wont work.
Both your _Timer1_Tick and _Timer2_Tick will run in the UI thread. If you perform some long-running operations there, it'll hang the UI.
I don't get it, why do you need timers at all? Using timers for anything else but measuring time intervals is rarely a good strategy. You could e.g. run your update process in the infinite loop in background, as soon as it put new data in the DB you call Dispatcher.BeginInvoke (passing any data you want) to notify your UI thread it should update itself with the newly available data.
And by the way, for the tasks like "send HTTP request, wait response, parse, store, repeat", the new async/await feature is a natural choice. For WP7 the functionality is available as "Async CTP" redistributable package for Visual Studio 2010, for WP8 it's already integrated into the framework. There're some compatibility issues between the 2, though.
load some url, parse them, keep them into sqlite db and the UI will read the saved data and show them in controls
Please don't do that. Don't create your own thread management system, just don't. I'm not saying it won't work, but it'll most likely backfire in the most horrendous and inexplicable ways. Like for example using a DisptacherTImer completely exploding in your face since it runs on the UI thread. If you really want to use threading considering ThreadPool.QueueUserWorkItem() or Task.Run() to start fire-and-forget actions.
Your workflow is also just strange, I don't get why you need to write data you already have to a DB, then read it back and only then use it. Won't it make more sense to use the deserialized data to sequentially write it to the DB and present it to the UI? Instead of doing the needless loop of involving Disk I/O considering you already have the data?
Have you considered using Messaging in your app? It's a pretty well known MVVM pattern implemented both in MVVM Light as the Messenger class and in PRISM as the EventAggregator. It seems to me that your system has a Message for "new data available from service" and that message has two subscribers: writing to a DB and updating the UI.

Resources