How to implement Java Callback in constructor using C#

Background

I did one case for my customer who’s trying to binding one Android aar which is a DatePicker/TimerPicker control to his Xamarin.Android project. I helped to generate the aar file and the binding was successful. However, when trying to use the binding library, I got stuck on some code implemment.

What’s the problem?

Sometimes in Android development, you will see this kind of scenario: for some customized UI control, there will be a Callback class in the constructor of that control. In Java, it’s quite convenient because you can customize the callback behavior for each instance of that control.

In my case, the CustomDatePicker can be either DatePicker (only select Date) or TimerPicker (select Date+Time). And the callback is different becasue we have 2 Editor on the screen, when you click on the DatePicker editor, the DatePicker pop up and the callback is to write the selected Date to that Editor. Also there will be a method to handle the string parameter which is also implemented differently. Same as TimerPicker.

Java implementation

In the Android library, there will be an interface for the callback method as below:

1
2
3
4
// Callback Interface after time selected
public interface Callback {
void onTimeSelected(long timestamp);
}

Below is one of the constructor of the CustomDatePicker:

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* Instantitate the DatePicker
*
* @param context Activity Context
* @param callback Callback after select date
* @param beginDateStr Date String, format: yyyy-MM-dd HH:mm
* @param endDateStr Date String, format: yyyy-MM-dd HH:mm
*/

public CustomDatePicker(Context context, Callback callback, String beginDateStr, String endDateStr)
{
// ...
}

Then in the MainActivity.java file, we will have 2 functions that will instantitate 2 DatePicker with different implementation as below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private void initDatePicker()
{
// ....
mDatePicker = new CustomDatePicker(this, new CustomDatePicker.Callback(){
@override
public void onTimeSelected(long timestamp) {
mTvSelectedDate.setText(DateFormatUtils.long2Str(timestamp, false));
}
}, beginTimestamp, endTimestamp);
//...
}

private void initTimerPicker()
{
// ...
mTimerPicker = new CustomDatePicker(this, new CustomDatePicker.Callback(){
@override
public void onTimeSelected(long timestamp){
mTvSelectedTime.setText(DateFormatUtils.long2Str(timestamp, true));
}
}, beginTimestamp, endTimestamp);
// ...
}

We can see from the above code that for DatePicker, we are going to set the text to mTvSelectedDate textbox and the second parameter for DateFormatUtils.long2Str is false.

However, for TimerPicker, we are going to set the text to mTvSelectedTime textbox and the second parameter for DateFormatUtils.long2Str is true.

But in Xamarin.Android, we are going to code this as the C# language, you will see that this cannot be done because we cannot implement the interface within a class’s constructor.

Solution

In C#, we all know that if we are going to implement some interface, we need a class that inherits from this interface and then implement the method that needs to be implemented for that interface.

If we look at the binding library which is a dll that generated from the aar package, we will see in the dll the interface is there. Check below screenshot:

According to the current constructor of the CustomDatePicker class, we have to pass an instance of the Callback as the second parameter to it. But definitely we need to have the same implementation as the callback in Java, it should have different implementation for the onTimeSelected event.

I got some insights from my previous blog, and I decided to write a new class called Callback and make it a flexsible implementation in that class. I will make a constructor of that class which will determine whether it’s a DatePicker or TimerPicker and pass the TextView to it to set the text to correct TextView. Check the below implementation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class Callback : Java.Lang.Object, CustomDatePicker.ICallback
{
public bool mIsDatePicker { get; set; }
public bool mIsTimerPicker { get; set; }
public TextView mTextView { get; set; }

// Constructor
public Callback(TextView textView, bool isDatePicker, bool isTimerPicker)
{
mTextView = textView;
mIsDatePicker = isDatePicker;
mIsTimerPicker = isTimerPicker;
}

// Implement the interface method
public void OnTimeSelected(long p0)
{
if (mIsDatePicker)
{
mTextView.Text = DateFormatUtils.Long2Str(p0, false);
}
else if (mIsTimerPicker)
{
mTextView.Text = DateFormatUtils.Long2Str(p0, true);
}
}
}

Below is how we call it in our MainActivity.cs file:

1
2
3
4
5
6
7
8
9
10
11
12
13
private void InitDatePicker()
{
// ...
mDatePicker = new CustomDatePicker(this, new Callback(mTvSelectedDate, true, false), beginTimestamp, endTimestamp);
// ...
}

private void InitTimerPicker()
{
// ...
mTimerPicker = new CustomDatePicker(this, new Callback(mTvSelectedTime, false, true), beginTimestamp, endTimestamp);
// ...
}

We can see from the above, we implement the same feature as Java did in one class. And definitely this class can be developed more if the implementation is more complicated in Java side.

Conclusion

Java has lots of the features that will be hard to be transferred to C#, but do not be scared about that. We can always find some way to implement the same in our Xamarin project using C#.

Happy coding!

Xamarin.Forms - using Custom Renderer to customize the back button icon and text in Navigation Bar Know the different coding style between native Android and Xamarin.Android through one project
You need to set install_url to use ShareThis. Please set it in _config.yml.

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×