While working on an application using Next.js App Router and React Server Components, I needed to open a modal from two different places:
A button on the home page
A link on the navigation bar
While working on an application using Next.js App Router and React Server Components, I needed to open a modal from two different places:
A button on the home page
A link on the navigation bar
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
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
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
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!
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/
I recently needed to implement a custom ListView component with drag to rearrange functionality for an Android application written in C# using Xamarin.
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:
Then as the finger is panned up and down the screen, the following operations take place:
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:
How to implement:
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
One of the major changes in iOS 8 was the UIAlertController class replacing the UIAlertView and UIActionSheet as the preferred way of displaying alerts. Here is how I resolved a crash in iOS 8 when trying to navigate from a UIActionSheet.
Read MoreThe iOS simulator is extremely useful during active development, however, when ensuring required functionality and performance of an application, testing on an actual device is critical. The following post outlines key differences between an acutal iOS device and the iOS Simulator.
Read MoreCollectionViews are an excellent tool for presenting ordered sets of data that require a flexible layout. When developing using CollectionViews, memory management is critical for fluid functionality.
Read More