首页 > 解决方案 > 当后退按钮按下销毁应用程序时,Flutter Android Platform EventChannel 不会停止

问题描述

我正在尝试创建一个颤振应用程序,它使用我正在创建的本机 android 插件的后台服务:一个简单的计数器应用程序,它每 5 秒通过 EventChannel 发送一次计数值。

当我按下后退按钮并且应用程序被销毁时,服务仍在运行(这就是我想要做的)。但是当我再次打开应用程序时,事件接收器不再将数据发送到新的颤动视图。我认为事件通道插件并没有停止。

标签: androidflutter

解决方案


当我们按下后退按钮时,我们的应用程序就会被破坏。因此 EventSink(位于我们的 Native Code 中)无法将数据发送到我们的 Flutter 端。

您可以在控制台中看到此消息:尝试向 Flutter 发送平台消息,但 FlutterJNI 已与原生 C++ 分离。无法发送。通道:com.example.timestamp_saver 响应 ID:0 这里 com.example.timestamp_saver 是事件通道名称。

因此,要在按下返回按钮后再次打开应用程序时再次开始收听事件,您需要再次开始收听该频道,当您的应用程序状态处于“恢复”按下某个按钮时,您可以执行此操作。

要根据应用程序状态执行此操作,请按照以下步骤操作 -

  1. 所以首先用WidgetsBindingObserver实现你的有状态小部件

  2. 然后在 initState() 方法和 dispose()

      @override
      void initState() {
       super.initState();
       WidgetsBinding.instance.addObserver(this);
       }
    
      @override
      void dispose() {
      WidgetsBinding.instance.removeObserver(this);
      super.dispose();
      }
    
  3. 现在覆盖 didChangeAppLifecycleState(AppLifecycleState state) 并在 Flutter 中获取应用程序的当前状态。 或者 您也可以在按下某些刷新按钮时开始收听事件接收器

    @override
    void didChangeAppLifecycleState(AppLifecycleState state) {
     print('state = $state');
     if(state == AppLifecycleState.resumed)
       {
         //start listening to the Event Sink again
         listenData();
       }
     }
    

这是 listenData() 方法 -

void listenData() async {
 if(Platform.isAndroid){
        var eventChannel = EventChannel("com.example.timestamp_saver");
        eventChannel.receiveBroadcastStream("Just Listen").listen((event) async {
         debugPrint("Inside Listen Data");
         debugPrint(event);
      });
     }
   } 
  1. 这是我的示例代码,其中我每 5 秒更新一次带有时间戳的列表。在这种情况下,当用户按下返回按钮时,侦听器将使用 EventSink 发出的数据进行更新,因此在这种情况下,我将数据保存到数据库和当用户再次打开应用程序时,我正盯着同一个频道再次收听。

主要.dart

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:timestamp_saver/db/db_helper.dart';
import 'package:timestamp_saver/db/timestamp_model.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(),
    );
  }
}

 class MyHomePage extends StatefulWidget {
   @override
   _MyHomePageState createState() => _MyHomePageState();
 }

 class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver {
   DBHelper _dbHelper;
   List<TimeStampModel> timeStampList;

   @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    _dbHelper = DBHelper();
  }

   @override
   void dispose() {
     WidgetsBinding.instance.removeObserver(this);
     super.dispose();
   }
 

   @override
   Widget build(BuildContext context) {
     return Scaffold(
         appBar: AppBar(),
         body: Container(
           child: Column(
             children: [
               RaisedButton(
                 onPressed: (){startServiceAndReceiveUpdatea();},
                 child: Text("Start"),
               ),
               SizedBox(height: 20,),
               RaisedButton(
                 onPressed: (){listenData();},
                 child: Text("Listen"),
               ),
               Expanded(
                   child: FutureBuilder<List<TimeStampModel>>(
                       future: _dbHelper.getTimeStampModels(),
                       builder: (context, snapshot) {
                          if(snapshot.hasData)
                            {
                              timeStampList = snapshot.data;
                              return ListView.builder(
                                   itemCount: timeStampList.length,
                                  itemBuilder: (context, index) => ListTile(
                                    title: Text(timeStampList[index].timestamp),
                                  ),
                              );
                            }else if(snapshot.hasError)
                            return Center(child: Text("Error"),);
                          else
                            return Center(child: CircularProgressIndicator(),);
                       },
                   )
               )
             ],
           ),
         )
     );
   }

  

   void startServiceAndReceiveUpdatea() async
   {
     if(Platform.isAndroid){
       var eventChannel = EventChannel("com.example.timestamp_saver");
       eventChannel.receiveBroadcastStream("startService").listen((event) async {
         debugPrint("Listner called in dart");
         debugPrint(event);
         TimeStampModel timeStamp = TimeStampModel(id: null,timestamp: event);
         setState(() {

         });
    });
     }
   }

   void listenData() async
   {
     if(Platform.isAndroid){
       var eventChannel = EventChannel("com.example.timestamp_saver");
       eventChannel.receiveBroadcastStream("Just Listen").listen((event) async {
         debugPrint("Inside Listen Data");
         debugPrint(event);
         TimeStampModel timeStamp = TimeStampModel(id: null,timestamp: event);
         setState(() {

         });

       });
     }
   }


}

