1

I have two Activities: 1. contains the listview (Activity1), 2. details of each row in the listview (Activity2).

When the user clicks on any row of the listview in Activity1, its respective details get displayed in Activity2 i.e. Activity2 is started. When the user edits some details in Activity2, all changes are saved to the server and when I return to Activity1 I am fetching the new(updated) list from the server and want to update the UI (listview) of Activity1. But this does not happen. I am doing the following to update the listview:

@Override
protected void onStart() {
    super.onStart();
    Toast.makeText(this, "onStart", Toast.LENGTH_LONG).show();
    PetService petService = FactoryMaker.getFactory(AppConstants.PET_SERVICE).getPetServiceImpl(AppConstants.PARSE_IMPL, this);
    //pets = petService.getPetList();
    //adapter = new PetListArrayAdapter(getApplicationContext(),R.layout.pet_list_item, pets);
    //petListView.setAdapter(adapter);

    pets = petService.getPetList();
    adapter.clear();
    adapter.addAll(pets);
    adapter.notifyDataSetChanged();

    if(pets.size()>0) {
        retrieve.setVisibility(View.INVISIBLE);
    }else{
        retrieve.setVisibility(View.VISIBLE);
    }
}

However if I set the adapter again(like the three lines I commented out), the listview gets updated as required but with notifyDataSetChanged(), its not working. I have followed all the questions for this problem but nothing seems to work. My adapter extends from ArrayAdapter. Please help!

My adapter implementation:

public class PetListArrayAdapter extends ArrayAdapter<Pet> {

     private final String TAG="PetListArrayAdapter";

     private List<Pet> pets = null;
     private Context applicationContext =null;

     public PetListArrayAdapter(Context context, int resource, List<Pet> petList) {
          super(context, resource, petList);
          pets = petList;
          applicationContext = context;
     }

     @Override
     public int getCount(){
          int size = 0;
          if(pets!=null) {
             size = pets.size();
          }
          return size+1;
     }

     @Override
     public int getItemViewType(int position) {
          return (position == 0) ? 0 : 1;
     }

     @Override
     public int getViewTypeCount() {
          return 2;
     }


     @Override
     public View getView(int position, View convertView, ViewGroup parent)  {
         Log.d(TAG, "getView for position" + position);
         int type = getItemViewType(position);
         LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         if(convertView==null) {
              if(type==1) {
                  convertView = inflater.inflate(R.layout.pet_list_item, null);
                  TextView t = (TextView)convertView.findViewById(R.id.petName);
                  final Pet pet = pets.get(position-1);
                  Log.d(TAG, "pet:" + pet);
                  t.setText(pet.getName());

                  ImageView petImage =(ImageView)convertView.findViewById(R.id.petImage);

                  String imageUrl = pet.getThumbnailUrl();
                  //if(petImage.getDrawable()==null) {
                  if (imageUrl != null) {
                       Log.d(TAG, "Loading Image for position" + position);
                       new ImageDownloader(petImage).execute(imageUrl);
                  }
             /*}else{
             Log.d(TAG, "Image present for position" + position);
             }*/
          }else if (type==0){
               convertView = inflater.inflate(R.layout.add_pet, null);
          }
       }

       return convertView;
   }
}
Andrei T
  • 2,985
  • 3
  • 21
  • 28
I.shL
  • 769
  • 2
  • 8
  • 16
  • First of all, is the request on a background thread or ui thread? Second of all, what is the adapter implementation, ca you show it? – Andrei T Jun 03 '16 at 11:20
  • The request is on the UI thread. – I.shL Jun 03 '16 at 11:39
  • How a request to a server can be on UI thread I do not get it. – Andrei T Jun 03 '16 at 12:47
  • @AndreiT I am using Parse cloud for my backend. To fetch the data from it I used ParseQuery.find() which does block the calling thread as written in parse documentation and I am calling it from the main thread. – I.shL Jun 03 '16 at 13:24
  • Debug the app and see if there is a difference between the values you add and the values you have. – Andrei T Jun 03 '16 at 14:40
  • @AndreiT the values are getting saved correctly I have checked that. Everything is working as expected (with correct values) when I set the adapter again every time I need to update the list but the problem arises when I try to call notifyDataSetChanged instead of setting the adapter again. – I.shL Jun 03 '16 at 16:04
  • I do not really get this add pet layout. What exactly do you want to achieve. What is the use case? – Andrei T Jun 03 '16 at 17:10

