• 7
name

A PHP Error was encountered

Severity: Notice

Message: Undefined index: userid

Filename: views/question.php

Line Number: 191

Backtrace:

File: /home/prodcxja/public_html/questions/application/views/question.php
Line: 191
Function: _error_handler

File: /home/prodcxja/public_html/questions/application/controllers/Questions.php
Line: 433
Function: view

File: /home/prodcxja/public_html/questions/index.php
Line: 315
Function: require_once

I use LiveData + Transformations.map() :

private final LiveData<List<Task>> observableTasks;
(...)
observableTasks =  Transformations.map(tasksRepository.getTasks(), tasks-> filterTasks(tasks));

How to force LiveData to refresh? I need Transformations.map() to prepare new list. When the user changes filtering options I need to call filterTasks(tasks) again and show new, sorted list. Data coming from the repository (tasksRepository.getTasks()) stays the same.

    • By using private final LiveData> observableTasks = Transformations.map(dataList, this::addOne); I'm able to get new values every time I change the values.
      • 2
    • I need call filterTasks(tasks) again because user changed filtering order. Data coming form the repository stays the same.
      • 1
    • It can be for example function changeFilteringOrderTo(EnumFilterOrder enumFilterOrder), then filterTasks uses enumFilterOrder field to decide what to do with the list.

Based on the information you have provided, I did following steps, and my observable got triggered as expected. I think you're doing something wrong either in repository or in class where you handle the transformation. As there's not enough code to check, I created my own dummy classes:

  1. I created dummy Task POJO:
public class Task {
    private String id;

    public Task(String id) {
        this.id = id;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @NonNull
    @Override
    public String toString() {
        return "Task id is " +id;
    }
}
  1. I created dummy repository which has LiveData:
public class TasksRepository {
    private List<Task> taskList = new ArrayList<>();
    private MutableLiveData<List<Task>> _tasks = new MutableLiveData<>();
    private LiveData<List<Task>> tasks = _tasks;

    public TasksRepository() {
        for (int i = 0; i < 5; i++) {
            taskList.add(new Task(createTaskId()));
        }
        _tasks.setValue(taskList);
    }

    private String createTaskId() {
        return UUID.randomUUID().toString();
    }

    public void addTask() {
        taskList.add(new Task(createTaskId()));
        _tasks.setValue(taskList);
    }

    public LiveData<List<Task>> getTasks() {
        return tasks;
    }
}
  1. Created class called MyViewModel which can handle transformation. During transformation we just add "TEST" prefix to task id. You can compare it with your code and it should be fine:
public class MyViewModel {
    private final LiveData<List<Task>> observableTasks;

    public MyViewModel(TasksRepository tasksRepository) {
        this.observableTasks = Transformations.map(tasksRepository.getTasks(), this::changeId);
    }

    private List<Task> changeId(List<Task> tasks) {
        List<Task> resultTaks = new ArrayList<>();
        for (Task task : tasks) {
            String newId = "TASK" + task.getId();
            task.setId(newId);
            resultTaks.add(task);
        }
        return resultTaks;
    }

    public LiveData<List<Task>> getObservableTasks() {
        return observableTasks;
    }
}
  1. Add data on when button clicked and observe data changes:
TasksRepository tasksRepository = new TasksRepository();
MyViewModel viewModel = new MyViewModel(tasksRepository);

button.setOnClickListener(v -> tasksRepository.addTask());

viewModel.getObservableTasks().observe(this,
        tasks -> Log.d(TAG, Arrays.toString(new List[]{tasks})));
  • 1
Reply Report
      • 2
    • When the user change filter option, nothing changes in the repository, so transformation and filterTasks is not called. Check my answer.

I think I found the solution. I created additional LiveData field filterChangeEvent. Every time the user changes filtering order, new value is set to filterChangeEvent. Then I use switchMap with filterChangeEvent as a trigger:

    observableTasks = Transformations.switchMap(filterChangeEvent, input -> {
        final MediatorLiveData<List<Tasks>> result = new MediatorLiveData<>();
        result.addSource(tasksRepository.getTasks(), tasks -> result.setValue(filterTasks(tasks)));
        return result;
    });
  • 0
Reply Report

Checkout Transformation.switchMap. It explains following case when to use it also.)

Scenario:

In a scenario where the repository contains User(1, "Jane") and User(2, "John"), when the userIdLiveData value is set to "1", the switchMap will call getUser(1), that will return a LiveData containing the value User(1, "Jane"). So now, the userLiveData will emit User(1, "Jane"). When the user in the repository gets updated to User(1, "Sarah"), the userLiveData gets automatically notified and will emit User(1, "Sarah").

When the setUserId method is called with userId = "2", the value of the userIdLiveData changes and automatically triggers a request for getting the user with id "2" from the repository. So, the userLiveData emits User(2, "John"). The LiveData returned by repository.getUserById(1) is removed as a source.

  • 0
Reply Report