0

I'm not certain if I'm asking this question correctly, because I can't find any information on it at all.

I'd like to know if it's possible to target a view (ImageView) from my Activity that has been added through an ArrayAdapter.

My Activity receives JSON from the server, regarding the user's profile. I display that information into an ArrayAdapter. Within the ArrayAdapter, I have an ImageView that calls a method to change the User's profile image. The user chooses his/her image, and finally, the ImageView changes accordingly.

The problem is I can't actually target the ImageView. Below is my code:

Profile Activity:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_my_profile);

    userAdapter = new UserAdapter(this, new ArrayList<UserModel>());
    listView = (ListView) findViewById(R.id.myProfile_header);
    listView.setAdapter(userAdapter);

    LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    (new FetchUserTask()).execute(Constants.HOST + token.getAccessToken());

    image = (ImageView) findViewById(R.id.myProfile_avatar);
    avatarChange = (LinearLayout) findViewById(R.id.myProfile_avatar_change);
}

public String uriToPath(Uri uri) {
    String res = null;
    String[] proj = { MediaStore.Images.Media.DATA };
    Cursor cursor = getContentResolver().query(uri, proj, null, null, null);
    if(cursor.moveToFirst()){
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        res = cursor.getString(column_index);
    }
    cursor.close();
    return res;
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (data != null && (requestCode == SELECT_IMAGE_CODE || requestCode == CAMERA_IMAGE)) {

        Uri uri = Uri.parse("file://"+uriToPath(data.getData()));
        Picasso.with(this).load(uri).into(image);
    }

    /*...*/

}

 

ProfileAdapter:

/*...*/

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View v = convertView;
    if (v == null) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        v = inflater.inflate(R.layout.profile_header, null);
    }

    final ViewHolder viewHolder = new ViewHolder(v);
    v.setTag(viewHolder);

    final UserModel model = user.get(position);
    String userAvatar = model.getPhoto();

    viewHolder.name.setText(model.getUsername());
    viewHolder.email.setText(model.getEmail());
    viewHolder.phone.setText(model.getPhone_number());


    if (userAvatar != null && !userAvatar.isEmpty()) {
        //System.out.println(userAvatar);
        Picasso.with(getContext()).load(HOST+userAvatar).into(viewHolder.avatar);
    }

    viewHolder.avatarChange.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            selectImageFromGallery();
        }
    });

    return v;
}

public void selectImageFromGallery() {
    final CharSequence[] items = { "Take Photo", "Choose from Library",
            "Cancel" };

    AlertDialog.Builder builder = new AlertDialog.Builder(context);
    builder.setTitle("Add Photo!");
    builder.setItems(items, new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int item) {
            if (items[item].equals("Take Photo")) {
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                File f = new File(android.os.Environment
                        .getExternalStorageDirectory(), "temp.jpg");
                intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
                ((Activity) context).startActivityForResult(intent, CAMERA_IMAGE);
            } else if (items[item].equals("Choose from Library")) {
                Intent intent = new Intent(
                        Intent.ACTION_PICK,
                        android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                intent.setType("image/*");
                ((Activity) context).startActivityForResult(
                        Intent.createChooser(intent, "Select File"),
                        SELECT_IMAGE_CODE);
            } else if (items[item].equals("Cancel")) {
                dialog.dismiss();
            }
        }
    });
    builder.show();
}

/*...*/
ABCaesar
  • 112
  • 2
  • 9
  • 1
    Have you tried calling `notifyDataSetChanged()` on the adapter after the user selects a profile image? – John P. Mar 12 '15 at 20:19
  • @JohnP. `notifyDataSetChanged()` only works on when using `.add()`, `.remove()`, etc. I don't think that would help me here. Can you possibly explain in greater detail? – ABCaesar Mar 12 '15 at 20:57
  • 2
    @ABCaesar actually, John P is right. That's exactly what it's for. It's telling your ArrayAdapter that your DataSet has changed (which it has) and that it needs to redraw all the Views (which will end up calling your getView method). If calling notifyDataSetChanged() doesn't update your View, then you're not actually updating the Object backed by the ArrayAdapter. – Cruceo Mar 12 '15 at 21:02
  • 1
    @ABCaesar I was reading the following post the other day: http://stackoverflow.com/a/12234498/1309401 The poster says that calling `notifyDataSetChanged()` calls `getView()` on all of the items shown which would solve your problem since you do your logic in the `getView()` method. – John P. Mar 12 '15 at 21:03
  • OK, I'll give it a shot as soon as I arrive at a terminal. Thanks guys. – ABCaesar Mar 12 '15 at 21:15

1 Answers1

0

I have to thank John P. and Guardanis for the major clue as to why I couldn't target the ListView's inner child. It helped changed the way I thought about the problem itself. I thought the problem was in the Adapter, but it became clear after their suggestions that it was in the Activity.

Code change is essentially:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (data != null && (requestCode == SELECT_IMAGE_CODE || requestCode == CAMERA_IMAGE)) {
        Uri imageUri = data.getData();
        View child = header.getChildAt(0);
        View image = child.findViewById(R.id.myProfile_avatar);
        Resources resources = getResources();
        ImageView imageX = (ImageView) image;

        imageX.setImageDrawable(resources.getDrawable(R.drawable.blank));
        Picasso.with(this).load(imageUri).into(imageX);
        profileAdapter.notifyDataSetChanged();
    }
}

With this, I was able to access the View I needed with ListView.getChild(int), where "header" is my ListView and 0 being my integer. Then declaring the View (child) as an ImageView, I was able to manipulate its attributes the way I wanted to. Finished off with notifyDataStateChanged() on my adapter to ensure that the change would incur.

Side note: I needed to invoke getResources() to alter to my ImageView. Not quite sure what that's about, I'll look into it in the future.

Community
  • 1
  • 1
ABCaesar
  • 112
  • 2
  • 9