본문 바로가기

개발하자

Flater - 데이터가 변경될 때 getx 컨트롤러가 업데이트되지 않음

반응형

Flater - 데이터가 변경될 때 getx 컨트롤러가 업데이트되지 않음

나는 5페이지짜리 하단 네비게이션 바가 있는 앱을 개발하고 있다. 나는 getx를 사용한다. 첫 페이지에, 나는 데이터를 나열하고 있다. 문제는 내가 데이터베이스에서 수동으로 데이터(하단 탐색 모음의 첫 페이지)를 변경하고 페이지를 넘겼을 때 첫 페이지로 돌아왔을 때 변경 사항을 볼 수 없다는 것이다.

컨트롤러

class ExploreController extends GetxController {
  var isLoading = true.obs;
  var articleList = List<ExploreModel>().obs;

  @override
  void onInit() {
    fetchArticles();
    super.onInit();
  }

  void fetchArticles() async {
    try {
      isLoading(true);
      var articles = await ApiService.fetchArticles();
      if (articles != null) {
        //articleList.clear();
        articleList.assignAll(articles);
      }
    } finally {
      isLoading(false);
    }
    update();
  }
}

그리고 내 UI;

body: SafeArea(
        child: Column(
        children: <Widget>[
          Header(),
          Expanded(
            child: GetX<ExploreController>(builder: (exploreController) {
              if (exploreController.isLoading.value) {
                return Center(
                  child: SpinKitChasingDots(
                      color: Colors.deepPurple[600], size: 40),
                );
              }
              return ListView.separated(
                padding: EdgeInsets.all(12),
                itemCount: exploreController.articleList.length,
                separatorBuilder: (BuildContext context, int index) {



 GetX< ExploreController >(builder: (controller) {
        if (controller.isLoading.value) {
          return Center(
            child: SpinKitChasingDots(
                color: Colors.deepPurple[600], size: 40),);
        }
        return ListView.separated(
            padding: EdgeInsets.all(12),
            itemCount: controller.articleList.length,
            separatorBuilder: (BuildContext context, int index) {});
      });



GetBuilder는 관찰 가능한 변수를 위한 것이 아니기 때문에 여기에 필요하지 않습니다. 또한 GetBuilder 및 관찰할 수 없는 변수에서만 사용하기 때문에 fetchArtics 함수의 update()를 호출할 필요도 없습니다.

따라서 동일한 컨트롤러를 따르는 UI(GetBuilder 및 Obx)를 업데이트하기 위한 2개의 위젯이 있으며 OBX만 있으면 됩니다. Rahuls가 응답합니다. 또는 Obx를 그대로 두고 GetBuilder를 제거하고 빌드 메서드의 시작 부분에서 컨트롤러를 선언하고 초기화할 수 있습니다.

final exploreController = Get.put(ExploreController());

그런 다음 OBX 위젯에서 초기화된 컨트롤러를 Expanded의 하위로 사용합니다.


Obx(() => exploreController.isLoading.value
          ? Center(
              child:
                  SpinKitChasingDots(color: Colors.deepPurple[600], size: 40),
            )
          : ListView.separated(
              padding: EdgeInsets.all(12),
              itemCount: exploreController.articleList.length,
              separatorBuilder: (BuildContext context, int index) {},
            ),
    )



데이터베이스의 값을 '수동으로' 변경할 경우, 데이터베이스의 변경 내용을 수신하는 스트림이 필요합니다. 할 수 없습니다.

var articles = await ApiService.fetchArticles();

다음과 같은 작업을 수행해야 합니다.

var articles = await ApiService.listenToArticlesSnapshot();

설명하신 방법은 다른 페이지로 이동한 후 버튼을 클릭한 다음 첫 페이지로 이동(GetBuilder)하거나 첫 페이지(Obx) 내에서 데이터를 자동으로 추가하는 경우입니다. 그러나 간단히 기사를 스냅샷으로 검색한 다음 init의 컨트롤러에서 bindStream 메서드를 사용하여 스냅샷을 구독하고 ever() 함수를 사용하여 관찰 가능한 기사 목록의 변경 사항에 대응하면 됩니다. 이와 같은 것:




GetX는 데이터베이스 데이터가 변경/업데이트된 시기를 알 수 없습니다.

적절한 경우 GetX에 재구축하라고 말해야 합니다.

또는 위젯을 사용하여 GetX를 사용하는 경우 필드에 새 값을 할당합니다. 값이 변경되면 재구성이 수행됩니다.

GetX를 함께 사용하는 경우 위젯을 재구성하기 위해 내부 메서드를 호출해야 합니다.


아래 솔루션은 GetX 컨트롤러(즉, )를 사용하여 다음을 수행합니다.

  1. 응용 프로그램 상태 유지:

    1. 모든 탭 목록()
    2. 활성 탭()
  2. 메서드를 표시하여 활성/비활성 탭()을 변경합니다.

On ItemTaped()

이 메서드는 GetX 컨트롤러 안에 있습니다.

호출 시 다음과 같이 됩니다.

  1. 표시할 탭을 설정합니다.
  2. 데이터베이스에 보기 탭을 저장합니다().
  3. 다음을 사용하여 GetBuilder 위젯 재구성
  void onItemTapped(int index) {
    selectedIndex = index;
    db.insertViewedPage(index); // simulate database update while tabs change
    update(); // ← rebuilds any GetBuilder<TabX> widget
  }

전체 예제

작동 중인 Bottom Navigation Bar 페이지를 보려면 이 전체 코드를 앱의 다트 페이지에 복사/붙여 넣으십시오.

이 탭 / BottomNavigationBar 예제는 GetX를 사용하도록 편집된 것입니다.

import 'package:flutter/material.dart';
import 'package:get/get.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyTabHomePage(),
    );
  }
}

class FakeDB {
  List<int> viewedPages = [0];

  void insertViewedPage(int page) {
    viewedPages.add(page);
  }
}

/// BottomNavigationBar page converted to GetX. Original StatefulWidget version:
/// https://api.flutter.dev/flutter/material/BottomNavigationBar-class.html
class TabX extends GetxController {

  TabX({this.db});

  final FakeDB db;
  int selectedIndex = 0;
  static const TextStyle optionStyle =
  TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
  List<Widget> tabPages;

  @override
  void onInit() {
    super.onInit();
    tabPages = <Widget>[
      ListViewTab(db),
      Text(
        'Index 1: Business',
        style: optionStyle,
      ),
      Text(
        'Index 2: School',
        style: optionStyle,
      ),
    ];
  }

  /// INTERESTING PART HERE ↓ ************************************
  void onItemTapped(int index) {
    selectedIndex = index;
    db.insertViewedPage(index); // simulate database update while tabs change
    update(); // ← rebuilds any GetBuilder<TabX> widget
    // ↑ update() is like setState() to anything inside a GetBuilder using *this*
    // controller, i.e. GetBuilder<TabX>
    // Other GetX controllers are not affected. e.g. GetBuilder<BlahX>, not affected
    // by this update()
    // Use async/await above if data writes are slow & must complete before updating widget. 
    // This example does not.
  }
}

/// REBUILT when Tab Page changes, rebuilt by GetBuilder in MyTabHomePage
class ListViewTab extends StatelessWidget {
  final FakeDB db;

  ListViewTab(this.db);

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: db.viewedPages.length,
      itemBuilder: (context, index) =>
          ListTile(
            title: Text('Page Viewed: ${db.viewedPages[index]}'),
          ),
    );
  }
}


class MyTabHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    Get.put(TabX(db: FakeDB()));

    return Scaffold(
      appBar: AppBar(
        title: const Text('BottomNavigationBar Sample'),
      ),
      body: Center(
        /// ↓ Tab Page currently visible - rebuilt by GetBuilder when 
        /// ↓ TabX.onItemTapped() called
        child: GetBuilder<TabX>(
            builder: (tx) => tx.tabPages.elementAt(tx.selectedIndex)
        ),
      ),
      /// ↓ BottomNavBar's highlighted/active item, rebuilt by GetBuilder when
      /// ↓ TabX.onItemTapped() called
      bottomNavigationBar: GetBuilder<TabX>(
        builder: (tx) => BottomNavigationBar(
          items: const <BottomNavigationBarItem>[
            BottomNavigationBarItem(
              icon: Icon(Icons.home),
              label: 'Home',
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.business),
              label: 'Business',
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.school),
              label: 'School',
            ),
          ],
          currentIndex: tx.selectedIndex,
          selectedItemColor: Colors.amber[800],
          onTap: tx.onItemTapped,
        ),
      ),
    );
  }
}




