RemoteViews can only be used once ,if not ,it may cause ANR in hosts such as Laucher

这两天研究flutter downloader (插件flutter_downloader: ^1.5.0)时遇到上面一个错误。 

 我需要在download callback fuction中获取下载进度并显示

 

首先在initState()中实现了
pr = new ProgressDialog(context, type: ProgressDialogType.Download);
这是一个用来显示下载进度的RemoteView,
然后再flutter download callback中用如下方式调用:
static void downloadCallback(String id, DownloadTaskStatus status, int progress) {

  // 打印输出下载信息

  print('tvwidget Download task ($id) is in status ($status) and process ($progress)');



  if (!pr.isShowing()) {

    pr.show();

  }
……
}
编译没错,但是再运行的时候抛出如题的错误,貌似ProgressDialog 这个remoteview 调用地方不对。
于是查看了如下方法源码,
static registerCallback(DownloadCallback callback) {

  assert(_initialized, 'FlutterDownloader.initialize() must be called first');



  final callbackHandle = PluginUtilities.getCallbackHandle(callback);

  assert(callbackHandle != null,

      'callback must be a top-level or a static function');

  _channel.invokeMethod(

      'registerCallback', <dynamic>[callbackHandle.toRawHandle()]);

}
源码看不出来对downloadcallback有什么要求,但是源码上面有一大段关于callback的注释
///

/// Register a callback to track status and progress of download task

///

/// **parameters:**

///

/// * `callback`: a top-level or static function of [DownloadCallback] type

/// which is called whenever the status or progress value of a download task

/// has been changed.

///

/// **Note:**

///

/// Your UI is rendered in the main isolate, while download events come from a

/// background isolate (in other words, codes in `callback` are run in the

/// background isolate), so you have to handle the communication between two

/// isolates.
大概意思是说callbackfunction 必须是一个top-level或者static function, 而且并不运行再main isolate中,而是运行再 background isolate中。 而ui的刷新需要再main isolate中进行,所以才会出现如题的错误。
这段注释后面写出了一个example,写出如何将callbackfunction里的信息传递到main isolate中执行/// {@tool sample}

///

/// ```dart

///

ReceivePort _port = ReceivePort();

 @override

 void initState() {

   super.initState();



   IsolateNameServer.registerPortWithName(_port.sendPort, 'downloader_send_port');

   _port.listen((dynamic data) {

      String id = data[0];

      DownloadTaskStatus status = data[1];

      int progress = data[2];

      setState((){ });

   });

   FlutterDownloader.registerCallback(downloadCallback);

 }


static void downloadCallback(String id, DownloadTaskStatus status, int progress) {

   final SendPort send = IsolateNameServer.lookupPortByName('downloader_send_port');

   send.send([id, status, progress]);

 }
IsolateNameServer 通过注册的监听端口来获取从background isolate中发过来的消息,再端口监听回调是再Main isolate 中执行,所以在这个_port.listen()中执行刷新进度条内容,就没有如题的错误。
通过本问题解决主要明确两点:
  1. widget 和remoteview widget的刷新主要在Main isolate中进行, 不能在background isolate中直接调用
  2. 使用IsolateNameServer 来进行background isolate 和main isolate 之间的信息传递, 跟android里面的Handler功能一样
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值