Больше всех пахала лошадь, но председателем колхоза так и не стала



    В последнее время в мобильном сообществе часто можно услышать про Flutter, React Native. Мне стало интересно понять профит от этих штук. И насколько они реально изменят жизнь при разработке приложений. В итоге было создано 4 (одинаковых с точки зрения выполняемых функции) приложения: нативное Android, нативное iOS, Flutter, React Native. В этой статье я описал то, что вынес из своего опыта и как реализуются схожие элементы приложений в рассматриваемых решениях.

    Комментарии: автор статьи не является профессиональным кроссплатформенным разработчиком. И все о чем написано — это взгляд начинающего разраба под эти платформы. Но думаю, этот обзор будет полезен людям, уже использующим одно из рассматриваемых решений, и которые смотрят в сторону того, чтобы писать приложения под две платформы или улучшить процесс взаимодействия iOS и Android.

    В качестве разрабатываемого приложения было решено сделать “Спортивный Таймер”, который поможет людям, занимающимся спортом, при выполнении интервальных тренировок.

    Приложение состоит из 3 экранов.


    Экран работы таймера


    Экран истории тренировок


    Экран настроек таймера

    Мне это приложение интересно как разрабу, потому что его создании будут затронуты следующие интересующие меня компоненты:
    — Верстка
    — Custom View
    — Работа с UI списками
    — Многопоточность
    — База данных
    — Сеть
    — key-value хранилище

    Важно заметить, что для Flutter и React Native мы можем создать мост (канал) в нативную часть приложения и с его помощью реализовать все то, что предоставляет операционная система. Но мне было интересно, что фреймворки дают из коробки.

    Выбор средств для разработки


    Для нативного приложения под iOS — я выбрал среду разработки XCode и язык программирования Swift. Для нативного Android — Android Studio и Kotlin. React Native разрабатывал в WebStorm, язык программирования JS. Flutter — Android Studio и Dart.

    Интересным фактом при разработке на Flutter мне показалось то, что прямо из Android Studio (главной IDE для Android разработки) можно запустить приложение на iOS устройстве.



    Структура проектов


    Структуры нативного iOS и Android проектов очень схожи. Это файл для верстки с расширениями .storyboard (iOS) и .xml (Android), менеджеры зависимостей Podfile(iOS) и Gradle(Android), файлы исходного кода с расширениями .swift (iOS) и .kt(Android).


    Структура проекта Android


    Структура проекта iOS

    Структуры Flutter и React Native содержат папки Android и iOS, в которых находятся обычные нативные проекты под Android и iOS. Подключается Flutter и React Native к нативным проектам как библиотека. По факту, при запуске Flutter на устройстве iOS запускается обычное нативное приложение iOS с подключенной библиотекой Flutter. Для React Native и под Android все аналогично.

    Также Flutter и React Native содержат менеджеры зависимостей package.json(React Native) и pubspec.yaml(Flutter) и файлы исходного кода с расширениями .js (React Native) и .dart(Flutter) в которых находится и верстка.


    Структура проекта Flutter


    Структура проекта React Native

    Верстка


    Для нативного iOS и Android существуют визуальные редакторы. Это очень упрощает создание экранов.


    Визуальный редактор для нативного Android


    Визуальный редактор для нативного iOS

    Для React Native и Flutter визуальных редакторов нет, но существует поддержка функции горячей перезагрузки, которая хоть как-то упрощает работу с UI.


    Горячая перезагрузка во Flutter


    Горячая перезагрузка в React Native

    В Android и iOS верстка хранится в отдельных файлах с расширениями .xml и .storybord соответственно. В React Native и Flutter верстка происходит прямо из кода. Важным моментом при описании скорости ui нужно отметить то, что у Flutter собственные механизмы рендеринга, при помощи которых создатели фреймворка обещают 60 fps. А React Native использует нативные ui элементы, которые строятся при помощи js, что ведет к их излишней вложенности.

    В Android и iOS для изменения свойства View мы используем ссылку на нее из кода и, например, чтобы изменить цвет фона вызываем изменения у объекта напрямую. В случае React Native и Flutter другая философия: свойства мы меняем внутри вызова setState, а view уже сама перерисовывается в зависимости от измененного состояния.

    Примеры создания экрана таймера для каждого из выбранных решений:


    Верстка экрана таймера на Android


    Верстка экрана таймера на iOS

    Верстка экрана таймера Flutter

      @override
      Widget build(BuildContext context) {
        return Scaffold(
            body: Stack(
              children: <Widget>[
                new Container(
                  color: color,
                  child: new Column(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: <Widget>[
                      Text(
                        " ${getTextByType(trainingModel.type)}",
                        style: new TextStyle(
                            fontWeight: FontWeight.bold, fontSize: 24.0),
                      ),
                      new Text(
                        "${trainingModel.timeSec}",
                        style: TextStyle(
                            fontWeight: FontWeight.bold, fontSize: 56.0),
                      ),
                      new Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: <Widget>[
                          Text(
                            "СЕТЫ ${trainingModel.setCount}",
                            style: TextStyle(
                                fontWeight: FontWeight.bold, fontSize: 24.0),
                          ),
                          Text(
                            "ЦИКЛЫ ${trainingModel.cycleCount}",
                            style: TextStyle(
                                fontWeight: FontWeight.bold, fontSize: 24.0),
                          ),
                        ],
                      ),
                    ],
                  ),
                  padding: const EdgeInsets.all(20.0),
                ),
                new Center(
                  child: CustomPaint(
                    painter: MyCustomPainter(
                        //0.0
                        trainingModel.getPercent()),
                    size: Size.infinite,
                  ),
                )
              ],
            ));
      }
    

    Верстка экрана таймера React Native

           render() {
            return (
                <View style={{
                    flex: 20,
                    flexDirection: 'column',
                    justifyContent: 'space-between',
                    alignItems: 'stretch',
                }}>
                    <View style={{height: 100}}>
                        <Text style={{textAlign: 'center', fontSize: 24}}>
                            {this.state.value.type}
                        </Text>
                    </View>
                    <View
                        style={styles.container}>
                        <CanvasTest data={this.state.value} style={styles.center}/>
                    </View>
                    <View style={{height: 120}}>
                        <View style={{flex: 1}}>
                            <View style={{flex: 1, padding: 20,}}>
                                <Text style={{fontSize: 24}}>
                                    Сет {this.state.value.setCount}
                                </Text>
                            </View>
                            <View style={{flex: 1, padding: 20,}}>
                                <Text style={{textAlign: 'right', fontSize: 24}}>
                                    Цикл {this.state.value.cycleCount}
                                </Text>
                            </View>
                        </View>
    
                    </View>
                </View>
            );
        }
    

    Custom View


    Знакомясь с решениями, мне было важно, чтобы можно было создать абсолютно любой визуальный компонент. То есть рисовать ui на уровне квадратов, кругов и путей. Например, индикатор таймера является такой view.



    Для нативного iOS не было проблем, так как есть доступ к Layer, на котором можно нарисовать все, что угодно.

        let shapeLayer = CAShapeLayer()
        var angle = (-Double.pi / 2
            - 0.000001 + (Double.pi * 2) * percent)
        let circlePath = UIBezierPath(arcCenter: CGPoint(x: 100, y: 100),
            radius: CGFloat(95),
            startAngle: CGFloat(-Double.pi / 2),
            endAngle: CGFloat(angle),
            clockwise: true)
        
        shapeLayer.path = circlePath.cgPa
    

    Для нативного Android можно создать класс, наследующийся от View. И переопределить метод onDraw(Canvas canvas), в параметре которого объект Canvas — на нем и рисуем.

        @Override
        protected void onDraw(Canvas canvas) {
            pathCircleOne = new Path();
            pathCircleOne.addArc(rectForCircle, -90, value * 3.6F);
            canvas.drawPath(pathCircleBackground, paintCircleBackground);
        }
    

    Для Flutter можно создать класс, который наследуется от CustomPainter. И переопределить метод paint(Canvas canvas, Size size), который в параметре передает объект Canvas — то есть очень похожая реализация как в Android.

     @override
      void paint(Canvas canvas, Size size) {
        Path path = Path()
          ..addArc(
              Rect.fromCircle(
                radius: size.width / 3.0,
                center: Offset(size.width / 2, size.height / 2),
              ),
              -pi * 2 / 4,
              pi * 2 * _percent / 100);
        canvas.drawPath(path, paint);
      }
    

    Для React Native решение из коробки не было найдено. Думаю, это объясняется тем, что на js только описывается view, а строится уже нативными ui элементами. Но можно воспользоваться библиотекой react-native-canvas, которая дает доступ к canvas.

       handleCanvas = (canvas) => {
            if (canvas) {
                var modelTimer = this.state.value;
                const context = canvas.getContext('2d');
                context.arc(75, 75, 70,
                    -Math.PI / 2, -Math.PI / 2 - 0.000001 - (Math.PI * 2)
                    * (modelTimer.timeSec / modelTimer.maxValue), false);
            }
        }
    

    Работа с UI списками




    Алгоритм работы для Android, iOS, Flutter — решений очень схож. Нам нужно указать, сколько элементов в списке. И выдать по номеру элемента ту ячейку, которую нужно нарисовать.
    В iOS для рисования списков используют UITableView, в котором нужно реализовать методы DataSource.

        func tableView(_ tableView: UITableView,
                numberOfRowsInSection section: Int) -> Int {
                return  countCell
        }
    
        func tableView(_ tableView: UITableView, 
                cellForRowAt indexPath: IndexPath) -> UITableViewCell {
                return cell
        }
    

    Для Android используют RecyclerView, в адаптере которого, мы реализуем аналогичные IOS методы.

    class MyAdapter(private val myDataset: Array<String>) :
            RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
        override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
            holder.textView.text = myDataset[position]
        }
        override fun getItemCount() = myDataset.size
    }
    

    Для flutter используют ListView, в котором в билдере реализуются аналогичные методы.

    new ListView.builder(
           itemCount: getCount() * 2,
           itemBuilder: (BuildContext context, int i) {
           return new HistoryWidget(
                     Key("a ${models[index].workTime}"), models[index]);
            },
       )
    

    В React Native используют ListView. Реализация схожа с предыдущими решениями. Но здесь нет привязки к номеру и количеству элементов в списке, в DataSource мы задаем список элементов. А в renderRow реализуем создание ячейки в зависимости от того, какой элемент пришел.

    <ListView
                   dataSource={this.state.dataSource}
                   renderRow={(data) => <HistoryItem data={data}/>}  
      />
    

    Многопоточность, асинхронность


    Когда я начал разбираться с многопоточностью, асинхронностью — то ужаснулся разнообразием решений. В iOS — это GCD, Operation, в Android — AsyncTask, Loader, Coroutine, в React Native — Promise, Async/Await, во Flutter- Future, Stream. Принципы некоторых решение схожи, но реализация все же отличается.
    На спасение пришел всеми любимый Rx. Если вы еще не влюблены в него, советую изучить. Он есть во всех рассматриваемых мною решениях в виде: RxDart, RxJava, RxJs, RxSwift.

    RxJava

      Observable.interval(1, TimeUnit.SECONDS)
                    .subscribe(object : Subscriber<Long>() {
                        fun onCompleted() {
                            println("onCompleted")
                        }
    
                        fun onError(e: Throwable) {
                            println("onError -> " + e.message)
                        }
    
                        fun onNext(l: Long?) {
                            println("onNext -> " + l!!)
                        }
                    })
    

    RxSwift

    Observable<Int>.interval(1.0, scheduler: MainScheduler.instance)  
    .subscribe(onNext: { print($0) })
    

    RxDart

       Stream.fromIterable([1, 2, 3])
      .transform(new IntervalStreamTransformer(seconds: 1))
      .listen((i) => print("$i sec");
    

    RxJS

    Rx.Observable
        .interval(500 /* ms */)
        .timeInterval()
        .take(3)
    .subscribe(
        function (x) {
            console.log('Next: ' + x);
        },
        function (err) {
            console.log('Error: ' + err);
        },
        function () {
            console.log('Completed');
        })
    

    Как видите, код выглядит очень схоже на всех четырех языках. Что в будущем, в случае необходимости, облегчит вам переход с одного решения для мобильной разработки к другому.

    База данных


    В мобильных приложениях стандартом является SQLite база данных. В каждом из рассматриваемых решений написана обертка для работы с ней. В Android обычно используют ORM Room.

    В iOS — Core Data. Во Flutter можно воспользоваться плагином sqflite.

    В React Native — react-native-sqlite-storage. Все эти решения спроектированы по-разному. И чтобы приложения выглядели похоже, придется писать Sqlite запросы вручную, без использования оберток.

    Наверное, лучше посмотреть в сторону библиотеки для хранения данных Realm, которая использует своё ядро для хранения данных. Она поддерживается на iOS, Android и React Native. Во Flutter на данный момент поддержки нет, но инженеры Realm работают в этом направлении.

    Realm в Android

    RealmResults<Item> item = realm.where(Item.class) .lessThan("id", 2) .findAll();
    

    Realm в iOS

    let item = realm.objects(Item.self).filter("id < 2")
    

    Realm в React Native

    let item = realm.objects('Item').filtered('id < 2');
    

    Key-value хранилище


    В нативном iOS используется UserDefaults. В нативным Android — preferences. В React Native и Flutter можно пользоваться библиотеками, которые являются оберткой нативных key-value хранилищ (SharedPreference (Android) and UserDefaults (iOS)).

    Android

    SharedPreferences sPref = getPreferences(MODE_PRIVATE);
    Editor ed = sPref.edit();
    ed.putString("my key'", myValue);
    ed.commit();
    

    iOS

    let defaults = UserDefaults.standard
    defaults.integer(forKey: "my key'")
    defaults.set(myValue, forKey: "my key")
    

    Flutter

    SharedPreferences prefs = await SharedPreferences.getInstance();
    prefs.getInt(my key')
    prefs.setInt(my key', myValue)
    

    React Native

    DefaultPreference.get('my key').then(function(value) {console.log(value)});
    DefaultPreference.set('my key', myValue).then(function() {console.log('done')});
    

    Сеть


    Для работы с сетью в нативном iOS и Android есть огромное количество решений. Самые популярные — это Alamofire (iOS) и Retrofit (Android). В React Native и Flutter написаны свои собственные независимые от платформы клиенты для похода в сеть. Все клиенты спроектированы очень схоже.

    Android

    Retrofit.Builder()
           .baseUrl("https://timerble-8665b.firebaseio.com")
           .build()
    
    @GET("/messages.json")
    fun getData(): Observable<Map<String,RealtimeModel>>
    

    iOS

    let url = URL(string: "https://timerble-8665b.firebaseio.com/messages.json")
            Alamofire.request(url, method: .get)
    .responseJSON { response in …
    

    Flutter

    http.Response response = await
    http.get('https://timerble-8665b.firebaseio.com/messages.json')
    

    React Native

    fetch('https://timerble-8665b.firebaseio.com/messages.json')
                .then((response) => response.json())
    

    Время разработки




    Наверно некорректно делать какие-то выводы, исходя из моего времени разработки, так как я являюсь Android-разработчиком. Но думаю, для iOS разработчика вход в технологию Flutter и Android покажется легче, чем в React Native.

    Заключение


    Начиная писать статью, я знал, о чем напишу в выводе. Расскажу, какое решение понравилось больше, какое решения не нужно использовать. Но потом, пообщавшись с людьми, которые пользуются на продакшене этими решениями, понял, что мои выводы некорректны, потому что я смотрю на все со стороны своего опыта. Главное, я понял, что для каждого из рассматриваемых решений, есть свои проекты, для которых оно подходит идеально. И иногда для бизнеса реально выгоднее делать кроссплатформенное приложение, а не пахать над разработкой двух нативных. И если какое-то решение не подходит именно для вашего проекта, не стоит думать, что оно плохое в принципе. Надеюсь, статья будет полезна. Спасибо, что добрались до конца.

    По поводу правок статьи, пожалуйста, пишите в личку, я с удовольствием все поправлю.

    ONETRAK

    69,00

    Компания

    Поделиться публикацией

    Похожие публикации

    Комментарии 50
      0
      Небольшая просьба: укажите, в каких попугаях нарисован последний график. А то сверху «скорость», а на графике «время» (т.е. прямо противоположное). Или хотя бы «чем больше, тем лучше», или наоборот.
        –2
        Спасибо поправил. Там речь о времени
          +1

          Все равно непонятки остались. В чем выражается время? Часы, дни, недели?

        –2
        Как по мне (я писал и под Android, и под React Native, Flutter и iOS не пробовал), продуктивность разработки под React Native такова, что за это время в Android Studio можно в три раза больше функционала реализовать. Но это моё субъективное мнение.
          +4
          Мое субъективное мнение что продуктивность зависит от прямоты рук и понимания языка /фреймворка. Пока соберется приложение из-под Android Studio (Core5/SSD/16Gb) на React Native можно уже пару-тройку компонентов и протестировать.
            0
            Мое субъективное мнение что продуктивность зависит от прямоты рук и понимания языка /фреймворка.

            Ну понятно, что «кадры решают всё», но как правило, радиус кривизны рук у программистов постоянен и не особо зависит от инструмента. Неопытный программист везде мучается, опытный со всем легко разбирается. А инструмент играет большую роль. Взять тот же UI, в Android Studio вы рисуете вьюху в дизайнере, и запускаете посмотреть, по сути, один раз после того, как закончили рисовать. Под RN вы где-нибудь в VS Code описываете компоненту, запускаете, смотрите, рихтуете, перезапускаете, рихтуете, перезапускаете — и это дёрганье так продолжается до получения нужного результата. Это просто непродуктивно.
              +6
              Мусье, а вы точно на Реакте пробовали?
              Раскрою вам секрет, цепляетесь дебаггером к приложению и меняете стили прямо вот налету, без всяких перезапусков, как в браузере в консоли разработчика. Быстрее чем на Андроиде выходит.
                0
                Причем наибольшее преимущество получается на больших проектах, где сборка приложения занимает пару минут, а Instant Run по разным причинам не работает.
          0
          В сравнении реализации списков какая-то не полная картина:
          В android нужно делать create + bind, а в flutter только create, т.к. виджеты flutter легковеснее android views. Что несколько упрощает разработку.
            +7

            А что там с жором батарейки и вообще скоростью запуска и работы приложений?

              –2
              Жор батарейки мною не рассматривался. Насчет скорости — разрабатываемые приложения очень маленькие. Всего 3 экрана. И разницу в скорости визуально ощутить не получилось, так как все приложения выглядят шустро. А программное измерение скорости я не производил
              +9
              Как я понимаю автор топит за Flutter и пишет под Android, ничем иным объяснить график я не могу.
              У других экспериментаторов таких проблем не было (https://hackernoon.com/react-native-vs-flutter-which-is-more-startup-friendly-c6e412d0b9ab, https://hackr.io/blog/react-native-vs-flutter)
                0
                Я не понял как Rx относится к многопоточности? На примере того же Свифта, если сабджект дергается не из основного потока (например делался хттп запрос) то юай так просто из него не проапдейтишь
                  –1
                  Особенно на флаттере. Стримы кстати как и Rx там асинхронно работают, но по идее в том же потоке. В дарте для многопоточности вроде как отдельный механизм применяется, не стримы, изоляты или как то так. Но вообще посмотреть нужно, может можно для разных стрим трансформеров, или как там подобные объекты в Rx называются, задавать потоки выполнения. В нативном андроиде вроде можно было так Rx использовать, недавно смотрел видео
                  Если что я только учусь и сильно за искажения фактов не бейте.
                  Но в целом когда я с флаттером знакомился он мне своей концепцией и простотой понравился кстати.
                    –1
                    Выдержка из статьи про RxSwift
                    оператор — observeOn
                    Указывает, на каком Scheduler должен выполнять свою работу Observer, особенно критично при работе с GUI.
                    example("\"observeOn\"") {
                        DispatchQueue.global(qos: .background).async {
                            Observable
                                .of(1, 2, 3)
                                .observeOn(MainScheduler.instance)
                                .subscribe({ event in
                                    print("Main: \(Thread.isMainThread)\t\tEvent: \(event)")
                                })
                            Observable
                                .of("A", "B", "C")
                                .subscribe({ event in
                                    print("Main: \(Thread.isMainThread)\t\tEvent: \(event)")
                                })
                        }
                    }
                    

                    Консоль:
                    Main: false Event: next(A)
                    Main: false Event: next(B)
                    Main: true Event: next(1)
                    Main: true Event: next(2)
                    Main: true Event: next(3)
                    Main: true Event: completed
                    Main: false Event: next(C)
                    Main: false Event: completed
                      +1
                      А зачем в Реакт тянуть RX, есть там уже есть Promise и Async/Await? Просто для унификации или от нечего делать? Просто странно сравнивать скорость двух лошадей, у одной из которых к ногам привязали костыли, что бы говорить«Ну вот вы видите, не может она быстро бежать»…
                        –1
                        А зачем в Реакт тянуть RX, есть там уже есть Promise и Async/Await?

                        RX вообще не связано никак с promise и async/await.

                          +1
                          Что, серьезно? Я вот почему то думал что согласно своему описанию RXJS это «инструмент для удобного контроля последовательных действий». А если в примере автора он не для этого (из-за нежелания пользоваться встроенными механизмами) то зачем?
                            0
                            Зашел на reactivex.io и контроль последовательности действий там упомянут разве что между прочим.
                              0
                              Ну уж не знаю, не для асинхронности же его ввел автор в проект ReactNative, там как бы изначально все асинхронно. Ваши идеи зачем его добавили?
                                0
                                Поскольку код на реакт нейтиве не смотрел поэтому не могу ответить зачем его там ввел автор, но допустим когда я посматривал на флаттер я стримы и await всякие для заметно разного использовал. await, future не дает реактивности по факту, а Rx или даже просто стримы дают.
                                  0
                                  Цифра с тобой. мой друг :)
                              0
                              Прежде всего, оно дает абстракцию потока событий и механизмы для манипуляций с такими потоками.

                              Да, использование rx исключительно для запросов к бэкэнду неоправдано, и async/await куда проще. Но запросами к бэкенду модель в сложном приложении не ограничивается.
                                0
                                Всякому инструменту свое применение…
                                RX далеко не всегда оправдан даже самим разработчиками ReactiveX.
                                image
                                  0
                                  Табличка тут немного кривая: для Asynchronus Multiple Value есть AsyncIterable. А Observable применимо для push-based потоков независимо от их синхронности.
                                    0

                                    Observable — это просто двойственная к Iterable конструкция со всеми вытекающими.
                                    С асинхронностью это никак не связано все, а правильный аналог в первой колонке — это Get vs OnNext() (= Set)

                        +1
                        надо бросать vb.net.
                        А для теликов (ЛЫЖЫ) что лучше использовать?
                          +1
                          надо бросать тяжёлые препараты :)
                          0
                          Cпасибо за статью, интересно узнать про результат, сравнительные характеристики готовых приложений?
                            0
                            Так как приложения очень маленькие — скорость их работы визуально одинакова. Сначала я думал сравнить сколько будут весить Apk для Android. Но сравнивать размеры тоже было некорректно, т.к.:
                            1)В React Native был добавлен Realm, нативная часть которого очень утяжелила Apk.
                            2)В Android я запихнул кучу библиотек, без которых я считаю, как “истинный Android разработчик“, приложению не обойтись.
                              0

                              И всё-таки, шёпотом, вне зачёта, сколько вышло?

                            +1
                            в копилку для Flutter:
                            встроенного в AS редактора UI нет, но есть такой проектик flutterstudio
                            (спасибо GDGNN и лично Саше Денисову, за то что показал).
                            Возможно в скором времени это и в студию внесут)
                              +1
                              который опять ни в чем кроме хрома не работает?
                                0

                                В safari работает

                                  –2

                                  Я не в курсе) не проверял. В хроме работает и норм.

                                0

                                Возможно, глупый вопрос. При выключении экрана или увода в фон приложения таймер стопорится в каком-то приложении? Давно смотрел Cordova, а там webview, и внутренний JS таймер то ли стопорился совсем, то ли сильно замедлялся.

                                  –1
                                  Тут нужно обратить внимание: при уходе в фон убивается процесс приложения или нет. В ios процесс убивается у свернутого приложения, через некоторое время. И убийство процесса никакой из вариантов не переживет. А если рассматривать ситуацию сворачивания в Android до момента убийства процесса, то Flutter нормально работает и время не останавливается. А в React Native таймер зависает
                                    +1
                                    А вы точно пробовали на React Native писать? https://github.com/ocetnik/react-native-background-timer
                                      0
                                      Я реализовывал таймер через RxJs interval
                                       this.subscription = interval(1000)
                                                  .pipe(take(list.length))
                                                  .subscribe(a => {
                                                      this.timer.show(list[a])
                                                  })
                                      

                                      такой код в моем презентере. Именно в такой реализации таймер стопится. После вопроса я специально запустил приложение и проверил.
                                      Приведенную вами библиотеку я не рассматривал. Но видно, что либа строит мост в native и там уже реализуется таймер. Понятное дело, мне ничто не мешает сделать foreground service в Android, запустить в нем таймер и общатьсяс c js через мост, даже без использование либы. И такой таймер на родных прошивках в Android убиваться не будет в принципе.
                                      То что я писал это про выполнение JS
                                        +1
                                        Пардон, а что, Флаттер как то по другому реализует таймеры, не через foreground service? Всякому инструменту свое место, и в 99% ситуаций таймеру не нужна работа в фоне.
                                        Я понимаю что вы фанат Флаттера, но хотелось бы больше объективности.
                                          +1
                                          Во Flutter при той же реализации что и в React — Native c помощью Rx не стопиться
                                          Вот какая реализация во флатере
                                            subscription = new Observable<ModelTimer>.fromIterable(list)
                                                  .interval(new Duration(seconds: 1))
                                                  .listen((modelTimer) =>
                                          

                                          Я объективно ответил на комментарий — проверив, запустив разработанные приложения
                                            0
                                            Давайте что бы не разводить срач
                                            1. в ReactNative не работает Ваша реализация таймеров на RxJS
                                            2. в ReactNative успешно работают таймеры / процессы в фоне при помощи сторонних модулей


                                            Ведь можно так написать, а не «в React Native таймер зависает». Тут кстати вопрос к Flatter, он все таймеры выносит в foreground service Android или как то сам принимает решения.
                                              0
                                              Rx использует таймеры из стандартной библиотеки без каких-то особых хитростей. Так что правильно писать вот так:

                                              в ReactNative не работает setInterval

                                    0
                                    В активити Cordov'ы на onPause стопорятся таймауты WebView. Таймеры не работают в фоне.
                                    0
                                    Спасибо за статью! Очень хотелось бы все же узнать выводы, хотя бы в комментах :) Пусть это и будет с призмы личного опыта. И почему в выборку не попал популярный ionic?
                                      +1
                                      1)Почему не попал ionic? Потому что, лично для меня, были интересны React Native и Flutter
                                      2)Главное для меня при разработке приложений — это их поддерживаемость. Да, я понимаю, что кроссплатформа быстрее и кажется на первый взгляд выгоднее для бизнеса. Но в долгосрочной перспективе, по моему мнению, она себя не окупит, так как все равно придется писать мост к нативу, когда нужно будет писать что-то специфическое под платформу. Хотя, если я буду писать домашний проект, я склонюсь к Flutter.
                                      0
                                      По поводу скорости загрузки: специально создавал одинаковые приложения-пустышки для Android с использованием Xamarin, Flutter и Native. Оба кроссплатформенных проиграли на старте в разы. Потом, в работе, особой разницы не заметил.
                                        0
                                        -Товарищ несите отвертку! — Мне нужно забить гвоздь

                                        По своему опыту, могу сказать, разработка на кросс платформе занимает в разы больше времени и да и поддерживать это все…, короче для себя экономической выгоды не увидел
                                        Условно, написав за месяц приложение(а 70% времени это бизнес логика) для заказчика под андроид, создать тоже самое на ios займает ~неделю.

                                        +Бизнесу постоянно в голову приходят новые свистелки-хотелки, используя натив я уверен, что задача будет реализована и за вменяемое время.

                                        По моему мнению кросс-платформа подходит если:
                                        Пишите собственную лабуду из разряда «Пацаны смотри, че запилил»
                                        Клепаете на заказ 100500 приложений из разряда «Загрузить данные с сервера и нарисовать список»
                                        Создаете приложения из разряда «Ну хотя б раз рекламу посмотри и можешь удалять»
                                          0
                                          Также склоняюсь к мнению что на данный момент инструменты разработки мобильных кросс платформенных приложений все еще на стадии развития. Да и разработчики ios и Android особо то и не спешат создать совместными усилиями качественную кросс платформенную среду. Вместо этого они, напротив, еще больше плодят языки/инструментарии.
                                          Если посудить, что выбрать новичку в и начать изучать: нативные (native Android и ios), гибридные (Cordova, Phonegap), или кросс платформенные (React Native, Flutter, Xamarin)? Что более приемлемо с точки зрения затраченных усилий и полученных навыков? Для изучение кросс платформенных иснтрументов нужно затратить такое усилие, которое сопоставимо с изучением основ разработки для Android. Да плюс к тому же, для комфортной разработки на кросс платформенных иснтрументах нужны базовые навыки и знания основ разработки для Android и ios. Если нужно создать простое приложение без затрат значительных усилий, то выбор очевиден — Cordova и Phonegap. Получается, учитывая что разработка для ios затратно финансово (нужна машина на MacOS) и у ios меньшая доля рынка, оптимальная стратегия — выбрать либо native Android либо гибридные.
                                          0
                                          А я для своих домашних приложений запускаю на андроиде обычные extends Thread из Java. Вроде работает.

                                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                          Самое читаемое