Search code examples
c#androidemaillistviewcustom-adapter

send email by clicking textview in customized listview with android Xamarin


I am facing errors trying to send email by clicking a textview field inside a listview with Xamarin, all related to the instance of the activity not being avaiable to call the email Intent.

I´ve tried different approaches, but no success at all. first I´ve tried to call a method inside the activity clas (i´ve used a method for that in adapter, but it did not work); so I´ve changed to try call the textview click event. In java it seems easily done with the expression :

if (mContext instanceof MyActivity) { methodCall() };

In C#, I've tried to use

if (mContext.GetType() == TypeOf(ListaVereadoresActivity))

but this does not work, And also, the presented solution in code below, trying to call the StartActivity(email);

ERROR: Unhandled Exception: Java.Lang.Exception: No Activity found to handle Intent { act=android.intent.action.SEND typ=message/rfc822 flg=0x10000000 (has extras) }

CODE SAMPLES:

[Activity(Label = "Vereadores")]
public class ListaVereadoresActivity : Activity
{
    List<Vereador> listaVer = new List<Vereador>();        

    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
        SetContentView(Resource.Layout.listaVereadores_layout);

        GenerateListaVereadores();
        ListView vereadorListView = FindViewById<ListView>(Resource.Id.lstVereadores2);
        vereadorListView.ItemClick += OnListItemClick;
        VereadorAdapter adapter = new VereadorAdapter(this, listaVer, this.ApplicationContext);
        vereadorListView.Adapter = adapter;          
    }

// not using anymore

    public  void SendEmail(String emailAdd)
    {
        var email = new Intent(Android.Content.Intent.ActionSend);
        email.SetType("message/rfc822");
        email.PutExtra(Android.Content.Intent.ExtraEmail, new string[] { emailAdd });
        StartActivity(email);
    }

    private void GenerateListaVereadores()
    {
        var azuaite = new Vereador();
        azuaite.Nome = "Azuaite";
        azuaite.Foto = Resource.Drawable.azuaite;
        azuaite.Email = "some@email.address";
        listaVer.Add(azuaite);

        var aleksander = new Vereador();
        aleksander.Nome = "Aleksander";
        aleksander.Foto = Resource.Drawable.aleksander;
        aleksander.Email = "some@email.address";
        listaVer.Add(aleksander);

        var dhony = new Vereador();
        dhony.Nome = "dhony";
        dhony.Foto = Resource.Drawable.dhony;
        dhony.Email = "other@email.address";
        listaVer.Add(dhony);
    }

    void OnListItemClick(object sender, AdapterView.ItemClickEventArgs e)
    {
        var listView = sender as ListView;
        var t = listaVer[e.Position];
        Toast.MakeText(this, t.Nome, ToastLength.Short).Show();
    }

my custom adapter:

public class VereadorAdapter : BaseAdapter
{
    private List<Vereador> vereadorList;
    Activity activity;
    protected Context mContext;

    public VereadorAdapter(Activity act, List<Vereador> v, Context appContext)
    {
        activity = act;
        vereadorList = v;
        mContext = appContext;
    }

    public override int Count
    {
        get { return vereadorList.Count; }
    }

    class ViewHolder : Java.Lang.Object
    {
       public TextView nomeVereadorTxt { get; set; }
       public TextView emailVereadorTxt { get; set; }
       public ImageView fotoVereadorImg { get; set; }
    }

    public override Java.Lang.Object GetItem(int position)
    {
        var vereador = (Vereador)vereadorList[position];
        return vereador;
    }

    public override long GetItemId(int position)
    {
       return 0;
    }

    public override View GetView(int position, View convertView, ViewGroup parent)
    {
        var item = vereadorList[position];
        ViewHolder holder;
        var view = convertView;
        if (view != null)
        {
            holder = view.Tag as ViewHolder;
        }
        else
        {
           holder = new ViewHolder();
           view = activity.LayoutInflater.Inflate(Resource.Layout.CustomView, parent, false);
           holder.nomeVereadorTxt = view.FindViewById<TextView>(Resource.Id.VereadorNome);
           holder.fotoVereadorImg = view.FindViewById<ImageView>(Resource.Id.VereadorFoto);
           holder.emailVereadorTxt = view.FindViewById<TextView>(Resource.Id.VereadorEmail);

           view.Tag = holder;
        }

        //setar as propriedades dos componentes
        holder.emailVereadorTxt.Text = item.Nome;
        holder.fotoVereadorImg.SetImageResource(item.Foto);
        holder.emailVereadorTxt.Text = item.Email;
        holder.emailVereadorTxt.Click += EmailVereadorTxt_Click;

        return view;
    }

    private void EmailVereadorTxt_Click(object sender, EventArgs e)
    {
        TextView tv = (sender as TextView);
        string mailAddress = tv.Text;
        Toast.MakeText(activity.BaseContext, mailAddress, ToastLength.Short).Show();

        var email = new Intent(Android.Content.Intent.ActionSend);
        email.AddFlags(ActivityFlags.NewTask);
        email.SetType("message/rfc822");
        email.PutExtra(Android.Content.Intent.ExtraEmail, new string[] { mailAddress });
        Application.Context.ApplicationContext.StartActivity(email);
    }      
}

here my custom view:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
android:background="@drawable/CustomSelector">
<ImageView
    android:id="@+id/VereadorFoto"
    android:layout_width="50dp"
    android:layout_height="50dp"
    android:layout_marginBottom="5dp"
    android:layout_marginLeft="5dp"
    android:layout_marginRight="5dp"
    android:layout_marginTop="5dp"
    android:src="@drawable/Icon" />
<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <TextView
        android:id="@+id/VereadorNome"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:paddingTop="5dp" />
    <TextView
        android:id="@+id/VereadorEmail"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="15sp"
        android:paddingTop="5dp" />
</LinearLayout>
</LinearLayout>

So, how is the right way to implement an send email action by clicking the email text?


Solution

  • I think you might be misinterpreting the error you're getting.

    When you try and start an activity on Android you send an intent, and the operating system tries to respond to that intent in the best way it can. If you set up the intent to have a specific activity subclass in mind, then it will open your activity subclass. However, if you set up the intent to have something more generic like an action, you leave it to the operating system's interpretation. Normally, this means it will try and find activities that have registered themselves as being able to handle that action intent.

    In this case, you are starting an activity with ACTION_SEND and the operating system is throwing an error because it can't find any activities that have registered themselves as being able to handle ACTION_SEND. Normally this means that the device (or emulator) you're running on doesn't have an email app installed.

    If you want to check with the operating system first to see if it can find an activity for an intent, you should use resolveActivity(intent) which will return null if it cannot find one.

    Hope this helps.