skip to Main Content

I am a newbie in Flutter and I am trying to build an app using Provider. I will try to provide an oversimplified example here. My app includes a model of a room.

class Room {
String roomDisplayName;
String roomIdentifier;
Image image;
List<IDevices> devices = [];

Room(this.roomDisplayName, this.roomIdentifier, this.image, this.devices);
}

Rooms have list of devices like a temperature sensor

class TempSensor implements IDevices {
late String tempSensorName;
late double temperatureValue;
late double humidityValue;
late int battery;

TempSensor(this.displayName, this.zigbeeFriendlyName);

UpdateTempSensor(double temperature, double humidiy, int battery) {
  this.temperatureValue = temperature;
  this.humidityValue = humidiy;
  this.battery = battery;
}

I have a RoomProvider class that implements ChangeNotifier that is responsible for updating devices in List<Room> rooms

class RoomsRepositoryProvider with ChangeNotifier {

List<Room> get rooms {
//return _rooms;
return _rooms;
}

  UpdateTemperatureSensor(TempSensor tempSensor) {
  TempSensor? foundTempSensor = null;
  _rooms.forEach((room) {
    room.devices.forEach((element) {
      if (element.displayName == tempSensor.displayName) {
        foundTempSensor = element as TempSensor;
      }
    });
  });
  if (foundTempSensor != null) {
    foundTempSensor?.UpdateTempSensor(tempSensor.temperatureValue,
        tempSensor.humidityValue, tempSensor.battery);
    notifyListeners();
  }
}

I also have a Stateful widget page to show Room information like temperature/humidity value.

class DetailPage extends StatefulWidget {
final Room room;

DetailPage({required this.room});

@override
_DetailPageState createState() => _DetailPageState();
}

class _DetailPageState extends State<DetailPage> {
@override
Widget build(BuildContext context) {
context.watch<RoomsRepositoryProvider>().rooms;
return Text ("Temperature is ${widget.room.devices[0].temperatureValue}");
}

Here is question:

The problem I am facing is that, if I am showing the Living Room in DetailPage and the temperature sensor from Bedroom gets updated in the List<Room> rooms, the whole DetailPage gets rebuild. Since it is not an issue in the flutter and the app works good. I would still like to know how to solve this architecture problem, that the DetailPage only gets build for the room updates related to the room being shown?

PS: please ignore any build, indentation or naming convention mistakes.

3

Answers


  1. Chosen as BEST ANSWER

    So, I solved my problem by creating a separate provider DevicesProvider that contains the list of devices modified in the room. I provide the current room by calling the method SetCurrentRoom(String currentRoomIdentifier) from the DetailPage and the provider does its job whenever the devices list in the current room updates.

    class DevicesProvider with ChangeNotifier {
    String _currentRoomIdentifier = "";
    
    List<IDevices> _listCurrentRoomDevices = [];
    
    List<IDevices> get ListCurrentRoomDevices => _listCurrentRoomDevices;
    
    void SetCurrentRoom(String currentRoomIdentifier) {
      _currentRoomIdentifier = currentRoomIdentifier;
    }
    
    UpdateDevicesList(IDevices device) {
        if (serviceLocator<RoomProviderService>()
            .rooms
            .any((room) => room.roomIdentifier == _currentRoomIdentifier)) && 
             IsDeviceUpdateComingFromCurrentRoom(device)
          {
            _listCurrentRoomDevices.clear();
            var devices = serviceLocator<RoomProviderService>()
                .rooms
                .firstWhere(
                    (room) => room.roomIdentifier == _currentRoomIdentifier)
                .devices;
            _listCurrentRoomDevices.addAll(devices);
            notifyListeners();
          }
       }
    
    bool IsDeviceUpdateComingFromCurrentRoom(IDevices device) {
      bool isUpdateFromCurrentRoom = false;
      if (device.Name.contains(_currentRoomIdentifier)) {
        isUpdateFromCurrenRoom = true;
      }
      return isUpdateFromCurrentRoom;
      }
    }
    

    Maybe this can be solved in a different way which is more elegant or efficient, but for now my problem is solved with this approach.


  2. To only rebuild the specific widget, you can wrap that widget inside Consumer widget provider by Provider in flutter. Consumer takes a builder function and will build the widget returned by this builder function only when the data changes.

    Consumer(
       builder:(context,_,__){
         return Container();
      },
    ),
    
    Login or Signup to reply.
  3. To implement this, you can use a Comsumer widget

    Consumer<RoomsRepositoryProvider>(
    builder:(context,value,child) => Text("Temperature is ${value.room}");
    ),
    

    A StatelessWidget is also sufficient. Don’t forget the index by room. It should work like this

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search