Making SupportMapFragment load faster (Xamarin.Android) by Pranav Khandelwal

So I am working on an Android application in which one of the sections is a location search screen. Because I need backwards compatibility, I am using the SupportMapFragment to load the map into the layout.

The layout is fairly complex, consisting of a parent Activity, with tabs at the bottom. Each tab is represented by a Fragment, and each of these Fragments can contain a ViewPager that displays several other Fragments. For reasons that are irrelevant to this post, I needed to init and inject the SupportMapFragment into the layout programmatically. 

One of the issues I was running into was that when I went to the Locations tab, I would see an ugly black background where the map is supposed to be and after about 3-5 seconds, the screen would update to display the map. This is not ideal at all, and a jarring user experience. So off to StackOverflow I went, looking for answers to a problem that I suspected many people have encountered before. My suspicions were confirmed:

http://stackoverflow.com/questions/26265526/what-makes-my-map-fragment-loading-slow
http://stackoverflow.com/questions/26178212/first-launch-of-activity-with-google-maps-is-very-slow
http://stackoverflow.com/questions/26977051/supportmapfragment-loads-extremely-slowly-the-first-time-but-quickly-in-subsequ

So the natural question was, why is it taking so long to load the map? After doing some research and a bit of debugging, I realized that downloading everything that is needed to display the map from the Google Play Services API was the primary issue. 

The Solution (Hack?):

I hate to call this a solution because it feels more like a hack, but whatever, lets just get to the nitty gritty. I basically knew that I needed to download all the data from Google Play Services before the user is able to access the Locations tab. The app has an initial Activity (lets call it InitActivity) that is loaded with a spinner while it downloads the necessary data to launch...kind of like the Splash Screen on iOS apps. This seemed like a pretty ideal spot to download Google Play Services stuff for the map.

So what I did was in the OnCreate method of the InitActivity, I constructed a SupportMapFragment, injected it into the layout and dispatched the call to download the Google Play Services data. 

protected override void OnCreate(Bundle bundle)
{   
    base.OnCreate(bundle);

    SetContentView(Resource.Layout.init);

    var supportMapFragment = SupportMapFragment.NewInstance();
    var supportMapFragment.GetMapAsync(this);

    var ft = SupportFragmentManager.BeginTransaction();
    ft.Add(Resource.Id.pre_load_map_frame, supportMapFragment, typeof(SupportMapFragment).Name);
    ft.Commit();
}

public void OnMapReady(GoogleMap googleMap)
{
}

Notice that the OnMapReady callback method is completely empty...because we don't use this map in anyway. Another thing to note here is that my pre_load_map_frame ViewGroup in which I am injecting the SupportMapFragment is actually just a FrameLayout with a height of 0dp.

I also learned that we have to perform the Fragment Transaction if we want the GetMapAsync call to actually download the Google Play Services data. When I tried removing the transaction as an optimization, I noticed that the OnMapReady callback stopped firing completely, suggesting that the data wasn't being downloaded! 

Once this runs, anytime in the future when I try to construct and inject a SupportMapFragment to a layout, it shows up instantly. This works because the SupportMapFragment class will cache the downloaded Google Play Services data after the initial download. 

The downside of this approach is that the 3-5 second loading time hasn't been eliminated, but instead just moved to the launch time of the app....which isn't ideal, but it is leaps and bounds better than the nasty, jarring user-experience of loading the map on the Location tab. 

-PK

System.Net.Primitives version differences in PCL Profile 7 vs PCL Profile 78 by Pranav Khandelwal

I recently ran into a strange issue with a version mismatch for the System.Net.Primitives assembly between PCL profile 7 and PCL profile 78. Profile 78 targeted version 3.9 whereas Profile 7 targeted version 4.0.

The primary reference "MyLibrary" could not be resolved because it has an indirect dependency on the .NET Framework assembly "System.Net.Primitives, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" which has a higher version "4.0.0.0" than the version "3.9.0.0" in the current target framework. (MSB3258) (myApp.Core)

What was even more strange was that the warning above would only be fired on Xamarin Studio running on Windows. XS on Mac would build fine, however, XS on windows would fail to resolve the "MyLibrary" reference due to the mismatch.

The way I solved the issue was by making sure the PCL Profiles matched. Profile 78 does not include System.Net.Http, which was being used in "MyLibrary", so that had to be included in as a Nuget package.

Hope this helps anyone else having version mismatches for various assemblies between PCL profiles. Feel free to reach out if you are having the same issue.

Thanks!
PK

 

