Search code examples
androidandroid-intentandroid-recyclerviewonclicklistenerandroid-viewholder

How to fetch new data from an activity that was launched through an Intent?


This is a bit of a complicated problem. In the ViewHolder of my RecyclerView's custom adapter, I've implemented an onClickListener and through the onClick, I'm passing an intent that fires up EditItemActivity with text and recyclerview list item position as extras. In the EditItemActivity, I have a TextView that has the text that was passed from an intent and a "Save Changes" button. That text belonged to a specific list item in my Recyclerview list. After I change the text, I want the app to go back to the main screen with the list and have that specific item updated with the new text.

So far, here what I was able to successfully implement:

  1. EditItemActivity launches whenever a list item is clicked.
  2. When the activity launches, it's textview has the same text as the list-item whose onClick launched the activity.

What I want to add:

  • When I change the text in the EditItemActivity and click the "Save Changes" button, it updates the text of that same list item.

Here is my implementation. This is ViewHolder in my adapter that houses the onClick:

public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
        TextView todoView;

        public ViewHolder(View itemView) {
            super(itemView);
            itemView.setOnClickListener(this);
            todoView = itemView.findViewById(R.id.to_do_display);
        }

        @Override
        public void onClick(View view) {
            Toast.makeText(context, "position = " + getAdapterPosition(), Toast.LENGTH_SHORT).show();
            Intent intent = new Intent(context, EditItemActivity.class);
            intent.putExtra("data", todoView.getText());
            intent.putExtra("position", getAdapterPosition());
            context.startActivity(intent);
        }
    }

And this was my attempt that updating the text of that list item:

public class EditItemActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_edit_item);

        final ToDoData toDoData = new ToDoData(this);
        final ToDoAdapter toDoAdapter = new ToDoAdapter(this);

        final EditText editToDo = (EditText)findViewById(R.id.edit_todo_item);
        Button button = (Button)findViewById(R.id.save_changes);
        final String text = getIntent().getExtras().getString("data");
        final String position = getIntent().getExtras().getString("position");
        editToDo.setText(text);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(editToDo.getText().toString() != text){
                    toDoData.setToDo(editToDo.getText().toString());
                    toDoAdapter.notifyDataSetChanged();
                    finish();
                }
            }
        });
    }
}

ADDING CODE PER REQUEST

Code for the class that has the listview:

public class MainActivity extends AppCompatActivity {

    private List<ToDoData> toDoList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final ToDoAdapter toDoAdapter = new ToDoAdapter(toDoList, this);

        final EditText toDoInput = (EditText)findViewById(R.id.add_todo);
        Button toDoAdd = (Button)findViewById(R.id.add_item);

        RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
        RecyclerView toDoDisplay = (RecyclerView) findViewById(R.id.toDoDisplayRecyclerView);
        toDoDisplay.setAdapter(toDoAdapter);
        toDoDisplay.setHasFixedSize(true);
        toDoDisplay.setLayoutManager(layoutManager);


        toDoAdd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ToDoData newToDoData = new ToDoData(MainActivity.this);
                newToDoData.setToDo(toDoInput.getText().toString());
                toDoList.add(newToDoData);
                toDoAdapter.notifyDataSetChanged();
                toDoInput.setText("");
            }
        });
    }
}

Code for the adapter:

public class ToDoAdapter extends RecyclerView.Adapter<ToDoAdapter.ViewHolder> {

    private List<ToDoData> toDoList;
    private Context context;

    public ToDoAdapter(List<ToDoData> todoList, Context context) {
        this.toDoList = todoList;
        this.context = context;
    }

    public ToDoAdapter(Context context){}

    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
        TextView todoView;

        public ViewHolder(View itemView) {
            super(itemView);
            itemView.setOnClickListener(this);
            todoView = itemView.findViewById(R.id.to_do_display);
        }

        @Override
        public void onClick(View view) {
            Toast.makeText(context, "position = " + getAdapterPosition(), Toast.LENGTH_SHORT).show();
            Intent intent = new Intent(context, EditItemActivity.class);
            intent.putExtra("data", todoView.getText());
            intent.putExtra("position", getAdapterPosition());
            context.startActivity(intent);
        }
    }

    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.to_do_list_item, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position){
        ToDoData todoPosition = toDoList.get(position);

        holder.todoView.setText(todoPosition.getToDo());
    }

    @Override
    public int getItemCount() {
        return (toDoList == null) ? 0 : toDoList.size();
    }
}

ToDoData.class

public class ToDoData implements Serializable{
    private String toDoString;

    public ToDoData(String todoString){
        this.toDoString = todoString;
    }

    public ToDoData(Context context){}

    public String getToDo() {
        return toDoString;
    }

    public void setToDo(String toDoString) {
        this.toDoString = toDoString;
    }
}

Solution

    1. Make your ToDoData class implement Serializable.

      public class ToDoData implements Serializable{}
      
    2. Now, pass the List<ToDoData> into the EditItemActivity along with the positon and data through Intent as:

      Intent intent = new Intent(MainActivity.this, EditItemActivity.class);
      intent.putExtra("data", todoView.getText());
      intent.putExtra("position", getAdapterPosition());
      //along with data and position, we are passing the list as well.
      intent.putExtra("LIST", (Serializable) toDoList); //this 'list' is your toDoList that you pass to the adapter (and gets populated into the view)
      startActivity(intent);
      
    3. Now, inside your EditItemActivity,

      Receive the list from the intent as:

      Intent i = getIntent();
      list = (List<ToDoData>) i.getSerializableExtra("LIST");
      

      And set the listener for button click as,

      toDoAdd.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View view) {
              // set the new input of user from toDoInput into the list 
              list.set(position, *object_of_ToDoData_with_updated_user_input*);
              startActivity(new Intent(EditItemActiviy.this, MainActivity.class));
      
          }
      });
      
    4. Inside MainActivity,

      @Override
      protected void onResume() {
          super.onResume();
          toDoAdapter.notifyDataSetChanged();
      
      }