Forum Xamarin.Android
We are excited to announce that the Xamarin Forums are moving to the new Microsoft Q&A experience. Q&A is the home for technical questions and answers at across all products at Microsoft now including Xamarin!

We encourage you to head over to Microsoft Q&A for .NET for posting new questions and get involved today.

How to speed up creating objects deriving from Java.Lang.Object?

I need to generate a large list of objects for a ListView / GridView. From what I understand, these objects must derive from Java.Lang.Object. The time it takes to generate these objects is significant.

I created a simple test to see how long it takes to simply create 5000 objects that derive from Java.Lang.Object and compared it to creating 5000 objects that derive from System.Object.

public class MyJavaObject : Java.Lang.Object { }    
public class MyObject : System.Object { }

private void CreateObjects()
{
    var objectCount = 5000;

    var javaObjectsWatch = new Stopwatch();
    javaObjectsWatch.Start();
    for (int i = 0; i < objectCount; i++)
    {
        new MyJavaObject();
    }
    javaObjectsWatch.Stop();
    var javaObjectsCreationElapsed = javaObjectsWatch.Elapsed.TotalMilliseconds;
    Console.WriteLine($"{objectCount} java objects took {javaObjectsCreationElapsed} milliseconds");

    var objectsWatch = new Stopwatch();
    objectsWatch.Start();
    for (int i = 0; i < objectCount; i++)
    {
        new MyObject();
    }
    objectsWatch.Stop();
    var objectsCreationElapsed = objectsWatch.Elapsed.TotalMilliseconds;
    Console.WriteLine($"{objectCount} objects took {objectsCreationElapsed} milliseconds");
}

Running CreateObjects results in the following being written to console.

"5000 java objects took 4437.1033 milliseconds"

"5000 objects took 1.831 milliseconds"

It takes almost 4.5 seconds to create the MyJavaObjects, and not even a hundredth of a second for the MyObjects.

How can I get the creation of the MyJavaObjects to be closer to the efficiency of creating MyObjects?
Could there be a way to make a "single call" to create all of the java objects using a custom binding?

Best Answer

  • rmaciasrmacias USBeta, University ✭✭✭✭✭
    Accepted Answer

    No, you wouldn't need 5,000 View Holders. If you implemented the pattern correctly, then you should only be creating only the number of Views that fit onto a screen. For example, if only 5 list items fit on the screen, then the pattern will only create 5 view holders. As the user scrolls down the list view the view holders should get recycled between the 5 that were created. 5,000 should not be created.

    public override View GetView (int position, View convertView, ViewGroup parent)
    {
      MyViewHolder holder;
      var view = convertView;
    
      //This is where the recycling happens for the view holder
      //No need to create another ViewHolder if one already exists what can re-use
      if(view != null) 
        holder = view.Tag as MyViewHolder;
    
    
      if (holder == null) {
        //No view holder available for us to recycle, so we can create a new one
        //This should not happen 5,000 times, this should only happen N times, where N
        //is the number of items that can fit onto a device screen.
        holder = new MyViewHolder ();
        view = activity.LayoutInflater.Inflate (Resource.Layout.OptimizedItem, null);
        holder.Name = view.FindViewById<TextView> (Resource.Id.textView1);
        holder.Description = view.FindViewById<TextView> (Resource.Id.textView2);
        holder.Image = view.FindViewById<ImageView> (Resource.Id.imageView);
        view.Tag = holder;
      } 
    
      //Now that we have a view holder, we can bind our Model or ViewModel to
      //the view.
      holder.Name.Text = Names [position];
      holder.Description.Text = Descriptions [position];
      holder.Image.SetImageResource (Names [position].ToLower().Contains ("xamarin") ?
                     Resource.Drawable.hexagongreen :
                     Resource.Drawable.hexagopurple);
    
      return view;
    }
    

    Something sounds missing in your implementation. You don't have to post your exact code if it's proprietary, but you can post an example that shows how your implementation is creating 5,000 view holders. Also ViewModels and ViewHolders are two different patterns that serve different purposes, so I think there was a disconnect on the terminology we're using.

