2017-01-29 13 views
10

Tôi có một ứng dụng hẹn giờ đơn giản trong Rung, hiển thị đếm ngược với số giây còn lại. Tôi có:Làm cách nào để chạy mã trong nền, ngay cả khi màn hình tắt?

new Timer.periodic(new Duration(seconds: 1), _decrementCounter); 

Dường như hoạt động tốt cho đến khi màn hình điện thoại tắt (ngay cả khi tôi chuyển sang ứng dụng khác) và chuyển sang chế độ ngủ. Sau đó, bộ hẹn giờ tạm dừng. Có cách nào được khuyến nghị để tạo một dịch vụ chạy trong nền ngay cả khi màn hình tắt?

+0

Có thể câu hỏi thực sự là: Có thể chạy mã trong nền (ví dụ: hẹn giờ) cho ứng dụng Rung với Hoạt động bị hủy không? Trong trường hợp của tôi, bộ hẹn giờ sẽ tiếp tục chạy ngay cả khi tôi tắt màn hình (xem câu trả lời bên dưới). –

Trả lời

6

Câu trả lời ngắn gọn: không, không thể, mặc dù tôi đã quan sát thấy một hành vi khác nhau cho màn hình sẽ chuyển sang chế độ ngủ. Mã sau đây sẽ giúp bạn hiểu các trạng thái khác nhau của ứng dụng Rung trên Android, được thử nghiệm với các phiên bản Flutter và Flutter Engine này:

  • Sửa đổi khung b339c71523 (6 giờ trước), 2017-02-04 00:51 : 32
  • phiên bản động cơ cd34b0ef39

Tạo một ứng dụng Flutter mới, và thay thế nội dung của lib/main.dart với mã này:

import 'dart:async'; 

import 'package:flutter/material.dart'; 

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

class LifecycleWatcher extends StatefulWidget { 
    @override 
    _LifecycleWatcherState createState() => new _LifecycleWatcherState(); 
} 

class _LifecycleWatcherState extends State<LifecycleWatcher> 
    with WidgetsBindingObserver { 
    AppLifecycleState _lastLifecyleState; 

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

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

    @override 
    void onDeactivate() { 
    super.deactivate(); 
    } 

    @override 
    void didChangeAppLifecycleState(AppLifecycleState state) { 
    print("LifecycleWatcherState#didChangeAppLifecycleState state=${state.toString()}"); 
    setState(() { 
     _lastLifecyleState = state; 
    }); 
    } 

    @override 
    Widget build(BuildContext context) { 
    if (_lastLifecyleState == null) 
     return new Text('This widget has not observed any lifecycle changes.'); 
    return new Text(
     'The most recent lifecycle state this widget observed was: $_lastLifecyleState.'); 
    } 
} 

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

class MyHomePage extends StatefulWidget { 
    MyHomePage({Key key, this.title}) : super(key: key); 

    final String title; 

    @override 
    _MyHomePageState createState() => new _MyHomePageState(); 
} 

class _MyHomePageState extends State<MyHomePage> { 
    int _timerCounter = 0; 
    // ignore: unused_field only created once 
    Timer _timer; 

    _MyHomePageState() { 
    print("_MyHomePageState#constructor, creating new Timer.periodic"); 
    _timer = new Timer.periodic(
     new Duration(milliseconds: 3000), _incrementTimerCounter); 
    } 

    void _incrementTimerCounter(Timer t) { 
    print("_timerCounter is $_timerCounter"); 
    setState(() { 
     _timerCounter++; 
    }); 
    } 

    @override 
    Widget build(BuildContext context) { 
    return new Scaffold(
     appBar: new AppBar(
     title: new Text(config.title), 
    ), 
     body: new Block(
     children: [ 
      new Text(
      'Timer called $_timerCounter time${ _timerCounter == 1 ? '' : 's' }.', 
     ), 
      new LifecycleWatcher(), 
     ], 
    ), 
    ); 
    } 
} 

