Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Flutter ChangeNotifierProvider显示灰色屏幕_Flutter_Flutter Provider - Fatal编程技术网

Flutter ChangeNotifierProvider显示灰色屏幕

Flutter ChangeNotifierProvider显示灰色屏幕,flutter,flutter-provider,Flutter,Flutter Provider,我有以下代码 类来保存我的项目,如下所示: class ItemList extends ChangeNotifier { List items = [ { "id": "1", "type": "men", "liked" : true, "cuisine": "Americain", "img": "../../images/jeans.png", "price" : 1, }, {

我有以下代码

类来保存我的项目,如下所示:

class ItemList extends ChangeNotifier {
  List items = [
    {
      "id": "1",
      "type": "men",
      "liked" : true,
      "cuisine": "Americain",
      "img": "../../images/jeans.png",
      "price" : 1,
    },
    {
      "id": "2",
      "type": "men",
      "liked" : true,
      "cuisine": "Americain",
      "img": "../../images/jeans.png",
      "price" : 2,
    },
    {
      "id": "3",
      "type": "men",
      "liked" : true,
      "cuisine": "Americain",
      "img": "../../images/jeans.png",
      "price" : 3,
    },
    {
      "id": "4",
      "type": "men",
      "liked" : true,
      "cuisine": "Americain",
      "img": "../../images/jeans.png",
      "price" : 4,
    },
    {
      "id": "5",
      "type": "men",
      "liked" : true,
      "cuisine": "Americain",
      "img": "../../images/jeans.png",
      "price" : 5,
    },
  ];

  likeAndUnlike(id){
    items.forEach((item)  {
      if(item['id'] == id){
        item['liked'] = !item['liked'];
      }
    }  ) ;
    notifyListeners() ;
  }
}
class LikedProduct extends StatelessWidget {
  final productDetails;

  LikedProduct({this.productDetails});

  @override
  Widget build(BuildContext context) {
    final size = MediaQuery.of(context).size;
    print("insideLikedProject");
    return Padding(
      padding: EdgeInsets.only(bottom: 22),
      child: GestureDetector(
        onTap: () {
          print("CLICKED!");
        child: Container(
          height: size.height * 0.15,
          width: size.width * 0.9,
          child: Row(
            children: <Widget>[
              Hero(
                transitionOnUserGestures: true,
                tag: productDetails['id'],
                child: ClipRRect(
                  borderRadius: BorderRadius.circular(12),
                  child: Image.asset(
                    productDetails['img'],
                    width: size.width * 0.35,
                    height: size.height * 0.15,
                    fit: BoxFit.cover,
                  ),
                ),
              ),
              SizedBox(
                width: 8,
              ),
              SizedBox(
                height: size.height * 0.13,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: <Widget>[
                    Text(
                      productDetails['type'],
                      style: style.headerStyle3,
                    ),
                    Text(
                      productDetails['price'].toString() + " OMR",
                      style: style.textTheme
                          .copyWith(color: Theme.of(context).primaryColor),
                    ),
                  ],
                ),
              )
            ],
          ),
        ),
      ),
    );
  }
}
class OrdersUI extends StatefulWidget {
  @override
  _OrdersUIState createState() => _OrdersUIState();
}

class _OrdersUIState extends State<OrdersUI> {
  final totalCost = 0;
  final jeansPrice = 0;
  final jeansCounter = 0;
  final standardDeliveryCost = 5;
  final expressDeliveryCost = 15;

  void _changeTotalPrice() {
    setState(() {});
  }

  final productDetails;

  _OrdersUIState({this.productDetails});

  @override
  Widget build(BuildContext context) {
    final data = MediaQuery.of(context);
    final size = MediaQuery.of(context).size;

    return Scaffold(
        appBar: AppBar(
          title: Align(
              alignment: Alignment.center,
              child: Text(
                'Title',
                style: TextStyle(color: Colors.black),
              )),
          actions: <Widget>[],
          backgroundColor: Colors.white,
        ),
        body: Container(
            width: data.size.width,
            //height: data.size.height * 0.05,
            child: Column(
              children: <Widget>[
                Row(
                  children: <Widget>[
                    Align(
                      alignment: Alignment.topCenter,
                      child: Container(
                          color: Color.fromARGB(255, 81, 202, 238),
                          height: data.size.height * 0.05,
                          width: data.size.width,
                          alignment: Alignment.topCenter,
                          child: Align(
                              alignment: Alignment.center,
                              child: Text(
                                'Total : ${totalCost.toString()} OMR',
                              ))),
                    ),
                  ],
                ),

                Padding(
                  padding: EdgeInsets.symmetric(horizontal: 12, vertical: 12),
                  child: Column(
                    children: <Widget>[
                      ChangeNotifierProvider<ItemList>(
                        create: (context) => locator<ItemList>(),
                        child: Consumer<ItemList>(
                          builder: (context, model, child) {
                            print("Inside Builder"); // doesn't get executed
                            return Expanded(
                              child: ListView.builder(
                                physics: ScrollPhysics(
                                    parent: BouncingScrollPhysics()),
                                shrinkWrap: true,
                                itemCount: model.items.length,
                                itemBuilder: (context, index) {
                                  print('Inside Item Builder');  // doesn't get executed
                                  return LikedProduct(
                                    productDetails: model.items[index],
                                  );
                                },
                              ),
                            );
                          },
                        ),
                      ),
                    ],
                  ),
                ),
                Row(
                  children: <Widget>[
                    Expanded(
                      child: Container(
                        //margin: const EdgeInsets.only(left: 50.0, right: 50.0),
                        child: Divider(
                          height: 1,
                          thickness: 1,
                          color: Colors.grey.shade700,
                        ),
                      ),
                    )
                  ],
                ),
              ],
            )
        )
    );
  }
}
import 'package:get_it/get_it.dart';
import './core/Items_lists.dart';

GetIt locator = GetIt();

void setupLocator() {
  locator.registerFactory(() => ItemList()) ;
}
以及一个用于从ItemList类返回项的类,如下所示:

class ItemList extends ChangeNotifier {
  List items = [
    {
      "id": "1",
      "type": "men",
      "liked" : true,
      "cuisine": "Americain",
      "img": "../../images/jeans.png",
      "price" : 1,
    },
    {
      "id": "2",
      "type": "men",
      "liked" : true,
      "cuisine": "Americain",
      "img": "../../images/jeans.png",
      "price" : 2,
    },
    {
      "id": "3",
      "type": "men",
      "liked" : true,
      "cuisine": "Americain",
      "img": "../../images/jeans.png",
      "price" : 3,
    },
    {
      "id": "4",
      "type": "men",
      "liked" : true,
      "cuisine": "Americain",
      "img": "../../images/jeans.png",
      "price" : 4,
    },
    {
      "id": "5",
      "type": "men",
      "liked" : true,
      "cuisine": "Americain",
      "img": "../../images/jeans.png",
      "price" : 5,
    },
  ];

  likeAndUnlike(id){
    items.forEach((item)  {
      if(item['id'] == id){
        item['liked'] = !item['liked'];
      }
    }  ) ;
    notifyListeners() ;
  }
}
class LikedProduct extends StatelessWidget {
  final productDetails;

  LikedProduct({this.productDetails});

  @override
  Widget build(BuildContext context) {
    final size = MediaQuery.of(context).size;
    print("insideLikedProject");
    return Padding(
      padding: EdgeInsets.only(bottom: 22),
      child: GestureDetector(
        onTap: () {
          print("CLICKED!");
        child: Container(
          height: size.height * 0.15,
          width: size.width * 0.9,
          child: Row(
            children: <Widget>[
              Hero(
                transitionOnUserGestures: true,
                tag: productDetails['id'],
                child: ClipRRect(
                  borderRadius: BorderRadius.circular(12),
                  child: Image.asset(
                    productDetails['img'],
                    width: size.width * 0.35,
                    height: size.height * 0.15,
                    fit: BoxFit.cover,
                  ),
                ),
              ),
              SizedBox(
                width: 8,
              ),
              SizedBox(
                height: size.height * 0.13,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: <Widget>[
                    Text(
                      productDetails['type'],
                      style: style.headerStyle3,
                    ),
                    Text(
                      productDetails['price'].toString() + " OMR",
                      style: style.textTheme
                          .copyWith(color: Theme.of(context).primaryColor),
                    ),
                  ],
                ),
              )
            ],
          ),
        ),
      ),
    );
  }
}
class OrdersUI extends StatefulWidget {
  @override
  _OrdersUIState createState() => _OrdersUIState();
}

class _OrdersUIState extends State<OrdersUI> {
  final totalCost = 0;
  final jeansPrice = 0;
  final jeansCounter = 0;
  final standardDeliveryCost = 5;
  final expressDeliveryCost = 15;

  void _changeTotalPrice() {
    setState(() {});
  }

  final productDetails;

  _OrdersUIState({this.productDetails});

  @override
  Widget build(BuildContext context) {
    final data = MediaQuery.of(context);
    final size = MediaQuery.of(context).size;

    return Scaffold(
        appBar: AppBar(
          title: Align(
              alignment: Alignment.center,
              child: Text(
                'Title',
                style: TextStyle(color: Colors.black),
              )),
          actions: <Widget>[],
          backgroundColor: Colors.white,
        ),
        body: Container(
            width: data.size.width,
            //height: data.size.height * 0.05,
            child: Column(
              children: <Widget>[
                Row(
                  children: <Widget>[
                    Align(
                      alignment: Alignment.topCenter,
                      child: Container(
                          color: Color.fromARGB(255, 81, 202, 238),
                          height: data.size.height * 0.05,
                          width: data.size.width,
                          alignment: Alignment.topCenter,
                          child: Align(
                              alignment: Alignment.center,
                              child: Text(
                                'Total : ${totalCost.toString()} OMR',
                              ))),
                    ),
                  ],
                ),

                Padding(
                  padding: EdgeInsets.symmetric(horizontal: 12, vertical: 12),
                  child: Column(
                    children: <Widget>[
                      ChangeNotifierProvider<ItemList>(
                        create: (context) => locator<ItemList>(),
                        child: Consumer<ItemList>(
                          builder: (context, model, child) {
                            print("Inside Builder"); // doesn't get executed
                            return Expanded(
                              child: ListView.builder(
                                physics: ScrollPhysics(
                                    parent: BouncingScrollPhysics()),
                                shrinkWrap: true,
                                itemCount: model.items.length,
                                itemBuilder: (context, index) {
                                  print('Inside Item Builder');  // doesn't get executed
                                  return LikedProduct(
                                    productDetails: model.items[index],
                                  );
                                },
                              ),
                            );
                          },
                        ),
                      ),
                    ],
                  ),
                ),
                Row(
                  children: <Widget>[
                    Expanded(
                      child: Container(
                        //margin: const EdgeInsets.only(left: 50.0, right: 50.0),
                        child: Divider(
                          height: 1,
                          thickness: 1,
                          color: Colors.grey.shade700,
                        ),
                      ),
                    )
                  ],
                ),
              ],
            )
        )
    );
  }
}
import 'package:get_it/get_it.dart';
import './core/Items_lists.dart';

GetIt locator = GetIt();

void setupLocator() {
  locator.registerFactory(() => ItemList()) ;
}
ChangeNotifierProvider中使用的定位器文件用于注册我想在ui中使用的类,如下所示:

class ItemList extends ChangeNotifier {
  List items = [
    {
      "id": "1",
      "type": "men",
      "liked" : true,
      "cuisine": "Americain",
      "img": "../../images/jeans.png",
      "price" : 1,
    },
    {
      "id": "2",
      "type": "men",
      "liked" : true,
      "cuisine": "Americain",
      "img": "../../images/jeans.png",
      "price" : 2,
    },
    {
      "id": "3",
      "type": "men",
      "liked" : true,
      "cuisine": "Americain",
      "img": "../../images/jeans.png",
      "price" : 3,
    },
    {
      "id": "4",
      "type": "men",
      "liked" : true,
      "cuisine": "Americain",
      "img": "../../images/jeans.png",
      "price" : 4,
    },
    {
      "id": "5",
      "type": "men",
      "liked" : true,
      "cuisine": "Americain",
      "img": "../../images/jeans.png",
      "price" : 5,
    },
  ];

  likeAndUnlike(id){
    items.forEach((item)  {
      if(item['id'] == id){
        item['liked'] = !item['liked'];
      }
    }  ) ;
    notifyListeners() ;
  }
}
class LikedProduct extends StatelessWidget {
  final productDetails;

  LikedProduct({this.productDetails});

  @override
  Widget build(BuildContext context) {
    final size = MediaQuery.of(context).size;
    print("insideLikedProject");
    return Padding(
      padding: EdgeInsets.only(bottom: 22),
      child: GestureDetector(
        onTap: () {
          print("CLICKED!");
        child: Container(
          height: size.height * 0.15,
          width: size.width * 0.9,
          child: Row(
            children: <Widget>[
              Hero(
                transitionOnUserGestures: true,
                tag: productDetails['id'],
                child: ClipRRect(
                  borderRadius: BorderRadius.circular(12),
                  child: Image.asset(
                    productDetails['img'],
                    width: size.width * 0.35,
                    height: size.height * 0.15,
                    fit: BoxFit.cover,
                  ),
                ),
              ),
              SizedBox(
                width: 8,
              ),
              SizedBox(
                height: size.height * 0.13,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: <Widget>[
                    Text(
                      productDetails['type'],
                      style: style.headerStyle3,
                    ),
                    Text(
                      productDetails['price'].toString() + " OMR",
                      style: style.textTheme
                          .copyWith(color: Theme.of(context).primaryColor),
                    ),
                  ],
                ),
              )
            ],
          ),
        ),
      ),
    );
  }
}
class OrdersUI extends StatefulWidget {
  @override
  _OrdersUIState createState() => _OrdersUIState();
}

class _OrdersUIState extends State<OrdersUI> {
  final totalCost = 0;
  final jeansPrice = 0;
  final jeansCounter = 0;
  final standardDeliveryCost = 5;
  final expressDeliveryCost = 15;

  void _changeTotalPrice() {
    setState(() {});
  }

  final productDetails;

  _OrdersUIState({this.productDetails});

  @override
  Widget build(BuildContext context) {
    final data = MediaQuery.of(context);
    final size = MediaQuery.of(context).size;

    return Scaffold(
        appBar: AppBar(
          title: Align(
              alignment: Alignment.center,
              child: Text(
                'Title',
                style: TextStyle(color: Colors.black),
              )),
          actions: <Widget>[],
          backgroundColor: Colors.white,
        ),
        body: Container(
            width: data.size.width,
            //height: data.size.height * 0.05,
            child: Column(
              children: <Widget>[
                Row(
                  children: <Widget>[
                    Align(
                      alignment: Alignment.topCenter,
                      child: Container(
                          color: Color.fromARGB(255, 81, 202, 238),
                          height: data.size.height * 0.05,
                          width: data.size.width,
                          alignment: Alignment.topCenter,
                          child: Align(
                              alignment: Alignment.center,
                              child: Text(
                                'Total : ${totalCost.toString()} OMR',
                              ))),
                    ),
                  ],
                ),

                Padding(
                  padding: EdgeInsets.symmetric(horizontal: 12, vertical: 12),
                  child: Column(
                    children: <Widget>[
                      ChangeNotifierProvider<ItemList>(
                        create: (context) => locator<ItemList>(),
                        child: Consumer<ItemList>(
                          builder: (context, model, child) {
                            print("Inside Builder"); // doesn't get executed
                            return Expanded(
                              child: ListView.builder(
                                physics: ScrollPhysics(
                                    parent: BouncingScrollPhysics()),
                                shrinkWrap: true,
                                itemCount: model.items.length,
                                itemBuilder: (context, index) {
                                  print('Inside Item Builder');  // doesn't get executed
                                  return LikedProduct(
                                    productDetails: model.items[index],
                                  );
                                },
                              ),
                            );
                          },
                        ),
                      ),
                    ],
                  ),
                ),
                Row(
                  children: <Widget>[
                    Expanded(
                      child: Container(
                        //margin: const EdgeInsets.only(left: 50.0, right: 50.0),
                        child: Divider(
                          height: 1,
                          thickness: 1,
                          color: Colors.grey.shade700,
                        ),
                      ),
                    )
                  ],
                ),
              ],
            )
        )
    );
  }
}
import 'package:get_it/get_it.dart';
import './core/Items_lists.dart';

GetIt locator = GetIt();

void setupLocator() {
  locator.registerFactory(() => ItemList()) ;
}
当我运行应用程序查看订单时,我会看到如下屏幕:

它显示灰色,而不是列出项目

我做错了什么?为什么这些项目没有出现


注意:我使用的是提供程序版本4.0.0

您可以复制下面的粘贴运行完整代码 步骤1:您可以将ChangeNotifierProvider移动到MyApp

应该是

GestureDetector(
          onTap: () {
            print("CLICKED!");
          },
          child: Container(
工作演示

完整代码

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:get_it/get_it.dart';

GetIt locator = GetIt.instance;

void setupLocator() {
  locator.registerFactory(() => ItemList());
}

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

class ItemList extends ChangeNotifier {
  List items = [
    {
      "id": "1",
      "type": "men",
      "liked": true,
      "cuisine": "Americain",
      "img": "../../images/jeans.png",
      "price": 1,
    },
    {
      "id": "2",
      "type": "men",
      "liked": true,
      "cuisine": "Americain",
      "img": "../../images/jeans.png",
      "price": 2,
    },
    {
      "id": "3",
      "type": "men",
      "liked": true,
      "cuisine": "Americain",
      "img": "../../images/jeans.png",
      "price": 3,
    },
    {
      "id": "4",
      "type": "men",
      "liked": true,
      "cuisine": "Americain",
      "img": "../../images/jeans.png",
      "price": 4,
    },
    {
      "id": "5",
      "type": "men",
      "liked": true,
      "cuisine": "Americain",
      "img": "../../images/jeans.png",
      "price": 5,
    },
  ];

  likeAndUnlike(id) {
    items.forEach((item) {
      if (item['id'] == id) {
        item['liked'] = !item['liked'];
      }
    });
    notifyListeners();
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(
          create: (BuildContext context) => locator<ItemList>(),
        ),
      ],
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: OrdersUI(),
      ),
    );
  }
}

class LikedProduct extends StatelessWidget {
  final productDetails;

  LikedProduct({this.productDetails});

  @override
  Widget build(BuildContext context) {
    print("productDetails ${productDetails["id"]}");
    final size = MediaQuery.of(context).size;
    print("insideLikedProject");

    return Padding(
        padding: EdgeInsets.only(bottom: 22),
        child: GestureDetector(
          onTap: () {
            print("CLICKED!");
          },
          child: Container(
            height: size.height * 0.15,
            width: size.width * 0.9,
            child: Row(
              children: <Widget>[
                Hero(
                  transitionOnUserGestures: true,
                  tag: productDetails['id'],
                  child: ClipRRect(
                    borderRadius: BorderRadius.circular(12),
                    child: Image.asset(
                      productDetails['img'],
                      width: size.width * 0.35,
                      height: size.height * 0.15,
                      fit: BoxFit.cover,
                    ),
                  ),
                ),
                SizedBox(
                  width: 8,
                ),
                SizedBox(
                  height: size.height * 0.13,
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: <Widget>[
                      Text(
                        productDetails['type'],
                        //style: style.headerStyle3,
                      ),
                      Text(
                        productDetails['price'].toString() + " OMR",
                        /*style: style.textTheme
                        .copyWith(color: Theme.of(context).primaryColor),*/
                      ),
                    ],
                  ),
                )
              ],
            ),
          ),
        ));
  }
}

class OrdersUI extends StatefulWidget {
  @override
  _OrdersUIState createState() => _OrdersUIState();
}

class _OrdersUIState extends State<OrdersUI> {
  final totalCost = 0;
  final jeansPrice = 0;
  final jeansCounter = 0;
  final standardDeliveryCost = 5;
  final expressDeliveryCost = 15;

  void _changeTotalPrice() {
    setState(() {});
  }

  final productDetails;

  _OrdersUIState({this.productDetails});

  @override
  Widget build(BuildContext context) {
    final data = MediaQuery.of(context);
    final size = MediaQuery.of(context).size;

    return Scaffold(
        appBar: AppBar(
          title: Align(
              alignment: Alignment.center,
              child: Text(
                'Title',
                style: TextStyle(color: Colors.black),
              )),
          actions: <Widget>[],
          backgroundColor: Colors.white,
        ),
        body: Container(
            width: data.size.width,
            //height: data.size.height * 0.05,
            child: Column(
              children: <Widget>[
                Row(
                  children: <Widget>[
                    Align(
                      alignment: Alignment.topCenter,
                      child: Container(
                          color: Color.fromARGB(255, 81, 202, 238),
                          height: data.size.height * 0.05,
                          width: data.size.width,
                          alignment: Alignment.topCenter,
                          child: Align(
                              alignment: Alignment.center,
                              child: Text(
                                'Total : ${totalCost.toString()} OMR',
                              ))),
                    ),
                  ],
                ),
                Padding(
                  padding: EdgeInsets.symmetric(horizontal: 12, vertical: 12),
                  child: Column(
                    children: <Widget>[
                      Consumer<ItemList>(
                        builder: (context, model, child) {
                          print("Inside Builder"); // doesn't get executed
                          return Container(
                            height: 500,
                            child: ListView.builder(
                              physics: ScrollPhysics(
                                  parent: BouncingScrollPhysics()),
                              shrinkWrap: true,
                              itemCount: model.items.length,
                              itemBuilder: (context, index) {
                                print(model.items[index]["type"].toString());
                                print(
                                    'Inside Item Builder'); // doesn't get executed
                                return Container(
                                  height: 200,
                                  width: 300,
                                  child: LikedProduct(
                                    productDetails: model.items[index],
                                  ),
                                );
                              },
                            ),
                          );
                        },
                      ),
                    ],
                  ),
                ),
                Row(
                  children: <Widget>[
                    Expanded(
                      child: Container(
                        //margin: const EdgeInsets.only(left: 50.0, right: 50.0),
                        child: Divider(
                          height: 1,
                          thickness: 1,
                          color: Colors.grey.shade700,
                        ),
                      ),
                    )
                  ],
                ),
              ],
            )));
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

您使用的是哪个提供商软件包版本?@Abbas版本4.0.0请尝试降级,因为最新版本似乎已损坏。我也遇到了一些问题。@Abbas我试过了,但同样的问题也出现了。ChangeNotifierProvider的create参数中的“locator”是什么??