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!

Thinking about… Design

Much progress has been made: A couple of views have been created:

So far did not give formatting too much thought, all I know is standard droid formatting is a bit lackluster…

So now the simple UI is done I need to figure out how to show something a lot more complex wich is the whole workout on one screen. To do this the best way possible I am going to look other apps that have been created in this space, first of all: GymRun. Should post some info this week.

P.S.

It works Horizontally as well ;). Was afraid it might get screwed up on Tilt :).

 

MVVM – Oh God yes!

While I was learning Xamarin forms I could not shake the thought: “Well a complex app in this must be a nightmare to debug”…

Enter the MVVM development, it stands for Model View ViewModel and is in principle very close to MVC Model Viewer Controller.

Let’s take my Workout Domain class:


public class Workout
{
public bool IsTemplate { get; set; }
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
[ForeignKey(typeof(WorkOutType))]
public int TypeId { get; set; }
public DateTime Date { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Comments { get; set; }
public string ImageDirectory { get; set; }
}

What it basically does it creates ViewModels bound to Views via a simple BindingContext Expression:

        public WorkoutsOverviewViewModel ViewModel
        {
            get { return BindingContext as WorkoutsOverviewViewModel; }
            set { BindingContext = value; }
        }

and then in the code behind you simply use this to initialize the ViewModel

 public WorkoutsOverview()
{
var workoutStore = new SQLiteWorkoutStore(DependencyService.Get<ISQLiteDb>());
var pageService = new PageService();
ViewModel = new WorkoutsOverviewViewModel(workoutStore, pageService);
InitializeComponent();
}

Simple and clean you can find the PageService, ISQLiteDb and one of it’s 3 implementations on my GitHub.

Now in my new WorkoutsOverviewViewModel:


public class WorkoutsOverviewViewModel : BaseViewModel
{
public ObservableCollection<Workout> Workouts { get; private set; } = new ObservableCollection<Workout>();
private readonly IPageService _pageService;
private Workout _selectedWorkout;
private IWorkoutStore _workoutStore;
private bool _isDataLoaded;

public ICommand LoadDataCommand { get; private set; }
public ICommand AddWorkoutCommand { get; private set; }

public WorkoutsOverviewViewModel(IWorkoutStore workoutStore ,IPageService pageService)
{
_pageService = pageService;
_workoutStore = workoutStore;
LoadDataCommand = new Command(async () => await LoadData());
AddWorkoutCommand = new Command(async () => await AddWorkout());
}
public Workout selectedWorkout
{
get { return _selectedWorkout; }
set { SetValue(ref _selectedWorkout, value); }
}
private async Task LoadData()
{
if (_isDataLoaded)
{
return;
}
Workouts.Clear();
_isDataLoaded = true;
var workouts = await _workoutStore.GetWorkoutsAsync();
{

}
foreach (var c in workouts)
{
Workouts.Add(c);
}

}
private async Task AddWorkout()
{
await _pageService.PushAsync(new WorkoutDetailsPage());
_isDataLoaded = false;
}
}

Look how in the constructor for the class we pass PageService which is in charge of handling the Xamarin forms and workoutStore in charge of handling the database operations.  So we use Xamarin and SQLite but to the class these are just methods it invokes, they can but don’t have to be Xamarin/SQLite related cuz they are defined elsewhere!

Why is it so appealing to me? To my personally despite it on a first glance being more complicated it is simpler. I have my WorkoutOverviewsViewModel and everything related to that this page is there on top of everything related to the database and page navigation is stored in a separate object. So the “meat” of my app while right now depends on Xamarin forms and SQLite, can be without too much of a problem bound to for example Azure!

Love it! And it also brings fond memories of MVC which I love as a way of delivering a web page.

So my first app in Xamarin is MVVM already!