Detecting User Inactivity/Idle Time in Xamarin.iOS using async/await by Pranav Khandelwal

iOS includes a method within the UIApplication class that can be used to disable the idle timer and keep the device from going into idle. This is often used during long running processes where the device needs to remain in an active state:

Objectice-C
[UIApplication sharedApplication].idleTimerDisabled = YES;

Xamarin.iOS
UIApplication.SharedApplication.IdleTimerDisabled = True;

What is missing is a hook to determine how long a user has been idle while the application is in an active state. After searching for code snippets on how to accomplish this, I noticed that there were many in Objective-C but none for Xamarin, C#. Furthermore, the Objective-C ones made use of NSTimer, which was something I wanted to avoid. 

I decided to go the async/await route and dispatch a thread that would return after a specified amount of time. One of the requirements was that we must restart the timer every time the user touches the screen, which was a perfect fit for CancellationTokens.

See the implementation here:

Step 1: Add the following 3 methods to your AppDelegate:

		private CancellationTokenSource idleTimerCancellationTokenSource;
        public void ResetIdleTimer ()
		{
    		//use, then gid rid of the old CancellationTokenSource
			if (idleTimerCancellationTokenSource != null) {
				idleTimerCancellationTokenSource.Cancel ();
				idleTimerCancellationTokenSource.Dispose ();
				idleTimerCancellationTokenSource = null;
			}
				// Restart the timer with a new CancellationTokenSource
				StartIdleTimer (new CancellationTokenSource ());
		}

		public void StopIdleTimer ()
		{
        	// use, then get rid of the CancellationTokenSource
			if (idleTimerCancellationTokenSource != null){
				idleTimerCancellationTokenSource.Cancel ();
                idleTimerCancellationTokenSource.Dispose ();
				idleTimerCancellationTokenSource = null;
             }
		}
		
		public async Task StartIdleTimer (CancellationTokenSource tokenSource)
		{
			try {
            	//maintain a reference to the token so we can cancel when needed
				idleTimerCancellationTokenSource = tokenSource;

				Debug.WriteLine ("Idle Timer Thread Started");
				await Task.Delay (TimeSpan.FromSeconds(120), tokenSource.Token);

				Debug.WriteLine ("Idle Timeout Detected, Do Stuff!");
                //Do something here, like show a screensaver or something
                InvokeOnMainThread(() => /* Do Some navigation or something */);

			} catch (TaskCanceledException ex) {
            	//if we cancel/reset, this catch block gets called
				Debug.WriteLine ("Idle Timer Thread Cancelled");
			}
			// if we reach here, this timer has stopped
			Debug.WriteLine ("Idle Timer Thread Complete");
		}

Step 2: Create a custom UIApplication and override the SendEvent(UIEvent uievent) method to capture application-wide Touch events. Call ResetIdleTimer() in the AppDelegate when a touch event is captured:

    public class CustomApplication : UIApplication
    {
        public CustomApplication () : base ()
        {
        }

        public CustomApplication (IntPtr handle) : base (handle)
        {
        }

        public CustomApplication (Foundation.NSObjectFlag t) : base (t)
        {
        }
        public override void SendEvent (UIEvent uievent)
        {
            if (uievent.Type == UIEventType.Touches) {
                if (uievent.AllTouches.Cast<UITouch> ().Any (t => t.Phase == UITouchPhase.Began)) {
                    ((AppDelegate)Delegate).ResetIdleTimer ();
                }
            }

            base.SendEvent (uievent);
        }
    }

Step 3: Update Main.cs to use our new CustomApplication class instead of the default UIApplication class:

static void Main (string[] args)
{
    UIApplication.Main (args, typeof(CustomApplication), typeof(AppDelegate));
}

Step 4: To start/stop the Idle Timer, you can make the following calls from anywhere in your iOS code:

START:
((AppDelegate)UIApplication.SharedApplication.Delegate).StartIdleTimer (new CancellationTokenSource ());

STOP:
((AppDelegate)UIApplication.SharedApplication.Delegate).StopIdleTimer ();

Remember, that anything UI specific that is called when the Timeout is reached should be wrapped in an InvokeOnMainThread(...):

InvokeOnMainThread(() => /* Do Some navigation or something */);

And thats it! Congratulations! You have implemented an Idle Timer that will run in the background and be reset each time the user has any on screen activity.

Feel free to reach out if you have any questions or suggestions on improving this code! I am planning on creating an open soruce cross-platform helper for this and posting to GitHub. Check back for the link!

Thanks!
PK

