getx的使用场景,详细举例

news/2024/7/20 21:36:47 标签: flutter, android, ios

Getx是一种在Flutter中使用的状态管理框架,它提供了许多便利的功能,包括路由、依赖注入、状态管理等,以下是一些Getx的使用场景和详细的举例:

  1. 路由管理:Getx可以帮助我们在Flutter中管理路由,例如可以使用Get.to方法来实现页面跳转,使用Get.back()方法来返回上一个页面,使用Get.offAll()方法来关闭所有页面等等。

举例:假设我们有两个页面A和B,现在需要在A页面中跳转到B页面,可以使用以下代码:

Get.to(BPage());
  1. 依赖注入:Getx可以通过依赖注入的方式来管理我们的组件之间的依赖关系,例如可以使用Get.lazyPut()方法来懒加载一个对象,使用Get.put()方法来创建一个对象等等。

举例:假设我们有一个MyController控制器,需要在另一个组件中使用,可以使用以下代码来进行依赖注入:(后面我们会详细举例)

final MyController myController = Get.put(MyController());
  1. 状态管理:Getx可以帮助我们管理Flutter应用程序中的状态,包括全局状态、页面状态等等,例如可以使用GetBuilder()方法来更新页面状态,使用GetX()方法来更新全局状态等等。

举例:假设我们有一个计数器,需要在页面上显示当前的计数值,可以使用以下代码来实现状态管理:

class MyHomePage extends StatelessWidget {
  final MyController myController = Get.find();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("My App"),
      ),
      body: Center(
        child: GetBuilder<MyController>(
          builder: (controller) {
            return Text(
              'Count: ${controller.count}',
              style: TextStyle(fontSize: 24),
            );
          },
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          myController.increment();
        },
        child: Icon(Icons.add),
      ),
    );
  }
}
  1. 国际化:Getx提供了便利的国际化功能,可以轻松地在Flutter应用程序中实现多语言的支持,例如可以使用Get.locale和Get.updateLocale方法来设置当前的语言环境,使用Get.tr方法来获取当前语言环境下的字符串等等。

举例:假设我们需要在应用程序中支持英文和中文两种语言,可以使用以下代码来实现国际化:

// 设置默认语言环境
void main() async {
  await GetStorage.init(); // 初始化存储
  await Get.putAsync(() => LocalizationService().init()); // 初始化国际化服务
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  final LocalizationService localizationService = Get.find();

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'My App',
      locale: localizationService.locale, // 设置当前语言环境
      translations: localizationService, // 设置翻译服务
      fallbackLocale: Locale('en', 'US'), // 设置默认语言环境
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("My App"),
      ),
      body: Center(
        child: Text(
          'hello'.tr, // 获取当前语言环境下的字符串
          style: TextStyle(fontSize: 24),
        ),
      ),
    );
  }
}

class LocalizationService extends Translations {
  static final fallbackLocale = Locale('en', 'US'); // 默认语言环境

  @override
  Map<String, Map<String, String>> get keys => {
        'en_US': {
          'hello': 'Hello',
        },
        'zh_CN': {
          'hello': '你好',
        },
      };
}
  1. 状态持久化:Getx可以帮助我们实现状态的持久化,例如可以使用GetStorage来存储和读取本地数据,使用Get.putAsync()方法来异步地初始化状态等等。

举例:假设我们需要在应用程序中保存一个用户的登录状态,可以使用以下代码来实现状态的持久化:

class UserController extends GetxController {
  final _isLogin = false.obs;
  bool get isLogin => _isLogin.value;

  @override
  void onInit() async {
    await GetStorage.init();
    final box = GetStorage();
    _isLogin.value = box.read('isLogin') ?? false; // 从本地读取登录状态
    super.onInit();
  }

  void login() {
    _isLogin.value = true;
    final box = GetStorage();
    box.write('isLogin', true); // 将登录状态保存到本地
  }

  void logout() {
    _isLogin.value = false;
    final box = GetStorage();
    box.remove('isLogin'); // 从本地删除登录状态
  }
}

依赖注入使用的较多,我们再具体阐述下:

依赖注入是指在应用程序中,通过一个容器(通常称为“依赖注入容器”或“服务容器”)来管理对象之间的依赖关系,从而实现解耦、可测试性和可维护性。

比如下面:

假设有一个需要依赖一个网络请求服务的组件,我们可以使用Getx来进行依赖注入。

首先,我们需要创建一个抽象类或接口,定义网络请求服务的方法:

abstract class ApiService {
  Future<String> fetchData(String url);
}

