学习Flutter应用程序中的线程和隔离器

254 阅读6分钟

Flutter应用程序中的线程和隔离器

线程和隔离是你在使用Flutter开发应用程序时需要了解的两个基本抽象。

线程和隔离器允许开发者利用多核处理器,通过减少移动设备上的UI卡顿和电池消耗来改善用户体验。

线程是合作、非抢占式多任务(软件线程)的实现,而隔离器是一个带有事件循环的线程,它在自己的内存空间中持续处理事件。

前提条件

在我们开始之前,读者需要具备以下条件。

  • 安装了[Visual Studio]或任何代码编辑器。
  • 对[flutter小部件]有基本了解。
  • 熟悉dart编程语言。
  • 对开发flutter应用程序有基本了解。

目标

在本教程结束时,读者应更好地理解线程和隔离器,以及何时适合使用它们。

Flutter中的隔离器

您可以将隔离器与线程一起使用,以提高应用程序的性能并减少移动设备上的电池消耗。隔离器与其他编程语言的线程概念类似,但它们有一些关键的区别。

你可以使用Isolate API来生成新的隔离器;你可以在隔离器和其父线程之间传递消息。但是,你不能从一个隔离体中直接访问共享的可变状态。

应用开发

为了演示它们的用法,我们将建立一个简单的反例。一个从初始值为0开始的应用程序,允许用户增加或减少该值。

该应用程序有一个按钮,可以启动一个新的计数器。当相应的隔离线程被创建时,我们将在一个变量中存储其实例,并通过各种消息处理程序来更新当前的计数器值。隔离线程的实例被存储在一个名为_isolate 的类成员变量中。

让我们开始吧!

第一步:创建状态

在这一步,我们将创建一个负责计数器的类。计数器类将包含用于创建新状态的 createstate 方法。最后,隔离器将处理应用程序的计数器以及我们隔离器中的变化。

在下面的代码片断中,以//[START isolate]开头的注释意味着一个孤立的线程已经开始。以//[END isolate]开头的注释意味着相应的隔离被终止了。

/// Flutter Widget to display a counter and increment it.
class Demo extends StatefulWidget {
@ override _DemoState createState ( ) = > _DemoState ( ) ;
} /// Class responsible for the counter business logic
class _DemoState extends State < Demo> { int _counter = 0 ; // [START isolate] 
static MyIsolate _isolate ;
 // [END isolate]
  @ override void initState ( ) { super . initState ( ) ; _isolate = new MyIsolate ( ) . spawnFunction (
  incrementCounter ) ; 
  // [START isolate] 
  setInterval ( updateCounter , 1000 ) ;
   // [END isolate]
  } @ override void dispose ( bool disposing ) {
   super . dispose ( disposing ) ; if ( disposing && _isolate != null ) {
  _isolate . killFunction ( incrementCounter ) ; } // [START isolate] 
  _isolate = null ;
   // [END isolate]
    }

第二步:通过 isolate 发送消息

接下来,我们将演示如何将一条消息从主线程通过隔离区再传回来。这样做的目的是为了在不破坏隔离区封装的情况下,允许对隔离区的数据进行更新。

  void incrementCounter(MyMessage msg) { // [START isolate] 
  _isolate . send ( new IncrementCounter ( currentCounter :
  _counter + 1 ) ) ; 
  // [END isolate]
   }
    /// Sends a message to update the counter. 
    void incrementCounter ( int delta ) {
  // [START isolate]
  _isolate . send ( new IncrementCounter ( currentCounter : _counter + delta ) ) ;
   // [END isolate] 
   }
  /// Sends a message to update the counter. 
  void incrementCounter ( MyMessage msg ) { // [START isolate]
   _isolate . send ( new IncrementCounter ( currentCounter : _counter + 1 , message : msg ) ) ; 
   // [END isolate] 
   }

第三步:在线程之间传递参数

这一步将涉及从main 线程向isolate 线程传递一个参数。

注:注意,这个参数必须是可序列化的。不可能跨越隔离的边界发送Future sStream s

如果你想顺便传递一个Future ,请看下一节。