Xamarin.Android + Xamarin Android Player - Fixing emulator launch issues by Pranav Khandelwal

I really like the Xamarin Android Player emulator (https://xamarin.com/android-player). It is hassle free and very easy to setup. 

Unfortunately, I have been constantly running into an issue where if I launch the emulator via Xamarin Studio, by attempting to build and run a Xamarin.Android app, the emulator launches successfully, but the IDE never attaches to it, and just keeps displaying the "Starting...." message:

After a bit of research I discovered a workaround that fixes this:

Rename the emulators so that they are alphanumeric with no spaces, and voila, the emulators now launch perfectly fine from the IDE!

4 Tips To Build Production Apps With Xamarin Forms by Pranav Khandelwal

Xamarin.Forms is a game changer in mobile development. Introduced in May 2014, Xamarin.Forms provides developers with a way to share user interface code. This ability to share such an impressive amount of code greatly cuts down on development time. The initial releases of Xamarin.Forms were excellent for making quick prototypes and internal applications that didn’t require complex user interfaces. Over the past 11 months, the Forms team has fixed bugs and added improvements to the API making the most recent release (v1.4) feel like a very polished product. It seems that Xamarin.Forms has finally matured enough to where it can be used to build a true production application without making compromises in user interface design. By leveraging the power of custom renderers, developers can use Xamarin.Forms to create production applications that are fully featured and boast an impressive user interface.

Read the whole post here:
http://bluetubeinc.com/blog/2015/4/4-tips-to-build-production-apps-easier-with-xamarin-forms/

Drag & Rearrange ListView for Xamarin Android by Pranav Khandelwal

I recently needed to implement a custom ListView component with drag to rearrange functionality for an Android application written in C# using Xamarin.

Video Link: http://vimeo.com/115447413

After doing some research, I came across the DevBytes tutorials on YouTube. If you are doing Android development and haven’t come across these videos yet, I would highly recommend taking a look: https://www.youtube.com/channel/UCVHFbqXqoYvEWM1Ddxl0QDg. They have some really informative and helpful content.

One of the videos walked you through the implementation of a drag to rearrange ListView on Android: https://www.youtube.com/watch?v=_BZIvjMgH-Q. This was exactly what I needed. 

The approach that was taken was that when a long press was detected, we perform the following operations:

  1. We determine the index-position in the List of our touch point.
     
  2. We create a “mock-cell” that would essentially be a screenshot of the long-pressed ListView cell. We add this cell on the screen in the same position and on top of our ListView cell.
     
  3. We set the visibility of the actual ListView cell to invisible. This gives the visual effect of an “empty” spot in the ListView

Then as the finger is panned up and down the screen, the following operations take place:

  1. We update the y-position of the touch-point on our “mock cell” to match the y-position of our pointer finger. This will provide the dragging effect.
     
  2. As our cell position updates, we will check to see if the cell is above or below an adjacent cell. When this condition is true, we will animate a swap by sliding the adjacent cell into its new position. When this animation is complete, we will update the dataset to match what is displayed on screen.

When the pointer finger is released we will animate the “mock-cell”
 back into position and when this animation is complete, we will get rid of our mock-cell and unhide the actual ListView cell.

The original source code is in Java, but porting it to C# was fairly straightforward.  I made a couple changes in the C# implementation:

  1.  Instead of doing the animation of the cells in the PreDraw event on the ViewTreeObserver after the dataset is updated. I do the animation and then change the dataset using an Object Animator object and its AnimationEnd event.
     
  2. I did not implement rearranging while scrolling, but it should be relatively straightforward to port the functionality over from the original tutorial.

How to implement:

  1. Download and include DraggabeListView.cs and IDragagbleListAdapter.cs into your solution.
     
  2.  Implement the custom component in your layout file. The following documentation from the Android Developer portal has an example of how to do this: http://developer.android.com/training/custom-views/create-view.html
     
  3. Create a ListView adapter class that implements the IDraggableListAdapter interface.  The interface includes one method: SwapItems(int from, int to) and one integer property: mMobileCellPosition. 
    SwapItems(int from, int to) is responsible for updating the underlying dataset, the mMobileCellPosition variable, and calling NotifyDataSetChanged() on the adapter. The integer property mMobileCellPosition is responsible for ensuring the correct visibility states for cells. Suggested implementations are included in the code.

Hope this helps anyone else doing Android development using Xamarin. If you have questions or comments to improve the code, do not hesitate to comment or reach out!

Link to code: https://github.com/pnavk/DraggableListView

Thanks for reading!

PK