Don’t load data you dont really need.

In my previous posts, we discussed my load method and how to implement a picker resulting in the following method:


private async Task LoadData()
{
if (_isDataLoaded)
return;
ModelExercises.Clear();
_isDataLoaded = true;

var modelExercises = await _workoutStore.GetModelExercisesAsync();

foreach (var modelExercise in modelExercises)
{
ModelExercises.Add(await
ModelExerciseViewModel.CreateAsync(modelExercise, _workoutStore)
);

}

var muscles = await _workoutStore.GetMusclesAsync();

foreach (var muscle in muscles)
{
Muscles.Add(muscle);
}

if (SelectedMuscle != null)
{
var selectedMuscle = from m in Muscles
where m.Name == SelectedMuscle
select m;
Muscles.Clear();
Muscles.Add(selectedMuscle.SingleOrDefault());
}

foreach (var muscle in Muscles)
{
var currentMuscle = new ExerciseGroup(muscle.Name, muscle.Name);

var foundMuscles = from e in ModelExercises
where e.PrimaryMuscles.Contains(muscle, _compareMuscle)
select e;
currentMuscle.AddRange(foundMuscles);
GroupedExercises.Add(currentMuscle);
}

}

The primary problem with this approach is in:


foreach (var modelExercise in modelExercises)
{
ModelExercises.Add(await
ModelExerciseViewModel.CreateAsync(modelExercise, _workoutStore)
);

}

Which triggers the static async method (which replaces the constructor which itself cannot be async):


public static async Task<ModelExerciseViewModel> CreateAsync(ModelExercise exercise, IWorkoutStore workoutStore)
{
_workoutStore = workoutStore;

ModelExerciseViewModel exerciseViewModel = new ModelExerciseViewModel(exercise);
exerciseViewModel.PrimaryMuscles = await GetMuscles("Primary");
exerciseViewModel.SecondaryMuscles = await GetMuscles("Secondary");
return exerciseViewModel;
}

It works… but it is super slow, on my Galaxy A52016 it took ~6sec to generate the original list and ~2sec for each filtering. Unacceptable.

Then it dawned on me… Why do I generate objects I don’t need at this time?

The original logic was: I am going to create all the objects and then use the lists of muscles I build for them for filtering.

What seemed like a good plan was loading information I did not need into the application when I have a perfectly good simple object:


public class MuscleExerciseAssosiation
{
public int MuscleId { get; set; }
public int ModelExerciseId { get; set; }
public string MuslceType { get; set; }
}

In my database based on which I can use for filtering:


public async Task<IEnumerable<MuscleExerciseAssosiation>> GetMuscleExerciseAssosiations(string muscleType, int? muscleID = null)
{
List<MuscleExerciseAssosiation> assosiations = new List<MuscleExerciseAssosiation>();
if (muscleID == null)
{
assosiations = await _connection.Table<MuscleExerciseAssosiation>()
.Where(e=>e.MuslceType == muscleType).ToListAsync();
}
else
{
assosiations = await _connection.Table<MuscleExerciseAssosiation>()
.Where(e => e.MuscleId == muscleID && e.MuslceType == muscleType).ToListAsync();
}

return assosiations;
}

Now when I can pull at will either a filtered or full list of exercises I need I can simply:


if (SelectedMuscle != null)
{
var assosiatedExercises = await _workoutStore.GetMuscleExerciseAssosiations("Primary", SelectedMuscle.Id);
foreach (var assosiation in assosiatedExercises)
{
ModelExercises.Add(modelExercises.Where(e => e.Id == assosiation.ModelExerciseId).SingleOrDefault());
}
}
else
{
muscles = await _workoutStore.GetMusclesAsync();

foreach (var muscle in muscles)
{
Muscles.Add(muscle);
}
foreach (var exercise in modelExercises)
{
ModelExercises.Add(exercise);
}

}

And thats it. Perfomance to being unoticable for both the initial load and filtering, so I am preatty proud of myself 🙂

The full new ViewModel can be found on github.

A little guide on dealing Xamarin errors

So… I  sank around 3 hours into fixing this across 2 days… Turns out there is nothing wrong with the Picker, nothing wrong with my solution… The issue was within Xamarin.

Mono just got confused and was killing everything…

While digging thru the logs of the output I found out that the issue was linked to XamlFilePathAttribute so while there was no direct thread related to my issue I found this post, and it saved my life bottom line to fix a variety of issues with this class:

  • Cleanup solution
  • Close Xamarin Studio/VS
  • Remove all .bin and .obj folders in all projects.
  • Open Xamarin Studio/VS and rebuild the solution.

The Rebuild word is key be sure to

ReBuild

And not just try to debug it again like I did. Now everything works perfectly:

The simplest of things…

In Xamarin Forms 2.3.4 they added a Bindable picker to the XAML as per this documentation:
https://blog.xamarin.com/new-bindable-picker-control-for-xamarin-forms/

But cut my dick off and call me daisy but I cannot get it to work… I made a list dedicated to it:


public ObservableCollection<string> MuscleGroups { get; private set; } = new ObservableCollection<string>();

Filling it in nice and proper


var muscles = await _workoutStore.GetMusclesAsync();
foreach (var muscle in muscles)
{
MuscleGroups.Add(muscle.Name);
}

Bound it in XAML:


<Picker ItemsSource="{Binding MuscleGroups}" SelectedItem="{Binding SelectedMuscle}" />

But it crashes as soon as I try to load the page, its been two hours after a long day of doing Python in the office, I need a break… Going to fix it tommorow.

Implementing IEqualityComparer for custom object comparison

I had a simple snippet of code:


foreach (var muscle in muscles)
{
var currentMuscle = new ExerciseGroup(muscle.Name, muscle.Name);

var foundMuscles = from e in ModelExercises
where e.PrimaryMuscles.Contains(muscle)
select e;
currentMuscle.AddRange(foundMuscles);
GroupedExercises.Add(currentMuscle);
}

However where e.PrimaryMuscles.Contains(muscle) refused to generate any results. To me, it was logical that the muscles are the same (they Shared and ID and a Name), but to the compiler they were different. Obviously, they were equal in properties but not the same object… Silly me. So the problem is stated the stage is set.

Thankfully .Contains() has an overload that takes two parameters an object and an IEqualityComparer, great! Let’s get implementing!


private IEqualityComparer<Muscle> _compareMuscle { get; set; } = new MuscleComparer();

private class MuscleComparer : IEqualityComparer<Muscle>
{
public bool Equals(Muscle x, Muscle y)
{
bool id=false;
bool name=false;
if (x.Id == y.Id)
id = true;
if (x.Name == y.Name)
name = true;
return id && name;
}

public int GetHashCode(Muscle muscle)
{
int hCode = muscle.Id ^ muscle.Name.Length;
return hCode.GetHashCode();
}
}

So a very simple interface of two methods Equals and GetHashCode quick implementation and now our app returns a proper segmented view:

Perfect, it does, however, take a performance hit after this change (the load takes ~2seconds) so I might want to look at making it faster somehow.

Removing HTML tags from a string

Problem:

Screenshot_1493145278.png

The HTML from the API is in the exercise description. It looks like shit and is a potential security threat!

There a couple of ways you can tackle this particular beast:

  • Use REGEX:
    
    using System.Text.RegularExpressions;
    ...
    const string HTML_TAG_PATTERN = "<.*>";
    
    static string StripHTML (string inputString)
    {
     return Regex.Replace
     (inputString, HTML_TAG_PATTERN, string.Empty);
    }
    

    Created by a StackOverflow use capdragon

  • HTML Agility Pack
     public static string StripTagsCharArray(string source)
     {
     HtmlDocument htmlDoc = new HtmlDocument();
     htmlDoc.LoadHtml(source);
     htmlDoc.DocumentNode.SelectNodes("//comment()")?.ForEach(c=> c.Remove());
     return htmlDoc.DocumentNode.InnerText;
     }
    

    Created by users Ssilas777 and Thierry_S

  • And lastly the simplest but fastest one:
     public static string StripTagsCharArray(string source)
     {
     char[] array = new char[source.Length];
     int arrayIndex = 0;
     bool inside = false;
     for (int i = 0; i &amp;lt; source.Length; i++)
     {
     char let = source[i];
     if (let == '<')
     {
     inside = true;
     continue;
     }
     if (let == '>')
     {
     inside = false;
     continue;
     }
     if (!inside)
     {
     array[arrayIndex] = let;
     arrayIndex++;
     }
     }
     return new string(array, 0, arrayIndex);
     }
    

    Shared by AuthorProxy in the same thread a capdragons solution.

I went for what is behind door no. 3. IT suites my needs does not require any additional libraries to be loaded does not process the HTML code, so any malicious code it will get its ass ignored by being treated as a string.

Screenshot_1493146922.png

Voila!

Builder Pattern – Creating a full set of exercise objects

Three things need to happen in order for me to have a full ModelExercise from the API:

  1. Muscle Groups need to be downloaded
  2. Exercises need to be downloaded
  3. An association table must be built between the two.

Normally I’d use Entity Framework for this sort of thing but with PCL at a time when I started the project, it had quite a lot of problems and SQLite.NET-PCL  was the recommended solution.
That is okay but it means I need to build everything myself so long:


public virtual List<Exercise> Exercises {get; set;}

I need to build this relationship myself, so first of a model class:


 public class MuscleExerciseAssosiation
 {
 public int MuscleId { get; set; }
 public int ModelExerciseId { get; set; }
 public string MuslceType { get; set; }
 }

How I get muscles and exercises you can see in my previous post the association is build:


public override List<MuscleExerciseAssosiation> AssosiationGet()
{
if (_wgerExercises.Count == 0 || _muscles.Count == 0)
{
return new List<MuscleExerciseAssosiation>();
}
foreach (var exercise in _wgerExercises)
{
foreach (var muscle in exercise.muscles)
{
_muscleAssosiations.Add(
new MuscleExerciseAssosiation
{
ModelExerciseId = exercise.id,
MuscleId = muscle,
MuslceType = "Primary"
}
);
}
foreach (var muscle in exercise.muscles_secondary)
{
_muscleAssosiations.Add(
new MuscleExerciseAssosiation
{
ModelExerciseId = exercise.id,
MuscleId = muscle,
MuslceType = "Secondary"
}
);
}
}
return _muscleAssosiations;
}

which I then simply load into the database:


private async Task FillMuscleExerciseAssosiations(AbstractSourceFactory factory)
{
List<MuscleExerciseAssosiation> assosiations = factory.AssosiationGet();
await _connection.InsertAllAsync(assosiations);
}

But it is private… so I cannot call it outside of the class… Thats where the builder pattern comes in, as mentioned at the top of the post all 3 things need to happen in a sequence and they all need to happen, hence a new public method:


public async Task BuildMuscleDatabase(AbstractSourceFactory factory)
{
await FillMusclesFromDataStore(factory);
await FillExercisesFromDataStore(factory);
await FillMuscleExerciseAssosiations(factory);
}

calling all 3 in a sequence with one call from the outside, we are always sure that we called are methods correctly, and with this method being part of the IWorkoutStore interface we opened another ease of work for the future.

Refactoring for the glory of Bob!

Bob  has shown us the way and we shall not stray!!!

So in my previous API example, I used Newtonsofts JsonConvert.DeserializeObject(content);


JsonConvert.DeserializeObject<Type>(content);

The problem was that I have more than one API node I wish to pull on meaning that I had to either use anonymous types which would make the code hard to read or create a separate object for both responses:


private class _exerciseResponse
{
public int count { get; set; }
public string next { get; set; }
public string previous { get; set; }
public List<_wgerExercise> results { get; set; }
}
private class _muscleResponse
{
public int count { get; set; }
public string next { get; set; }
public string previous { get; set; }
public List<_wgerMuscle> results { get; set; }
}

It’s kind of sloppy because the response only differs when it comes to the “results” variable, so I decided to after checking that the core of the app works to do a bit of refactoring:


private class reposnse<T>
{
public int count { get; set; }
public string next { get; set; }
public string previous { get; set; }
public List<T> results { get; set; }
}

Logically after I call the JSON deserialize I call it giving it a proper type:


var response = JsonConvert.DeserializeObject<reposnse<_wgerExercise>>(content);

var response = JsonConvert.DeserializeObject<reposnse<_wgerMuscle>>(content);

Good now that leaves this lump of old code:


ExercisesGet()
{
string next;
next = await ParseJSON();
while (next != null)
{
await ParseJSON(next);
}
return _exercises;
}
private async Task<string> ParseJSON(string url= null)
{
if (url == null)
{
url = _URL;
}
var content = await _client.GetStringAsync(_URL);
var response = JsonConvert.DeserializeObject<_response>(content);
var exercises = response.results;
foreach (var exercise in exercises)
{
_exercises.Add(
new ModelExercise
{
Id = exercise.id,
Name = exercise.name,
Description = exercise.description,
}
);
}
return response.next;

}

It’s refactoring time!

First of all lets make the Method ParseJSON() generic:


private async Task<List<T>> ParseJSON<T>(string url = null)
{
_next = null;
if (url == null)
{
url = _ExerciseURL;
}
var content = await _client.GetStringAsync(url);
var response = JsonConvert.DeserializeObject<_response<T>>(content);
var results = response.results;
_next = response.next;

return results;
}

But now instead of returning our final object it retuns a list of our dummy objects so we need to make changes in the ExercisesGet() 


public async override Task<List<ModelExercise>> ExercisesGet()
{

var exercises = await ParseJSON<_wgerExercise>();

while (_next != null)
{
exercises.AddRange(await ParseJSON<_wgerExercise>(_next));
}

foreach (var exercise in exercises)
{
_exercises.Add(
new ModelExercise
{
Id = exercise.id,
Name = exercise.name,
Description = exercise.description,
UserGenerated = false
}
);
}

return _exercises;
}

and to have show of it being worth it ExercisesGet()’s sister MuscleGet()


public async override Task<List<Muscle>> MuscleGet()
{
var content = await _client.GetStringAsync(_MuscleURL);
var muscles = await ParseJSON<_wgerMuscle>();
while (_next!=null)
{
muscles.AddRange(await ParseJSON<_wgerMuscle>(_next));
}
foreach (var muscle in muscles)
{
_muscles.Add(
new Muscle
{
Id = muscle.id,
Name = muscle.name
});
}
return _muscles;
}

The only block that I do not like still where I repeat myself is:


while (_next!=null)
{
muscles.AddRange(await ParseJSON<_wgerMuscle>(_next));
}

And I will figure out how to re-factor this just not now ;).