Xamarin.Android vs. Native Android - How you implement Java Listener in C#

It’s really important for engineers who use Xamarin to develop Android app to know how to transfer Java code to C# code.

Recently I am trying to implement something in Xamarin.Android project (Not Forms) and I encountered lots of issues.

What I can find online is mostly Android native documents from Google. And I do find one sample project from Google that is implemented in Android Studio using Java.

So what I have to do is to understand how to transfer Java code to C# code, otherwise you will find it quite difficult to use pure Xamarin.Android project.

What’s the difficulty?

Although we always have a concept that Java has almost 80% simility with C#, maybe more. However, there are still lots of things that are different.

In this blog, I will use a Xamarin sample to demonstate how I transferred Java’s event handler which is also known as Listener to C#’s event handler.
Also, I will show you in Xamarin.Android, how it’t different in Xamarin.Android and native Android for setting value for fields.

Events Handler transfer

First I will talk about Event Handler in Java and C#.

We all know that in Java, it will always use setXXXX to provide implementation or values for event or fields.

However, the tricky thing is that: in one Android activity, on the UI, you might have multiple same UI controls that have the same events to implement.

Assume that I have the below UI code:

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
<LinearLayout
android:id="@+id/width_input_area"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_medium"
android:layout_marginBottom="@dimen/margin_medium"
android:layout_marginStart="@dimen/margin_large"
android:layout_marginEnd="@dimen/margin_large">

<TextView
android:id="@+id/width_seekbar_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/margin_small"
android:text="@string/width"
android:textColor="@color/accent"
android:textSize="12sp" />

<LinearLayout
android:id="@+id/width_seekbar_area"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

<SeekBar
android:id="@+id/seek_bar_width"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />

<TextView
android:id="@+id/textview_width"
android:layout_height="wrap_content"
android:layout_width="80dp"
android:layout_marginStart="@dimen/margin_small"
android:layout_marginLeft="@dimen/margin_small"
android:textSize="16sp"
android:gravity="end" />
</LinearLayout>
</LinearLayout>

<LinearLayout
android:id="@+id/weight_input_area"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_medium"
android:layout_marginBottom="@dimen/margin_medium"
android:layout_marginStart="@dimen/margin_large"
android:layout_marginEnd="@dimen/margin_large">

<TextView
android:id="@+id/weight_seekbar_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/margin_small"
android:text="@string/weight"
android:textColor="@color/accent"
android:textSize="12sp" />

<LinearLayout
android:id="@+id/weight_seekbar_area"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

<SeekBar
android:id="@+id/seek_bar_weight"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />

<TextView
android:id="@+id/textview_weight"
android:layout_height="wrap_content"
android:layout_width="80dp"
android:layout_marginStart="@dimen/margin_small"
android:layout_marginLeft="@dimen/margin_small"
android:textSize="16sp"
android:gravity="end" />
</LinearLayout>
</LinearLayout>

If you used the Android designer, you will see something like this UI:

We can see that we have 2 SeekBar here and they both have the same behavior: when you move the point, the value of the text behind it should change accordingly.

Therefore, we are going to implement their onProgressChanged event.

Implementation

In the code that I refer to, it’s as the below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// ...

mWidthSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){
@override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser){
widthTextView
.setText(String.valueOf(progressToWidth(progress)));
}

@override
public void onStartTrackingTouch(SeekBar seekBar){

}

@override void onStopTrackingTouch(SeekBar seekBar){

}
});
// ...

We can see from the above code. In Java or native Android development, the event is created by calling the setXXXXListener method and pass a newly instanted Listener instance into it. Then, you can override whatever events you’d like to implement within that Listener.

However, in C#, we do not have this kind of Listener, we can use event handler or delegates to do the same thing. In C#, the event is binding to the object as a Property.

So, if we are going to implement the same as the above Java code, we can do like below:

1
2
3
4
5
6
7
8
widthSeekBar.ProgressChanged += WidthSeekBar_ProgressChanged;
widthSeekBar.StartTrackingTouch += (o, e) => { };
widthSeekBar.StopTrackingTouch += (o, e) => { };

private void WidthSeekBar_ProgressChanged(object sender, SeekBar.ProgressChangedEventArgs e)
{
widthTextView.Text = e.Progress.ToString();
}

Done. And if you use VS Intelligence, you will also see when you are writing widthSeekBar.ProgressChanged +=, there will be some hint for you. You can simply press Tab and the method structure in the above code will be generated automatically for you. What is really good is that the name is also intelligent, it starts with WidthSeekBar.

Other similar point of this article

What I want to share here is that, the above apporach is almost everywhere between Java and C#.

For example, if you declare a field in Java, then each time you want to modify the value of that field, you have to call setXXXX() method to that object.

On the other hand, C# always implement the same as Properties.

Check below Java code:

1
2
3
4
5
6
7
8
public class Person
{
private String name;
public void setName(String name)
{
this.name = name;
}
}

Then you will modify the value like this:

1
2
Person p = new Person();
p.setName("Allen");

But in C#, you will do like this:

1
2
3
4
public class Person
{
public string Name {get;set;}
}

Then you do like this:

1
2
Person p = new Person();
p.Name = "Allen";

This is a very useful pattern when you are transferring Java to C#.

Hope this will help.

Know the different coding style between native Android and Xamarin.Android through one project Broken AVD System Path - AVD Manager failed to run Android Emulator
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

×