@제빵사가 정답을 알려줘서 고마워요. 그러나 viewModel에 목록이 있고 해당 목록을 업데이트하려면 목록이 업데이트될 때 를 사용하십시오.

RxList<Models> myList = <Models>[].obs;

데이터 추가 또는 삽입 시 다음과 같이 작동합니다.

myList.add(newItem);
myList.refresh();



  1. 최종 탐색 컨트롤러 생성 = Get.put(탐색 컨트롤러());

  2. 추가: 탐색 컨트롤러();

body: SafeArea(
        child: Column(
        children: <Widget>[
          Header(),
          Expanded(
            child: GetX<ExploreController>(builder: (exploreController) {
                             *** here ***
             init: ExploreController();
              if (exploreController.isLoading.value) {
                return Center(
                  child: SpinKitChasingDots(
                      color: Colors.deepPurple[600], size: 40),
                );
              }
              return ListView.separated(
                padding: EdgeInsets.all(12),
                itemCount: exploreController.articleList.length,
                separatorBuilder: (BuildContext context, int index) {



ui 측에서 접근 방식을 사용하고 기본 제공 함수라고 하는 간단한 업데이트를 원하는 위치에 사용




내가 할 수 있는 가장 간단한 방법. 컨트롤러에서 obs(var indexClick = 1.obs;) 각 타일 테스트에서 선택한 == index...; 각 항목을 클릭하면 인덱스 변경순차적으로 클릭

  return Obx(() {
  return Drawer(
    child: ListView(
      padding: EdgeInsets.zero,
      children: [
        ListTile(
          leading: const Icon(Icons.dns),
          title: const Text('Menu1'),
          selected: controller.indexClick.value==1?true:false,
          onTap: () {
            controller.indexClick.value=1;
            Navigator.pop(context);
          },
        ),
        ListTile(
          leading: const Icon(Icons.search),
          title: const Text('Menu2'),
          selected: controller.indexClick.value==2?true:false,
          onTap: () {
            controller.indexClick.value=2;
            Navigator.pop(context);
          },
        ),

반응형