Answers

  • rmaciasrmacias USBeta, University ✭✭✭✭✭

    I need to generate a large list of objects for a ListView / GridView. From what I understand, these objects must derive from Java.Lang.Object.

    If you mean your underlying data for your ListView needs to be a decendant of Java.Lang.Object, then that is false. Only the Views are decendants from Java.Lang.Object. Something doesn't sound quite right. What does your adapter code look like?

  • MagneticLlamaMagneticLlama USMember ✭✭

    I'm not able to post any code right now, but I know that I'm taking advantage of the view Tag. Tag has to be of type Java.Lang.Object, and I'm currently assigning Tag to the view model within the GetView method of the adapter.

  • rmaciasrmacias USBeta, University ✭✭✭✭✭

    So are you using the ViewHolder pattern? As in creating a ViewHolder to recycle your view? Using the ViewHolder pattern is supposed to speed up your listview as it recycles your views so you don't have to re-create them 5,000 times in your case.

    When you get a chance, post up your code as it sounds like the implementation of the pattern might be missing something.

  • MagneticLlamaMagneticLlama USMember ✭✭
    edited March 2016

    That's correct, I am using the ViewHolder pattern. The 5000 objects are view models that are used to populate the recycled views.

    https://blog.xamarin.com/creating-highly-performant-smooth-scrolling-android-listviews/
    While the code I have isn't quite this simple, I am using the view models (what they call MyViewHolder) in the same way.

  • rmaciasrmacias USBeta, University ✭✭✭✭✭

    That might be the problem. You shouldn't be using your View Models. View Models should be platform independent. If you're sticking your views inside your view models, then it's not a view model any more by definition. It should be an abstract representation of your View, not your actual view itself. Refactor those views out of your view model, and create a view holder for your ListView. You can then bind your ViewModel to your ViewHolders by implementing the ViewHolder pattern correctly.

  • MagneticLlamaMagneticLlama USMember ✭✭
    edited March 2016

    Maybe I am misunderstanding how to do this pattern. What I am referring to as ViewModels is actually android specific information. I could rename this class to MyViewHolder, and I believe I would be using the ViewHolder pattern "correctly".

    If I have a list which contains 5000 entries, wouldn't I need 5000 ViewHolders? The data of these ViewHolders is then used to populate the recycled views.

    Edit - I forgot to post a relevant link in an earlier comment. https://blog.xamarin.com/creating-highly-performant-smooth-scrolling-android-listviews/

  • rmaciasrmacias USBeta, University ✭✭✭✭✭
    Accepted Answer

    No, you wouldn't need 5,000 View Holders. If you implemented the pattern correctly, then you should only be creating only the number of Views that fit onto a screen. For example, if only 5 list items fit on the screen, then the pattern will only create 5 view holders. As the user scrolls down the list view the view holders should get recycled between the 5 that were created. 5,000 should not be created.

    public override View GetView (int position, View convertView, ViewGroup parent)
    {
      MyViewHolder holder;
      var view = convertView;
    
      //This is where the recycling happens for the view holder
      //No need to create another ViewHolder if one already exists what can re-use
      if(view != null) 
        holder = view.Tag as MyViewHolder;
    
    
      if (holder == null) {
        //No view holder available for us to recycle, so we can create a new one
        //This should not happen 5,000 times, this should only happen N times, where N
        //is the number of items that can fit onto a device screen.
        holder = new MyViewHolder ();
        view = activity.LayoutInflater.Inflate (Resource.Layout.OptimizedItem, null);
        holder.Name = view.FindViewById<TextView> (Resource.Id.textView1);
        holder.Description = view.FindViewById<TextView> (Resource.Id.textView2);
        holder.Image = view.FindViewById<ImageView> (Resource.Id.imageView);
        view.Tag = holder;
      } 
    
      //Now that we have a view holder, we can bind our Model or ViewModel to
      //the view.
      holder.Name.Text = Names [position];
      holder.Description.Text = Descriptions [position];
      holder.Image.SetImageResource (Names [position].ToLower().Contains ("xamarin") ?
                     Resource.Drawable.hexagongreen :
                     Resource.Drawable.hexagopurple);
    
      return view;
    }
    

    Something sounds missing in your implementation. You don't have to post your exact code if it's proprietary, but you can post an example that shows how your implementation is creating 5,000 view holders. Also ViewModels and ViewHolders are two different patterns that serve different purposes, so I think there was a disconnect on the terminology we're using.

  • MagneticLlamaMagneticLlama USMember ✭✭

    I get it now :)
    Thank you very much for your help.

Sign In or Register to comment.