MainActivity.java

package com.example.timestamp_saver;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.Observer;
import java.nio.ByteBuffer;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugins.GeneratedPluginRegistrant;

public class MainActivity extends FlutterActivity {

    private Intent forService;
    static EventChannel.EventSink events;
    @Override
    public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
        super.configureFlutterEngine(flutterEngine);
        GeneratedPluginRegistrant.registerWith(flutterEngine);
        forService = new Intent(MainActivity.this,MyService.class);
 new EventChannel(flutterEngine.getDartExecutor(),"com.example.timestamp_saver").setStreamHandler(new EventChannel.StreamHandler() {
            @Override
            public void onListen(Object arguments, EventChannel.EventSink events) {
                MainActivity.events = events;
                System.out.println("On Listen in Activity called");
                     if(arguments.equals("startService"))
                     {
                         System.out.println("if");
                         startService();
                    }else if(arguments.equals("Just Listen")){
                         System.out.println("Just Listen");
                     }
            }

            @Override
            public void onCancel(Object arguments) {

            }
        });

    }

    private void startService(){
       if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
            startForegroundService(forService);
        } else {
            startService(forService);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }
}

我的服务.java

package com.example.timestamp_saver;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.PowerManager;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.lifecycle.LifecycleService;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import io.flutter.plugin.common.EventChannel;

public class MyService extends LifecycleService {

    MutableLiveData<String> stringMutableLiveData = new MutableLiveData<>();
    int timerCount = 0;
    private PowerManager.WakeLock wl;
    private DBManager dbManager;
    @Override
    public void onCreate() {
        super.onCreate();
        dbManager = new DBManager(this);
        dbManager.open();
        //Creating a partial wake lock,Because if we don't create wake lock then CPU Will stop working when
        //screen will be locked,which will cause timer to work inconsistently.

        //This solution can be modified more.For example Acquire the Wake Lock when user locks the screen and release
        //it when phone gets unlock.This can be achieved using Brodcast Receiver.
        //Because Wake Lock consumes much power,so use it properly.
        PowerManager pm = (PowerManager)  getSystemService(Context.POWER_SERVICE);
        wl =  pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"a:waketag");
        wl.acquire();
        //stringMutableLiveData = new MutableLiveData<>();
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
            NotificationCompat.Builder builder = new NotificationCompat.Builder(this,"messages")
                    .setContentText("This is running in Background")
                    .setContentTitle("Flutter Background")
                    .setSmallIcon(R.drawable.launch_background);

            startForeground(101,builder.build());
        }

        timerLogic();

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    void timerLogic()
    {
        stringMutableLiveData.observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                System.out.println("On Changed");
                if(MainActivity.events != null) {
                    dbManager.insert(s);
                    MainActivity.events.success(s);
                }
                else
                    System.out.println("Event is null");
            }
        });
         

        Timer timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                timerCount++;
                DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
                Calendar cal = Calendar.getInstance();
                String timerString = dateFormat.format(cal.getTime());
                System.out.println(timerString+": "+timerCount);
                stringMutableLiveData.postValue(timerString);

            }
        },1000,5000);
    }

    @Override
    public void onDestroy() {
        //Remember to relese wake lock
        wl.release();
        super.onDestroy();

    }
}












 

推荐阅读