I have a page where user can enter his name and attach an image.
When returning from tombstoning state, is it mandatory for my app to restore the image too?
Is it app certification requirement, something without which my app will not pass certification? Or is it a recommended pattern?
same question in the case when I have a pivot for example, is it mandatory to save the index of selected pivot item and restore the selection when activating from tombstoning?
Not necessary:
Is there a popular library \ framework to help me with tombstoning and serializing objects, images, etc?
According to the Technical certification requirements for Windows Phone , the only requirements are :
A Windows Phone app is deactivated when the user presses the Start button or if the device timeout causes the lock screen to engage. A Windows Phone app is also deactivated with it invokes a Launcher or Chooser API.
A Windows Phone OS 7.0 app is tombstoned (terminated) when it is deactivated. A Windows Phone OS 7.1 or higher app becomes Dormant when it is deactivated but can be terminated by the system when resource use policy causes it to tombstone.
When activated after termination, the app must meet the requirements in Section 5.2.1 – Launch time.
As the section 5.2.1 - "Launch time" only concerns startup performance and responsiveness, you don't have a certification requirement for your issue.
However, if the user enters data (attaches images, etc.) and let's say it answer a call, does some other stuff and get's back to the application and then the data he entered was lost... it surely won't appreciate it. That will look more like a defect/bug.
Concerning the serialization of your state, I recommend you to use binary serialization as the performance is at least 10x better than using Json, Xml or any other format.
Personally, I implement a custom interface, IBinarySerializable to my "state" related classes and use this BinaryWriter extensions class to help writing the serialization code:
using System.IO;
namespace MyCompany.Utilities
{
public interface IBinarySerializable
{
void Write(BinaryWriter writer);
void Read(BinaryReader reader);
}
}
using System;
using System.Collections.Generic;
using System.IO;
namespace MyCompany.Utilities
{
public static class BinaryWriterExtensions
{
public static void Write<T>(this BinaryWriter writer, T value) where T : IBinarySerializable
{
if (value == null)
{
writer.Write(false);
return;
}
writer.Write(true);
value.Write(writer);
}
public static T Read<T>(this BinaryReader reader) where T : IBinarySerializable, new()
{
if (reader.ReadBoolean())
{
T result = new T();
result.Read(reader);
return result;
}
return default(T);
}
public static void WriteList<T>(this BinaryWriter writer, IList<T> list) where T : IBinarySerializable
{
if (list == null)
{
writer.Write(false);
return;
}
writer.Write(true);
writer.Write(list.Count);
foreach (T item in list)
{
item.Write(writer);
}
}
public static List<T> ReadList<T>(this BinaryReader reader) where T : IBinarySerializable, new()
{
bool hasValue = reader.ReadBoolean();
if (hasValue)
{
int count = reader.ReadInt32();
List<T> list = new List<T>(count);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
T item = new T();
item.Read(reader);
list.Add(item);
}
return list;
}
}
return null;
}
public static void WriteListOfString(this BinaryWriter writer, IList<string> list)
{
if (list == null)
{
writer.Write(false);
return;
}
writer.Write(true);
writer.Write(list.Count);
foreach (string item in list)
{
writer.WriteSafeString(item);
}
}
public static List<string> ReadListOfString(this BinaryReader reader)
{
bool hasValue = reader.ReadBoolean();
if (hasValue)
{
int count = reader.ReadInt32();
List<string> list = new List<string>(count);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
list.Add(reader.ReadSafeString());
}
return list;
}
}
return null;
}
public static void WriteSafeString(this BinaryWriter writer, string value)
{
if (value == null)
{
writer.Write(false);
return;
}
writer.Write(true);
writer.Write(value);
}
public static string ReadSafeString(this BinaryReader reader)
{
bool hasValue = reader.ReadBoolean();
if (hasValue)
return reader.ReadString();
return null;
}
public static void WriteDateTime(this BinaryWriter writer, DateTime value)
{
writer.Write(value.Ticks);
}
public static DateTime ReadDateTime(this BinaryReader reader)
{
var int64 = reader.ReadInt64();
return new DateTime(int64);
}
}
}
Related
I have a Blazor server app. Some variables on a specific razor page (main.razor) are defined as static because I want that these variables keep their values when the client navigates to other pages in the same project and comes back again to main.razor. So far it is working good.
But when I refresh the complete page, or even close the tab and reopen my app (login again), I see that the static variables still keep their values. How can prevent this? Of course I want that the values return to their default values (like 0 or ""), when the client makes a login or refreshes the page with F5. How can I do that?
I have defined the related variables in the following way:
private static StringBuilder log = new StringBuilder();
public static string testvar1= "";
public static int testvar2= 0;
Statics exist for the lifetime of the application instance which explains the behaviour you see.
You need to be maintaining state. At one end of the spectrum you can implement a State Management system such as Fluxor. At the other just create a user class, set it up as a service and inject it as a Scoped Service. Or you can build a middle-of-the-road solution.
This is mine.
A generic UIStateService that maintains a Dictionary of (state)objects against a Guid.
public class UIStateService
{
private Dictionary<Guid, object> _stateItems = new Dictionary<Guid, object>();
public void AddStateData(Guid Id, object value)
{
if (_stateItems.ContainsKey(Id))
_stateItems[Id] = value;
else
_stateItems.Add(Id, value);
}
public void ClearStateData(Guid Id)
{
if (_stateItems.ContainsKey(Id))
_stateItems.Remove(Id);
}
public bool TryGetStateData<T>(Guid Id, out T? value)
{
value = default;
if (Id == Guid.Empty)
return false;
var isdata = _stateItems.ContainsKey(Id);
var val = isdata
? _stateItems[Id]
: default;
if (val is T)
{
value = (T)val;
return true;
}
return false;
}
}
Set it up as a service:
builder.Services.AddScoped<UIStateService>();
Next define a simple template ComponentBase page that contains the common page code:
using Blazr.UI;
using Microsoft.AspNetCore.Components;
namespace BlazorApp2.Pages
{
public class StatePage : ComponentBase
{
// this provides a guid for this specific page during the lifetime of the application runtime
// we use this as the reference to store the state data against
private static Guid RouteId = Guid.NewGuid();
[Inject] protected UIStateService UIStateService { get; set; } = default!;
protected void SaveState<T>(T state) where T : class, new()
{
if (RouteId != Guid.Empty)
this.UIStateService.AddStateData(RouteId, state);
}
protected bool GetState<T>( out T value) where T : class, new()
{
value = new T();
if (RouteId != Guid.Empty && this.UIStateService.TryGetStateData<T>(RouteId, out T? returnedState))
{
value = returnedState ?? new T();
return true;
}
else
return false;
}
}
}
And use it in a page:
#page "/"
#inherits StatePage
<PageTitle>Index</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
<SurveyPrompt Title="How is Blazor working for you?" />
<div class="p-2">
<button class="btn btn-primary" #onclick=SetData>Set Data</button>
</div>
<div class="p-3 text-primary">
State Time : #stateData.StateTime;
</div>
#code {
private MyStateData stateData = new MyStateData();
protected override void OnInitialized()
{
if (this.GetState<MyStateData>(out MyStateData value))
this.stateData = value;
else
this.SaveState<MyStateData>(this.stateData);
}
private void SetData()
{
this.stateData.StateTime = DateTime.Now.ToLongTimeString();
SaveState<MyStateData>(this.stateData);
}
public class MyStateData
{
public string StateTime { get; set; } = DateTime.Now.ToLongTimeString();
}
}
You can now navigate around the application and the state will be maintained for the page.
You can apply an observer/notification pattern to the state object to trigger automatic state updates if you wish.
I am building an android application that shows autocomplete feature and fetches autocomplete predictions in google maps using - GeoDataApi.getAutocompletePredictions. I followed this tutorial - https://github.com/googlesamples/android-play-places/blob/master/PlaceComplete/Application/src/main/java/com/example/google/playservices/placecomplete/PlaceAutocompleteAdapter.java
But somehow this is not working fine for me.
My class is this -
public class GooglePlacesAutoCompleteAdapter extends ArrayAdapter implements Filterable {
private ArrayList<PlaceAutocomplete> mResultList;
GoogleApiClient mGoogleApiClient;
private LatLngBounds mBounds;
private AutocompleteFilter mPlaceFilter;
int radius = 500;
public GooglePlacesAutoCompleteAdapter(Context context, int textViewResourceId, GoogleApiClient googleApiClient,
Location lastLocation, AutocompleteFilter filter) {
super(context, textViewResourceId);
LatLng currentLatLng = new LatLng(lastLocation.getLatitude(), lastLocation.getLongitude());
mBounds = Utility.boundsWithCenterAndLatLngDistance(currentLatLng, 500, 500);
mGoogleApiClient = googleApiClient;
mPlaceFilter = filter;
}
#Override
public int getCount() {
return mResultList.size();
}
#Override
public PlaceAutocomplete getItem(int index) {
return mResultList.get(index);
}
#Override
public android.widget.Filter getFilter() {
Filter filter = new Filter() {
#Override
public FilterResults performFiltering(CharSequence constraint) {
FilterResults filterResults = new FilterResults();
if (constraint != null && constraint.length() > 3 && constraint.length()%3 == 1) {
// Retrieve the autocomplete results.
mResultList = autocomplete(constraint.toString());
// Assign the data to the FilterResults
filterResults.values = mResultList;
filterResults.count = mResultList.size();
}
return filterResults;
}
#Override
public void publishResults(CharSequence constraint, FilterResults results) {
if (results != null && results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
};
return filter;
}
public ArrayList<PlaceAutocomplete> autocomplete(String input) {
if (mGoogleApiClient.isConnected()) {
// Submit the query to the autocomplete API and retrieve a PendingResult that will
// contain the results when the query completes.
PendingResult results = Places.GeoDataApi.getAutocompletePredictions(mGoogleApiClient, input.toString(),
mBounds, mPlaceFilter);
// This method should have been called off the main UI thread. Block and wait for at most 60s
// for a result from the API.
AutocompletePredictionBuffer autocompletePredictions = (AutocompletePredictionBuffer)results.await(60, TimeUnit.SECONDS);
// Confirm that the query completed successfully, otherwise return null
final Status status = autocompletePredictions.getStatus();
if (!status.isSuccess()) {
//Toast.makeText(getContext(), "Error contacting API: " + status.toString(),Toast.LENGTH_SHORT).show();
//Log.e(TAG, "Error getting autocomplete prediction API call: " + status.toString());
autocompletePredictions.release();
return null;
}
// Copy the results into our own data structure, because we can't hold onto the buffer.
// AutocompletePrediction objects encapsulate the API response (place ID and description).
Iterator<AutocompletePrediction> iterator = autocompletePredictions.iterator();
ArrayList resultList = new ArrayList<>(autocompletePredictions.getCount());
while (iterator.hasNext()) {
AutocompletePrediction prediction = iterator.next();
// Get the details of this prediction and copy it into a new PlaceAutocomplete object.
resultList.add(new PlaceAutocomplete(prediction.getPlaceId(), prediction.getDescription()));
}
// Release the buffer now that all data has been copied.
autocompletePredictions.release();
return resultList;
}
//Log.e(TAG, "Google API client is not connected for autocomplete query.");
return null;
}
class PlaceAutocomplete {
public CharSequence placeId;
public CharSequence description;
PlaceAutocomplete(CharSequence placeId, CharSequence description) {
this.placeId = placeId;
this.description = description;
}
#Override
public String toString() {
return description.toString();
}
}
}
The line on which GeoDataApi.getAutocompletePredictions is called, goes into an internal classes called - Filter.java, Log.java, handler.java and then Looper.java and loops there indefinetly on line 121 of Looper.java (I am sure studio sdk will show the code for Looper.java).
It is not even throwing an error, or going to the next line, it just does not work. Plus, I am not able to see the stack trace of an error.
This is the code snippet which is calling this -
if (mLastLocation != null) {
GooglePlacesAutoCompleteAdapter placesAdapter = new GooglePlacesAutoCompleteAdapter(this, R.layout.item_list, mGoogleApiClient, mLastLocation, null);
autoCompView.setAdapter(placesAdapter);
autoCompView.setOnItemClickListener(this);
}
Can someone please tell me what I am doing wrong here? Please any help will be greatly appreciated. I need to get this working as soon as I could.
PS - I am passing mPlaceFilter as null here.
Enable the Google Places API for Android in developers console
The architecture: Win8 app + local Web API Self-Host share a common "Contracts" project.
The Web API returns very general contract types (IEnumerable etc.).
Within the Win8 app I want to convert these contracts to concrete MVVM compatible model objects which use ObservableCollection for example instead of IEnumerables.
I would have loved to use AutoMapper for this task but it is not compatible with the WinRT.
I used AutoMapper some time ago, but now I generally use a specific class to do this work so I can test it and implement "strange" logic. This class is responsible for the mapping in the 2 direction (if both are needed).
Sometimes, because I'm lazy ;-), I have used an implicit conversion operator to simplify the conversion, but I think that conceptually a constructor for the dto could be better:
public class ItemDto
{
public Int32 Id { get; set; }
public String Description { get; set; }
public static implicit operator ItemDto (Item item)
{
var dto = new ItemDto()
{
Id = item.Id,
Description = item.LongDescription
};
return dto;
}
In all these cases, I think that the possibility to test your mapping has a great value.
You can to use reflection ( System.Reflection) for mapper yours DTOs by yourself, in a loop by the properties and mapping using the portable CLR types.
Thank you for your suggestions.
I solved it in a non-generic fashion, for every model I do have a specific converter that does the job. What do you think?
using Project.Contracts;
using Project.Models;
namespace Project.Converters.Contracts
{
public static class ProductConverter
{
public static ProductContract ToContract(this Product model)
{
if (model == null)
{
return new ProductContract();
}
return new ProductContract
{
Id = model.Id,
Name = mode.Name,
Tags = model.Tags.ToContracts()
};
}
public static ICollection<ProductContract> ToContracts(this IEnumerable<Product> models)
{
if (models == null)
{
return new Collection<ProductContract>();
}
return models.Select(m => m.ToContract()).ToList();
}
public static Product ToModel(this ProductContract contract)
{
if (contract == null)
{
return new Product();
}
return new Product
{
Id = contract.Id,
Name = contract.Name,
Tags = contract.Tags.ToModels()
};
}
public static ObservableCollection<Product> ToModels(this IEnumerable<ProductContract> contracts)
{
if (contracts == null)
{
return new ObservableCollection<Product>();
}
return new ObservableCollection<Product>(contracts.Select(c => c.ToModel()));
}
}
}
so I've been looking for this for a week now and reading though every problem similar but none seemed to ask the same problem as mine exactly(try reverse engineering other solution similar to what I want with no success.
explained caveman style: I'm trying to create list using Metadata.
I open with a multi dialog and select more than one mp3
I put the file in an ArrayList<File>
I loop though the files with an enhanced for loop and extract metadata using a media variable
The info for the metadata ( like "artist") is what i want to save in an ArrayList for example
the problem is that the listener only works way after the enhanced loop has finished which results in
ArrayList<String> having one object with nothing in it
here is a sample:
ArrayList<String> al;
String path;
public void open(){
files=chooser.showOpenMultipleDialog(new Stage());
for( File f:files){
path=f.getPath();
Media media = new Media("file:/"+path.replace("\\", "/").replace(" ", "%20"));
al= new ArrayList<String>();
media.getMetadata().addListener(new MapChangeListener<String, Object>() {
public void onChanged(Change<? extends String, ? extends Object> change) {
if (change.wasAdded()) {
if (change.getKey().equals("artist")) {
al.add((String) change.getValueAdded());
}
}
}
});
}//close for loop
//then i want to see the size of al like this
system.out.println(al.size());
//then it returns 1 no matter how much file i selected
//when i system out "al" i get an empty string
the other way to read a media source metadata with adding a listener is extract that information in the mediaplayer .setOnReady(); here is an example part of the java controller class
public class uiController implements Initializable {
#FXML private Label label;
#FXML private ListView<String> lv;
#FXML private AnchorPane root;
#FXML private Button button;
private ObservableList<String> ol= FXCollections.observableArrayList();
private List<File> selectedFiles;
private final Object obj= new Object();
#Override
public void initialize(URL url, ResourceBundle rb) {
assert button != null : "fx:id=\"button\" was not injected: check your FXML file 'ui.fxml'.";
assert label != null : "fx:id=\"label\" was not injected: check your FXML file 'ui.fxml'.";
assert lv != null : "fx:id=\"lv\" was not injected: check your FXML file 'ui.fxml'.";
assert root != null : "fx:id=\"root\" was not injected: check your FXML file 'ui.fxml'.";
// initialize your logic here: all #FXML variables will have been injected
lv.setItems(ol);
}
#FXML private void open(ActionEvent event) {
FileChooser.ExtensionFilter extention= new FileChooser.ExtensionFilter("Music Files", "*.mp3","*.m4a","*.aif","*.wav","*.m3u","*.m3u8");
FileChooser fc= new FileChooser();
fc.setInitialDirectory(new File(System.getenv("userprofile")));
fc.setTitle("Select File(s)");
fc.getExtensionFilters().add(extention);
selectedFiles =fc.showOpenMultipleDialog(root.getScene().getWindow());
if(selectedFiles != null &&!selectedFiles.isEmpty()){
listFiles();
}
}
/**
* Convert each fie selected to its URI
*/
private void listFiles(){
try {
for (File file : selectedFiles) {
readMetaData(file.toURI().toString());
synchronized(obj){
obj.wait(100);
}
}
} catch (InterruptedException ex) {
}
System.gc();
}
/**
* Read a Media source metadata
* Note: Sometimes the was unable to extract the metadata especially when
* i have selected large number of files reasons i don't known why
* #param mediaURI Media file URI
*/
private void readMetaData(String mediaURI){
final MediaPlayer mp= new MediaPlayer(new Media(mediaURI));
mp.setOnReady(new Runnable() {
#Override
public void run() {
String artistName=(String) mp.getMedia().getMetadata().get("artist");
ol.add(artistName);
synchronized(obj){//this is required since mp.setOnReady creates a new thread and our loopp in the main thread
obj.notify();// the loop has to wait unitl we are able to get the media metadata thats why use .wait() and .notify() to synce the two threads(main thread and MediaPlayer thread)
}
}
});
}
}
the few changes that have made is used an ObservableList to store the artist name from the metadata
in the code you will find this
synchronized(obj){
obj.wait(100);
}
I do this because the mediaplayer .setOnReady() creates a new thread and the loop is in the main application thread, The loop has to wait for some time before the other thread is created and we are able to extract the metadata, and in the .setOnReady() there is a
synchronized(obj){
obj.notify;
}
to wake up the main thread hence the loop is able to move to the next item
I admit that this may not be the best solution to do this but am welcomed to anyone who has any better way on how to read JavaFx media metadata from a list of files
The full Netbeans project can be found here https://docs.google.com/file/d/0BxDEmOcXqnCLSTFHbTVFcGIzT1E/edit?usp=sharing
plus have created a small MediaPlayer Application using JavaFX which expolits use of the metadata https://docs.google.com/file/d/0BxDEmOcXqnCLR1Z0VGN4ZlJkbUU/edit?usp=sharing
You can use the following function to retrieve the metadata for a given Media object:
public static void initializeMetaData(Media media) {
final Ref<Boolean> ready = new Ref<>(false);
MediaPlayer mediaPlayer = new MediaPlayer(media);
mediaPlayer.setOnReady(() -> {
synchronized (ready) {
ready.set(false);
ready.notify();
}
});
synchronized (ready) {
if (!ready.get()) {
try {
ready.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
However, do not call initializeMetaData from a JavaFX thread, otherwise the thread runs into a deadlock.
PS: It's really ridiculous that one has to build such a workaround. I hope that in future Media will provide an initialize() method which does this job.
My solution to that issue was this:
public class MediaListener implements MapChangeListener<String, Object>
{
public String title = null;
public String artist = null;
public String album = null;
private final Consumer<MediaListener> handler;
private boolean handled = false;
public MediaListener(Consumer<MediaListener> handler)
{
this.handler = handler;
}
#Override
public void onChanged(MapChangeListener.Change<? extends String, ?> ch)
{
if (ch.wasAdded())
{
String key = ch.getKey();
switch (key)
{
case "title":
title = (String) ch.getValueAdded();
break;
case "artist":
artist = (String) ch.getValueAdded();
break;
case "album":
album = (String) ch.getValueAdded();
break;
}
if (!handled && title != null && artist != null && album != null)
{
handler.accept(this);
handled = true;
}
}
}
}
It may not be the best way but it's way cleaner than creating a new MediaPlayer per file.
Example usage:
Media media = Util.createMedia(path);
media.getMetadata().addListener(new MediaListener((data) ->
{
// Use the data object to access the media
}));
Every programmer ends up with a set of utility classes after a while. Some of them are true programming pearls and they are reused in several of your projects. For example, in java:
class Separator {
private String separator;
private boolean called;
public Separator(String aSeparator) {
separator = aSeparator;
called = false;
}
#Override
public String toString() {
if (!called) {
called = true;
return "";
} else {
return separator;
}
}
}
and:
public class JoinHelper {
public static <T> String join(T... elements) {
return joinArray(" ", elements);
}
public static <T> String join(String separator, T... elements) {
return joinArray(separator, elements);
}
private static <T> String joinArray(String sep, T[] elements) {
StringBuilder stringBuilder = new StringBuilder();
Separator separator = new Separator(sep);
for (T element : elements) {
stringBuilder.append(separator).append(element);
}
return stringBuilder.toString();
}
}
What is your most reused class?
System.Object - almost all my types extend it.
A utility class that has logging and email functionality. An extensions class that contains extension methods. A reporting class that basically harness the reporting services web service and makes it easy to stream reports as excel, pdf, etc.
Examples...
1.) Utility Class (static)
public static void LogError(Exception ex)
{
EventLog log = new EventLog();
if (ex != null)
{
log.Source = ConfigurationManager.AppSettings["EventLog"].ToString();
StringBuilder sErrorMessage = new StringBuilder();
if (HttpContext.Current.Request != null && HttpContext.Current.Request.Url != null)
{
sErrorMessage.Append(HttpContext.Current.Request.Url.ToString() + System.Environment.NewLine);
}
sErrorMessage.Append(ex.ToString());
log.WriteEntry(sErrorMessage.ToString(), EventLogEntryType.Error);
}
}
2.) Extensions Class
public static IEnumerable<TSource> WhereIf<TSource>(this IEnumerable<TSource> source, bool condition, Func<TSource, bool> predicate)
{
if (condition)
return source.Where(predicate);
else
return source;
}
public static short getLastDayOfMonth(short givenMonth, short givenYear)
{
short lastDay = 31;
switch (givenMonth)
{
case 4:
case 6:
case 9:
case 11:
lastDay = 30;
break;
case 2:
if ((int)givenYear % 4 == 0)
{
lastDay = 29;
}
else
{
lastDay = 28;
}
break;
}
return lastDay;
}
Most reused but boring:
public static void handleException(Exception e) throws RuntimeException {
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
}
throw new RuntimeException(e); //NOPMD
}
Less boring (also methods for building lists and sets):
/**
* Builds a Map that is based on the Bean List.
*
* #param items Bean List items
* #param keyField Bean Field that will be key of Map elements (not null)
* #return a Map that is based on the Bean List
*/
#SuppressWarnings("unchecked")
public static <T, K> Map<K, T> buildMapFromCollection(final Collection<T> items,
boolean linkedMap,
final String keyField,
final Class<K> keyType) {
if (items == null) {
return Collections.emptyMap();
}
if (keyField == null) {
throw new IllegalArgumentException("KeyField is null");
}
final Map<K, T> result;
if (linkedMap) {
result = new LinkedHashMap<K, T>();
} else {
result = new HashMap<K, T>();
}
BeanMapper mapper = null;
for (final T item : items) {
if (mapper == null) {
mapper = new BeanMapper(item.getClass());
}
final K key = (K) mapper.getFieldValue(item, keyField);
result.put(key, item);
}
return result;
}
Logger class: Which logs the flow of control in a log file.
Configuration Reader/Setter: which reads the configuration from ini/xml file and sets the environment of the application
Most reused? Hmmm...
boost::shared_ptr<> with boost::weak_ptr<>
probably most reused (also probably most bang-for-buck ratio)
Globals
Just a simple class with static DBConnString, and a few other app wide settings.
Have reused the simple file in about 2 dozen projects since working with .Net
A ConcurrentDictionary I wrote, which I now seem to use everywhere (I write lots of parallel programs)