然后,我们需要创建一个具体的实现类,实现网络请求服务的方法:

class ApiServiceImpl implements ApiService {
  @override
  Future<String> fetchData(String url) async {
    // 发送网络请求并返回结果
    final response = await http.get(Uri.parse(url));
    return response.body;
  }
}

接下来,我们需要在Getx框架的依赖注入容器中注册这个服务。可以在应用程序的入口处初始化依赖注入容器,并注册服务:

void main() {
  // 初始化依赖注入容器
  Get.put(ApiServiceImpl());
  runApp(MyApp());
}

最后,在需要使用网络请求服务的组件中,我们可以通过依赖注入来获取这个服务:

class MyWidget extends StatelessWidget {
  final ApiService apiService = Get.find(); // 通过依赖注入获取服务

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<String>(
      future: apiService.fetchData('http://example.com/data'),
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          return Text(snapshot.data);
        } else if (snapshot.hasError) {
          return Text('Error: ${snapshot.error}');
        } else {
          return CircularProgressIndicator();
        }
      },
    );
  }
}

在上述代码中,我们通过Get.find()方法来获取ApiService的实例,然后在FutureBuilder中使用它来发送网络请求并显示结果。Getx会自动管理ApiService的生命周期,确保它只被创建一次,并在需要时注入到组件中。

以上是一个简单的依赖注入的举例,Getx的依赖注入还有很多其他的用法和功能,例如懒加载、单例模式、依赖注入顺序等等,可以在实际项目中灵活运用。

下面再举一个更为复杂的依赖注入的例子,来展示Getx的依赖注入的强大功能。假设我们有一个需求,需要实现一个带有登录和注册功能的应用程序。登录和注册功能需要依赖一个网络请求服务和一个用户数据存储服务。我们可以通过Getx来实现依赖注入,从而实现解耦、可测试性和可维护性。

首先,我们需要定义一个用户数据存储服务的接口:

abstract class UserRepository {
  Future<User> login(String username, String password);
  Future<User> register(String username, String password);
  Future<void> logout();
  User? getUser();
}

然后,我们可以创建一个具体的实现类,实现用户数据存储服务的方法:

class UserRepositoryImpl implements UserRepository {
  final _user = Rx<User?>(null);

  @override
  Future<User> login(String username, String password) async {
    // 发送登录请求
    final user = User(username, password);
    _user.value = user;
    return user;
  }

  @override
  Future<User> register(String username, String password) async {
    // 发送注册请求
    final user = User(username, password);
    _user.value = user;
    return user;
  }

  @override
  Future<void> logout() async {
    // 清除用户数据
    _user.value = null;
  }

  @override
  User? getUser() {
    // 获取当前用户数据
    return _user.value;
  }
}

接下来,我们需要定义一个网络请求服务的接口:

abstract class ApiService {
  Future<String> fetchData(String url);
}

然后,我们可以创建一个具体的实现类,实现网络请求服务的方法:

class ApiServiceImpl implements ApiService {
  @override
  Future<String> fetchData(String url) async {
    // 发送网络请求并返回结果
    final response = await http.get(Uri.parse(url));
    return response.body;
  }
}

接下来,我们需要在Getx的依赖注入容器中注册这些服务:

void main() async {
  await GetStorage.init(); // 初始化存储
  Get.put(ApiServiceImpl()); // 注册网络请求服务
  Get.put(UserRepositoryImpl()); // 注册用户数据存储服务
  runApp(MyApp());
}

最后,我们可以在需要使用用户数据存储服务的组件中,通过依赖注入来获取它,并使用它来实现登录和注册功能:

class LoginPage extends StatelessWidget {
  final UserRepository userRepository = Get.find(); // 通过依赖注入获取用户数据存储服务
  final TextEditingController usernameController = TextEditingController();
  final TextEditingController passwordController = TextEditingController();

  void _login() async {
    final username = usernameController.text;
    final password = passwordController.text;
    final user = await userRepository.login(username, password); // 调用用户数据存储服务的登录方法
    if (user != null) {
      Get.offAllNamed('/home');
    } else {
      Get.snackbar('Error', 'Login failed');
    }
  }