  void incrementCounter(int delta, bool start) { 
    // [START isolate] 
  _isolate . send ( new IncrementCounter (
  currentCounter : _counter + delta , isStarting : start ) ) ; 
  // [END isolate]
   } 
   /// Sends a message to update the
  counter with a value of newValue and /// with isStarting set to true if the start parameter is non-null. 
  void  incrementCounter ( MyMessage msg , bool start ) { // [START isolate] 
  _isolate . send ( new IncrementCounter (
  currentCounter : _counter + 1 , message : msg , isStarting : start ) ) ; 
  // [END isolate]
   } /// Sends a message to  update the counter with a value of newValue and /// with isStarting set to true if start parameter is non-null. void
  incrementCounter ( MyMessage msg , int newValue , bool start ) { 
    // [START isolate] 
  _isolate . send ( new
  IncrementCounter ( currentCounter : _counter + newValue , isStarting : start ) ) ; 
  // [END isolate] }

第4步:消息的序列化

隔离边界还可以将消息传递给main 线程。这些消息必须是可序列化的。如果你想从隔离的类中得到一个事件的反馈,请看对消息和事件的响应。

  void incrementCounter() { 
    // [START isolate] 
    _isolate . send ( new IncrementCounterCallback ( ) { 
      void onMessage ( MyMessage msg ) { 
        if ( msg . type == 0 && msg . data != null && msg . data is int i ) { 
    // [START isolate]
    update counter with the parameter from the main thread _counter = ( int ) msg . data ;
    // [END isolate] 
    } else if ( msg . type == 1 && msg . data != null && msg . data is MyMessage m ) { 
      // [START isolate] 
    update counter with the parameter from the main thread _counter += ( int ) m . data ; 
    // [END isolate]
     }
      }
       }
        ) ; 
        // [END isolate]
     } /// Sends a message
  to update the counter. void incrementCounter ( IncrementCounterCallback callback ) { 
    // [START isolate] _isolate .
  send ( new IncrementCounterProviderFunction ( callback : callback . onMessage , messageType : 0 , dataType : 1 ) ) ;
  // [END isolate] 
  } /// Sends a message to update the counter. 
  void incrementCounter ( IncrementCounterCallback
  callback ) { 
    // [START isolate] 
    _isolate . send ( new IncrementCounterProviderFunction ( callback : callback .
  onMessage , messageType : 0 ) ) ; 
  // [END isolate] 
  } 
  /// Adds a function that can be called from the main thread. 
  void incrementCounter ( IncrementCounterProviderFunction callback ) { 
    // [START isolate] 
    _isolate . send ( new
  IncrementCounterProviderFunction ( onMessage : callback . onMessage , messageType : 0 , dataType : 1 ) ) ; 
  // [END  isolate] 
  }

第五步:返回非可序列化的提供者函数

我们还提供了一种特殊类型的函数,叫做ProviderFunctionProviderFunction ,可以从主线程中调用。它向主线程返回一个不可序列化的值,这对于你想返回一个对象或默认不被序列化的数据(例如,std::shared_ptr)的情况很有帮助。

下面是一个例子。

 /// Sends a message to update the counter with a value of newValue and /// with isStarting set to true if start
 the parameter is non-null.
  void incrementCounter ( MyMessage msg , int newValue , bool start ) { // [START isolate] 
  _isolate . send ( new   IncrementCounterProviderFunction ( callback : msg . onMessage , messageType : 0 , dataType : 1 ) ) ; 
  // [END isolate]
  } 
  /// Sends a message to update the counter. 
  void incrementCounter ( MyMessage msg , bool start ) { 
    // [START isolate]
  _isolate . send ( new IncrementCounterProviderFunction ( callback : msg . onMessage , messageType : 0 ) ) ; 
  // [END   isolate] 
  } /// Sends a message to update the counter. 
  void incrementCounter ( MyMessage msg , int newValue ) { //  [START isolate] 
  _isolate . send ( new IncrementCounterProviderFunction ( callback : msg . onMessage , messageType : 0
  , dataType : 1 ) ) ; 
  // [END isolate] 
  } 
  /// Increments the counter. 
  void incrementCounter ( MyMessage msg , int
  newValue = 32 ) { // [START main] 
  _counter += newValue return IncrementCounterProviderFunction ( callback : this .onUpdate , messageType : 0 , dataType : 1 , newValue : newValue ) ; } /// Increments the counter. 
  void incrementCounter ( MyMessage msg , int newValue = 32 ) { 
    // [START main] 
  _counter += newValue return
  IncrementCounterProviderFunction ( callback : this . onUpdate , messageType : 0 , dataType : 1 ) ; }

这使得封装和分组标准回调函数变得更容易,而不是为每个不同的参数组合设置一个函数。

注意:IncrementCounterProviderFunction (或称ProviderFunction)是由NGMessageComposeViewController 提供的一个实用的函数,而不是隔离的。然而,我们提供这种方便的方法来简化代码,以使开发人员能够少写一些模板代码。

呼叫

下面是一个例子,说明你如何从客观C语言中调用这个方法。

@interface ViewController: 
  UIViewController < UITableViewDataSource, 
  UITableViewDelegate> 
@property(strong, nonatomic)
  NSMutableArray * idsToUpdate;
@end /// Sends a message to update the counter. 
-( void ) sendUpdateCounter : ( int ) count callback : (
  IncrementCounterCallback ) 
  callback { // [START isolate] 
  _isolate . send (UITableViewDelegate,  NGMessageComposeViewControllerDelegate> { 
    @public id<IncrementCounterProviderFunction>
    _incrementCounterCallback; id
  <IncrementCounterCallback> 
  _incrementCounterCallbackWithMessageTypeAndDataTypes; } 
 @end

下面是一个如何从swift中调用这个的例子。

/// Sends a message to update the value. func incrementValue () -> IncrementValueProvider { return
IncrementValueProvider( callback : self.onIncrementValue, messageType: 0, dataType: 1 ) } /// Increments the
value by a given amount. func incrementBy (amount: Int) { // [START isolate] let provider =
IncrementValueProvider( callback: self.onUpdate, messageType: 0,Thread and Isolate in flutter.

总结

实际情况是,你可以在Flutter中使用线程来帮助你提高应用程序的性能。然而,由于你使用的是Dart,你不能直接在widget里面做,而是需要创建一个隔离。

你也有不同的选择,如果你不想要任何线程,或者你想要一些线程,你可以使用隔离器。这个想法是,你将创建一个新的线程,与你的主程序代码并行运行。最好记住,你不能在两个线程之间共享任何状态,而是要通过消息传递或通过通道传递数据进行通信。