Khi khởi chạy ứng dụng, giá trị của _timerCounter được tăng lên mỗi 3 giây. Một trường text bên dưới quầy sẽ hiển thị bất kỳ AppLifecycleState thay đổi cho các ứng dụng Flutter, bạn sẽ thấy đầu ra tương ứng trong Flutter debug log, ví dụ:

[[email protected]:~/flutter/helloworld]$ flutter run 
Launching lib/main.dart on SM N920S in debug mode... 
Building APK in debug mode (android-arm)...   6440ms 
Installing build/app.apk...       6496ms 
I/flutter (28196): _MyHomePageState#constructor, creating new Timer.periodic 
Syncing files to device... 
I/flutter (28196): _timerCounter is 0 

    To hot reload your app on the fly, press "r" or F5. To restart the app entirely, press "R". 
The Observatory debugger and profiler is available at: http://127.0.0.1:8108/ 
For a more detailed help message, press "h" or F1. To quit, press "q", F10, or Ctrl-C. 
I/flutter (28196): _timerCounter is 1 
I/flutter (28196): LifecycleWatcherState#didChangeAppLifecycleState state=AppLifecycleState.paused 
I/flutter (28196): _timerCounter is 2 
I/flutter (28196): _timerCounter is 3 
I/flutter (28196): LifecycleWatcherState#didChangeAppLifecycleState state=AppLifecycleState.resumed 
I/flutter (28196): _timerCounter is 4 
I/flutter (28196): LifecycleWatcherState#didChangeAppLifecycleState state=AppLifecycleState.paused 
I/flutter (28196): _timerCounter is 5 
I/flutter (28196): _timerCounter is 6 
I/flutter (28196): _timerCounter is 7 
I/flutter (28196): LifecycleWatcherState#didChangeAppLifecycleState state=AppLifecycleState.resumed 
I/flutter (28196): LifecycleWatcherState#didChangeAppLifecycleState state=AppLifecycleState.paused 
I/flutter (28196): _timerCounter is 8 
I/flutter (28196): _MyHomePageState#constructor, creating new Timer.periodic 
I/flutter (28196): _timerCounter is 0 
I/flutter (28196): _timerCounter is 1 

Đối với các dữ liệu ghi nhận ở trên, sau đây là các bước tôi đã làm :

  1. Khởi chạy ứng dụng với flutter run
  2. Chuyển sang ứng dụng khác (_timerCounter giá trị 1)
  3. Return to ứng dụng Flutter (_timerCounter giá trị 3)
  4. nút nguồn Pressed, màn hình tắt (giá trị _timerCounter 4)
  5. điện thoại Unlocked, Flutter ứng dụng trở lại (giá trị _timerCounter 7)
  6. Pressed lại nút trên điện thoại (giá trị _timerCounter không thay đổi). Đây là thời điểm mà FlutterActivity bị phá hủy và Dart VM Isolate là tốt.
  7. ứng dụng Flutter nối lại (giá trị _timerCounter là 0 nữa)

Chuyển đổi giữa các ứng dụng, nhấn điện hoặc nút quay lại
Khi chuyển sang ứng dụng khác, hoặc khi nhấn nút nguồn để bật của màn hình hẹn giờ tiếp tục chạy. Nhưng khi nhấn nút quay lại trong khi ứng dụng Rung có tiêu điểm, Hoạt động sẽ bị hủy và với Dart cô lập. Bạn có thể kiểm tra điều đó bằng cách kết nối với Dart Observatory khi chuyển đổi giữa các ứng dụng hoặc xoay màn hình. Đài quan sát sẽ hiển thị một ứng dụng Flutter hoạt động Cô lập chạy. Nhưng khi nhấn nút quay lại, Đài quan sát sẽ không hiển thị Isolate đang chạy. Hành vi này đã được xác nhận trên Galaxy Note 5 chạy Android 6.x và Nexus 4 chạy Android 4.4.x.

vòng đời ứng dụng Flutter và vòng đời Android Đối với các lớp phụ tùng Flutter, chỉ có dừngtiếp tục bang được tiếp xúc. Phá hủy được xử lý bởi Android Activity cho một ứng dụng Android Flutter:

/** 
* @see android.app.Activity#onDestroy() 
*/ 
@Override 
protected void onDestroy() { 
    if (flutterView != null) { 
     flutterView.destroy(); 
    } 
    super.onDestroy(); 
} 

Kể từ khi Dart VM cho một ứng dụng Flutter đang chạy bên trong Hoạt động, VM sẽ được dừng lại mỗi khi Hoạt động bị tiêu diệt.

Flutter Động cơ mã logic
này không trực tiếp trả lời câu hỏi của bạn, nhưng sẽ cung cấp cho bạn một số thông tin nền chi tiết về cách động cơ Flutter xử lý thay đổi trạng thái cho Android.
Tìm kiếm thông qua mã công cụ Rung động trở nên rõ ràng rằng vòng lặp hoạt ảnh bị tạm dừng khi số FlutterActivity nhận được sự kiện Android Activity#onPause. Khi ứng dụng đi vào dừng nhà nước, theo source comment here sau xảy ra:

"Ứng dụng này hiện chưa rõ ràng cho người dùng khi ứng dụng ở trạng thái này, động cơ sẽ không gọi [onBeginFrame. ] gọi lại."

Dựa trên thử nghiệm của tôi, bộ hẹn giờ tiếp tục hoạt động ngay cả khi hiển thị giao diện người dùng bị tạm dừng, điều này có ý nghĩa. Sẽ rất tốt khi gửi sự kiện vào lớp tiện ích bằng cách sử dụng WidgetsBindingObserver khi Hoạt động bị hủy, vì vậy nhà phát triển có thể đảm bảo lưu trữ trạng thái của ứng dụng Rung cho đến khi Hoạt động được tiếp tục.

4

Trả lời câu hỏi về cách triển khai trường hợp bộ đếm thời gian cụ thể của bạn không thực sự phải thực hiện với mã nền. Nói chung chạy mã trong nền là một cái gì đó nản lòng trên hệ điều hành di động.

Ví dụ, iOS Tài liệu thảo luận về mã nền chi tiết hơn ở đây: https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html

hệ điều hành Thay vì điện thoại di động cung cấp apis (giống như một bộ đếm thời gian/báo động/apis thông báo) để gọi lại cho ứng dụng của bạn sau một thời gian cụ thể. Ví dụ trên iOS, bạn có thể yêu cầu ứng dụng của bạn được thông báo/đánh thức tại một thời điểm cụ thể trong tương lai qua UINotificationRequest: https://developer.apple.com/reference/usernotifications/unnotificationrequest Điều này cho phép họ giết/đình chỉ ứng dụng của bạn để tiết kiệm điện tốt hơn. dịch vụ hệ thống để theo dõi các thông báo/báo động/định vị địa lý này, v.v.

Rung hiện không cung cấp bất kỳ trình bao bọc nào cho các dịch vụ hệ điều hành này, tuy nhiên nó vẫn dễ dàng viết bằng cách sử dụng mô hình dịch vụ nền tảng của chúng tôi : flutter.io/platform-services

Chúng tôi đang làm việc trên một hệ thống để xuất bản/chia sẻ dịch vụ chia sẻ như thế này để một lần trên viết tích hợp này (cho biết lập kế hoạch thực hiện một số tương lai của ứng dụng của bạn) tất cả mọi người có thể hưởng lợi.

Riêng biệt, câu hỏi chung chung hơn là "có thể chạy mã Dart nền" (mà không có một FlutterView hoạt động trên màn hình), là "chưa".Chúng tôi có một lỗi trong hồ sơ: https://github.com/flutter/flutter/issues/3671

Trường hợp sử dụng thúc đẩy việc thực thi mã mặt đất đó là khi ứng dụng nhận được thông báo, muốn xử lý thông báo bằng một số mã Dart mà không cần đưa ứng dụng của bạn lên mặt trước. Nếu bạn có các trường hợp sử dụng khác cho mã nền bạn muốn chúng tôi biết, các nhận xét được chào đón nhiều nhất trên lỗi đó!

Các vấn đề liên quan