  void _register() async {
    final username = usernameController.text;
    final password = passwordController.text;
    final user = await userRepository.register(username, password); // 调用用户数据存储服务的注册方法
    if (user != null) {
      Get.offAllNamed('/home');
    } else {
      Get.snackbar('Error', 'Register failed');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Login'),
      ),
      body: Padding(
        padding: EdgeInsets.all(16),
        child: Column(
          children: [
            TextField(
              controller: usernameController,
              decoration: InputDecoration(
                labelText: 'Username',
              ),
            ),
            TextField(
              controller: passwordController,
              decoration: InputDecoration(
                labelText: 'Password',
              ),
              obscureText: true,
            ),
            SizedBox(height: 16),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                ElevatedButton(
                  onPressed: _login,
                  child: Text('Login'),
                ),
                ElevatedButton(
                  onPressed: _register,
                  child: Text('Register'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

在上述代码中,我们通过Get.find()方法来获取UserRepository的实例,并在登录和注册方法中调用它的相应方法。Getx会自动管理UserRepository的生命周期,确保它只被创建一次,并在需要时注入到组件中。

好的,下面再举一个依赖注入与路由管理相结合的例子。假设我们有一个需求,需要实现一个带有登录和注册功能的应用程序,登录成功后跳转到主页,并在主页上显示用户信息。我们可以通过Getx来实现依赖注入和路由管理,从而实现解耦、可测试性和可维护性。

首先,我们需要定义一个用户数据存储服务的接口:

abstract class UserRepository {
  Future<User> login(String username, String password);
  Future<User> register(String username, String password);
  Future<void> logout();
  User? getUser();
}

然后,我们可以创建一个具体的实现类,实现用户数据存储服务的方法:

class UserRepositoryImpl implements UserRepository {
  final _user = Rx<User?>(null);

  @override
  Future<User> login(String username, String password) async {
    // 发送登录请求
    final user = User(username, password);
    _user.value = user;
    return user;
  }

  @override
  Future<User> register(String username, String password) async {
    // 发送注册请求
    final user = User(username, password);
    _user.value = user;
    return user;
  }

  @override
  Future<void> logout() async {
    // 清除用户数据
    _user.value = null;
  }

  @override
  User? getUser() {
    // 获取当前用户数据
    return _user.value;
  }
}

接下来,我们需要定义一个用户信息显示页面:

class HomePage extends StatelessWidget {
  final UserRepository userRepository = Get.find(); // 通过依赖注入获取用户数据存储服务

  @override
  Widget build(BuildContext context) {
    final user = userRepository.getUser();
    return Scaffold(
      appBar: AppBar(
        title: Text('Home'),
      ),
      body: Center(
        child: user != null
            ? Text('Welcome, ${user.username}')
            : Text('Please login'),
      ),
    );
  }
}

然后,我们需要在Getx框架的依赖注入容器中注册这些服务,并设置路由:

void main() async {
  await GetStorage.init(); // 初始化存储
  Get.put(ApiServiceImpl()); // 注册网络请求服务
  Get.put(UserRepositoryImpl()); // 注册用户数据存储服务
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  final UserRepository userRepository = Get.find(); // 通过依赖注入获取用户数据存储服务

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'My App',
      initialRoute: userRepository.getUser() != null ? '/home' : '/login', // 根据用户数据判断初始路由
      getPages: [
        GetPage(name: '/login', page: () => LoginPage()),
        GetPage(name: '/home', page: () => HomePage()),
      ],
    );
  }
}

在上述代码中,我们通过GetMaterialApp来设置路由,根据用户数据判断初始路由。如果用户已经登录,则跳转到主页;否则跳转到登录页面。Getx会自动管理UserRepository的生命周期,确保它只被创建一次,并在需要时注入到组件中。

后,我们可以在登录页面中通过依赖注入来获取用户数据存储服务,并在登录成功后跳转到主页:

class LoginPage extends StatelessWidget {
  final UserRepository userRepository = Get.find(); // 通过依赖注入获取用户数据存储服务
  final TextEditingController usernameController = TextEditingController();
  final TextEditingController passwordController = TextEditingController();

  void _login() async {
    final username = usernameController.text;
    final password = passwordController.text;
    final user = await userRepository.login(username, password); // 调用用户数据存储服务的登录方法
    if (user != null) {
      Get.offAllNamed('/home'); // 跳转到主页
    } else {
      Get.snackbar('Error', 'Login failed');
    }
  }

  void _register() async {
    final username = usernameController.text;
    final password = passwordController.text;
    final user = await userRepository.register(username, password); // 调用用户数据存储服务的注册方法
    if (user != null) {
      Get.offAllNamed('/home'); // 跳转到主页
    } else {
      Get.snackbar('Error', 'Register failed');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Login'),
      ),
      body: Padding(
        padding: EdgeInsets.all(16),
        child: Column(
          children: [
            TextField(
              controller: usernameController,
              decoration: InputDecoration(
                labelText: 'Username',
              ),
            ),
            TextField(
              controller: passwordController,
              decoration: InputDecoration(
                labelText: 'Password',
              ),
              obscureText: true,
            ),
            SizedBox(height: 16),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                ElevatedButton(
                  onPressed: _login,
                  child: Text('Login'),
                ),
                ElevatedButton(
                  onPressed: _register,
                  child: Text('Register'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

在上述代码中,我们通过Get.offAllNamed()方法来跳转到主页,并使用Get.snackbar()方法来显示错误信息。Getx会自动管理UserRepository的生命周期,并在需要时注入到组件中。

以上是一个依赖注入与路由管理相结合的例子。

再详细说说状态管理的例子

假设我们有一个需求,需要实现一个计数器应用程序,可以通过按钮来增加或减少计数器的值。我们可以使用Getx来实现状态管理,从而实现组件之间的解耦、可测试性和可维护性。

首先,我们需要定义一个计数器状态的类,它继承自GetxController:

class CounterController extends GetxController {
  var count = 0.obs; // 使用Rx类型来定义响应式变量

  void increment() {
    count.value++; // 通过.value来获取和设置变量的值
  }

  void decrement() {
    count.value--;
  }
}

在上述代码中,我们使用Rx类型来定义响应式变量,可以在变量的值发生变化时自动通知相关的组件。通过使用GetxController,我们可以将计数器状态和相关的业务逻辑封装在一个组件中,从而实现组件之间的解耦。

接下来,我们需要在应用程序的入口处创建CounterController的实例,并将它注册到Getx框架的依赖注入容器中:

void main() {
  Get.put(CounterController()); // 将CounterController注册到Getx的依赖注入容器中
  runApp(MyApp());
}

然后,在需要使用计数器状态的组件中,我们可以通过依赖注入来获取CounterController的实例,并使用它来管理计数器状态:

class MyHomePage extends StatelessWidget {
  final CounterController controller = Get.find(); // 通过依赖注入获取CounterController的实例

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Counter App'),
      ),
      body: Center(
        child: Obx(() => Text('Count: ${controller.count.value}')), // 使用Obx来监听计数器状态的变化
      ),
      floatingActionButton: Row(
        mainAxisAlignment: MainAxisAlignment.end,
         FloatingActionButton( onPressed: controller.increment, // 调用CounterController的increment方法 
                   tooltip: 'Increment', child: Icon(Icons.add), ), 
                        SizedBox(width: 16),
         FloatingActionButton( onPressed: controller.decrement, // 调用CounterController的decrement方法 
                        tooltip: 'Decrement', child: Icon(Icons.remove),
              ), 
            ], 
          ); 
         } }

在上述代码中,我们通过Get.find()方法来获取CounterController的实例,并使用Obx来监听计数器状态的变化。当计数器状态发生变化时,Obx会自动通知相关的组件进行更新。

我们还可以通过调用Controller的increment和decrement方法来增加或减少计数器的值。通过使用Getx的状态管理功能,我们可以轻松实现计数器应用程序,并且实现组件之间的解耦、可测试性和可维护性。

Getx的状态管理还有很多其他的用法和功能,例如响应式变量、异步更新、依赖关系、局部更新等等,可以在实际项目中灵活运用。总之,Getx的状态管理功能可以帮助我们更加方便地管理Flutter应用程序中的状态,从而提高开发效率和代码质量。

实现组件之间的解耦、可测试性和可维护性。

首先,我们需要定义一个待办事项的类:

class Todo {
  final String title;
  final String description;
  final DateTime date;

  Todo(this.title, this.description, this.date);
  
  // 省略其他方法和属性
}

然后,我们可以创建一个待办事项数据存储服务的接口:

abstract class TodoRepository {
  Future<void> add(Todo todo);
  Future<void> delete(Todo todo);
  Future<void> update(Todo todo);
  List<Todo> getAll();
}

接下来,我们可以创建一个具体的实现类,实现待办事项数据存储服务的方法,这里我们使用GetStorage来实现数据的存储和读取:

class TodoRepositoryImpl implements TodoRepository {
  final _storage = GetStorage();
  final _todos = RxList<Todo>([]);

  @override
  Future<void> add(Todo todo) async {
    _todos.add(todo);
    await _storage.write('todos', _todos.toList());
  }

  @override
  Future<void> delete(Todo todo) async {
    _todos.remove(todo);
    await _storage.write('todos', _todos.toList());
  }

  @override
  Future<void> update(Todo todo) async {
    final index = _todos.indexWhere((t) => todo == t);
    if (index >= 0) {
      _todos[index] = todo;
      await _storage.write('todos', _todos.toList());
    }
  }

  @override
  List<Todo> getAll() {
    final todos = _storage.read<List>('todos');
    if (todos != null) {
      _todos.assignAll(todos.map((json) => Todo.fromJson(json)));
    }
    return _todos.toList();
  }
}

在上述代码中,我们使用RxList来定义响应式列表,可以在待办事项列表发生变化时自动通知相关的组件。通过使用GetStorage,我们可以将待办事项数据存储在本地,以便下次启动应用程序时可以恢复数据。Getx会自动管理TodoRepository的生命周期,确保它只被创建一次,并在需要时注入到组件中。

接下来,我们需要定义一个待办事项列表页面:


class TodoListPage extends StatelessWidget {
  final TodoRepository todoRepository = Get.find(); // 通过依赖注入获取待办事项数据存储服务

  @override
  Widget build(BuildContext context) {
    final todos = todoRepository.getAll();
    return Scaffold(
      appBar: AppBar(
        title: Text('Todos'),
      ),
      body: ListView.builder(
        itemCount: todos.length,
        itemBuilder: (context, index) {
          final todo = todos[index];
          return ListTile(
            title: Text(todo.title),
            subtitle: Text(todo.description),
            trailing: IconButton(
              icon: Icon(Icons.delete),
              onPressed: () => todoRepository.delete(todo),
            ),
            onTap: () => Get.toNamed('/todo/detail', arguments: todo),
          );
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => Get.toNamed('/todo/add'),
        tooltip: 'Add Todo',
        child: Icon(Icons.add),
      ),
    );
  }
}

在上述代码中,我们通过依赖注入来获取TodoRepository的实例,并使用它来管理待办事项列表的状态。当待办事项列表发生变化时,RxList会自动通知相关的组件进行更新。

我们还可以通过调用TodoRepository的delete方法来删除待办事项。通过使用Getx的状态管理功能,我们可以轻松实现待办事项列表页面,并且实现组件之间的解耦、可测试性和可维护性。

接下来,我们需要定义一个添加待办事项页面:

class TodoAddPage extends StatelessWidget {
  final TodoRepository todoRepository = Get.find(); // 通过依赖注入获取待办事项数据存储服务
  final TextEditingController titleController = TextEditingController();
  final TextEditingController descriptionController = TextEditingController();
  final TextEditingController dateController = TextEditingController();

  void _addTodo() async {
    final title = titleController.text;
    final description = descriptionController.text;
    final date = DateTime.parse(dateController.text);
    final todo = Todo(title, description, date);
    await todoRepository.add(todo);
    Get.back(); // 返回上一页
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Add Todo'),
      ),
      body: Padding(
        padding: EdgeInsets.all(16),
        child: Column(
          children: [
            TextField(
              controller: titleController,
              decoration: InputDecoration(
                labelText: 'Title',
              ),
            ),
            TextField(
              controller: descriptionController,
              decoration: InputDecoration(
                labelText: 'Description',
              ),
            ),
            TextField(
              controller: dateController,
              decoration: InputDecoration(
                labelText: 'Date (YYYY-MM-DD)',
              ),
            ),
            SizedBox(height: 16),
            ElevatedButton(
              onPressed: _addTodo,
              child: Text('Add Todo'),
            ),
          ],
        ),
      ),
    );
  }
}

在上述代码中,我们通过依赖注入来获取TodoRepository的实例,并使用它来添加待办事项。通过调用Get.back()方法,我们可以返回到上一页。在这个页面中,我们还使用了TextField来获取输入的待办事项的标题、描述和日期。

最后,我们需要定义一个编辑待办事项页面:

class TodoDetailPage extends StatelessWidget {
  final TodoRepository todoRepository = Get.find(); // 通过依赖注入获取待办事项数据存储服务
  final Todo todo;

  final TextEditingController titleController =TextEditingController(); // 创建三个文本编辑器来显示待办事项的标题、描述和日期
  final TextEditingController descriptionController = TextEditingController();
  final TextEditingController dateController = TextEditingController();

  TodoDetailPage(this.todo) : titleController = TextEditingController(text: todo.title),            descriptionController = TextEditingController(text: todo.description), 
  dateController = TextEditingController(text: todo.date.toString());

void _updateTodo() async { 
   final title = titleController.text; 
   final description = descriptionController.text; 
   final date = DateTime.parse(dateController.text); 
   final updatedTodo = Todo(title, description, date);
   await todoRepository.update(updatedTodo);
   Get.back(); // 返回上一页 
   }

@override 
Widget build(BuildContext context) { 
   return Scaffold( appBar: AppBar( title: Text('Todo Detail'), ), 
      body: Padding( padding: EdgeInsets.all(16), 
      child: Column( children: [ 
         TextField( controller: titleController, 
         decoration: InputDecoration( labelText: 'Title', ), ), 
         TextField( controller: descriptionController,
         decoration: InputDecoration( labelText: 'Description', ), ), 
         TextField( controller: dateController, 
         decoration: InputDecoration( labelText: 'Date (YYYY-MM-DD)', ),), 
         SizedBox(height: 16), 
         ElevatedButton( onPressed: _updateTodo, child: Text('Update Todo'),
         ), ], ), ), ); 
         } 
         }

我们通过依赖注入来获取TodoRepository的实例,并使用它来更新待办事项。

在这个页面中,我们通过三个TextField来显示待办事项的标题、描述和日期,并使用TextEditingController来获取用户输入的值。通过调用Get.back()方法,我们可以返回到上一页。

通过以上示例,我们可以看到,Getx的状态管理功能可以帮助我们更加方便地管理Flutter应用程序中的状态,从而提高开发效率和代码质量。


http://www.niftyadmin.cn/n/334257.html

相关文章

cpp test

1. 以下程序在linux 64位系统的输出结果&#xff08; &#xff09; #include <stdio.h> int main(void) {int buf[100] { 0 };printf("%d,%d,%d,%d,%d",sizeof(int), sizeof(long long), sizeof(buf),sizeof(buf)/sizeof(buf[0]), sizeof(&buf));retur…

opencv实践项目-图片拼接之缝合线算法

目录 1. stitcher_detail执行过程2. 源码3. stitching_detail 程序接口介绍4. 执行5. 结果图 1. stitcher_detail执行过程 stitcher_detail是opencv官网提供的一个用于多福图像拼接的Demo&#xff0c;其主要过程如下&#xff1a; 1.输入待拼接图像集合&#xff1b;2.分别对每幅…

360QPaaS参编信通院《组装式应用开发平台研究报告》| 应用前沿

在数字化转型的大背景下&#xff0c;“组装式应用” 成为行业重要战略趋势之一。数字化相较于信息化&#xff0c;强调基于信息数据反哺业务&#xff0c;业务进一步促进系统的迭代优化。组装式应用平台就是一种以业务为中心的模块化组件构成。组装式应用协力提供更灵活的组装式部…

每日算法(第三期)

2023年5月17日 先回顾一下昨天的算法题&#xff0c;及答案 题目&#xff1a;寻找两个有序数组的中位数 给定两个大小分别为 m 和 n 的有序数组 nums1 和 nums2。请你找出这两个有序数组的中位数&#xff0c;并且要求算法的时间复杂度为 O(log(m n))。 你可以假设 nums1 和 num…

243亿美元营收背后,百年龙头的汽车生态砝码

伴随着更为显著的全球汽车新能源化、智能化趋势&#xff0c;汽车产业必将迎来更多新机遇。 一方面&#xff0c;主机厂为保持竞争优势、适应客户多元化需求&#xff0c;不断加快汽车更迭速度&#xff0c;为汽车产业带来了新的市场机遇。另一方面&#xff0c;随着人工智能、云计…

mysql锁概述

第15章 锁 1. 概述 在数据库中&#xff0c;除传统的计算资源&#xff08;如CPU、RAM、I/O等&#xff09;的争用以外&#xff0c;数据也是一种供许多用户共享的资源。为保证数据的一致性&#xff0c;需要对并发操作进行控制&#xff0c;因此产生了锁。同时锁机制也为实现MySQL…

CSDN博客不更新了哦~ 后续在同名的知乎和微信公众号更新

如题。 感谢关注&#xff0c;感兴趣的小伙伴可以关注我同名的知乎和微信公众号哦~

有标签的各种图片大小的宫格拼图

当自己的数据集是从大图中切割下来的小图&#xff08;根据检测框外括一小部分比例的抠图&#xff0c;后续更新此方法&#xff09;&#xff0c;此时数据集一定是大小不一的图片&#xff0c;若每张都直接输入进行训练那么太小的图片会失真严重&#xff0c;本篇对此提出了解决方法…