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 s或Stream 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]
}
第五步:返回非可序列化的提供者函数
我们还提供了一种特殊类型的函数,叫做ProviderFunction 。ProviderFunction ,可以从主线程中调用。它向主线程返回一个不可序列化的值,这对于你想返回一个对象或默认不被序列化的数据(例如,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里面做,而是需要创建一个隔离。
你也有不同的选择,如果你不想要任何线程,或者你想要一些线程,你可以使用隔离器。这个想法是,你将创建一个新的线程,与你的主程序代码并行运行。最好记住,你不能在两个线程之间共享任何状态,而是要通过消息传递或通过通道传递数据进行通信。