4 Answers4

0

Try

pets.clear();
pets.addAll(petService.getPetList());
adapter.notifyDataSetChanged();

I guess the adapter list looses its link to the actual list.

Dominik Vincenz
  • 445
  • 3
  • 10
0

Add your fetching code in on resume

@Override
    protected void onResume() {
        super.onResume();

        pets = petService.getPetList();
        adapter.clear();
        adapter.addAll(pets);
        adapter.notifyDataSetChanged();

        if(pets.size()>0) {
            retrieve.setVisibility(View.INVISIBLE);
        }else{
            retrieve.setVisibility(View.VISIBLE);
        }
    }
Pavya
  • 6,015
  • 4
  • 29
  • 42
0
  1. First of, Start Activity2 using the startActivityForResult(intent,requesCode) instead of the startActivity(intent) method.
  2. Override/implement the onActivityResult(int requestCode, int resultCode, Intent data) of Activity1 and execute these codes. This will ensure that onBackPressed your list gets updated

    pets.clear(); pets.addAll(petService.getPetList()); adapter.notifyDataSetChanged();

so your codes will look like

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    //...some codes

    pets.clear();
    pets.addAll(petService.getPetList());
    adapter.notifyDataSetChanged();

}
Akinola Olayinka
  • 841
  • 7
  • 11
0


I tested with this adapter and it works on my side. However, I did not have images attached but it should be working fine.

public class CustomArrayAdapter extends ArrayAdapter<Pet> {
    private final String TAG = "PetListArrayAdapter";

    private List<Pet> pets = null;

    public CustomArrayAdapter(Context context, List<Pet> petList) {
         super(context, 0, petList);
         pets = petList;
    }

    @Override
    public int getCount() {
        int size = 0;
        if (pets != null) {
            size = pets.size() + 1;
        }
        return size;
    }

    @Override
    public int getItemViewType(int position) {
         return (position == 0) ? 0 : 1;
    }

    @Override
    public int getViewTypeCount() {
         return 2;
    }


    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
         Log.d(TAG, "getView for position" + position);
         ViewHolder holder;
         int type = getItemViewType(position);
         LayoutInflater inflater = LayoutInflater.from(getContext());
         if (convertView == null) {
             holder = new ViewHolder();
             if (type == 1) {
                 convertView = inflater.inflate(R.layout.list_item_layout, null);
                 holder.tvName = (TextView) convertView.findViewById(R.id.tv_name);
                 holder.tvDescription = (TextView) convertView.findViewById(R.id.tv_descriotion);
                 final Pet pet = pets.get(position - 1);
                 Log.d(TAG, "pet:" + pet);

                convertView.setTag(holder);
             } else if (type == 0) {
                  convertView = inflater.inflate(R.layout.list_add_layout, null);
                  holder.tvName = (TextView) convertView.findViewById(R.id.tv_add);
             }
        } else {
             holder = (ViewHolder) convertView.getTag();
        }
        if (holder != null) {
             if (type == 1) {
                 holder.tvName.setText(pets.get(position - 1).getName());
                 if (holder.tvDescription != null) {
                    holder.tvDescription.setText(pets.get(position - 1).getDescription());
                 }
             } else if (type == 0) {
                 holder.tvName.setText("Add new pet");
             }
         }

         return convertView;
     }
     static class ViewHolder {
         TextView tvName;
         TextView tvDescription;
     }
 }

I must add that you need to have a proper holder to handle the add pet layout and the layout for pets. What I added here it is just a starting point for you. I would create base holder containing one textview or nothing and use specific holders for specific types and you cast to the right holder whenever it is type 1 or 0.

Andrei T
  • 2,985
  • 3
  • 21
  • 28