← Назад к вопросам

Как выполнить задачу подсчета от 1 до 1 млн

2.0 Middle🔥 22 комментариев
#Другое#Многопоточность и асинхронность#Производительность и оптимизация

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Подходы к выполнению задачи подсчета от 1 до 1 миллиона

В Android-разработке задача подсчета до 1 миллиона может быть реализована разными способами в зависимости от требований к производительности, отзывчивости интерфейса и обработке результатов. Основная сложность заключается в том, чтобы не блокировать главный поток (UI-поток), так как длительные операции приведут к "зависанию" интерфейса и вызовут Application Not Responding (ANR).

Основные решения

1. Использование Kotlin Coroutines для асинхронного выполнения

Coroutines — это наиболее современный и рекомендованный способ работы с асинхронными операциями в Android. Они позволяют писать неблокирующий код в последовательном стиле.

import kotlinx.coroutines.*

class CounterViewModel : ViewModel() {
    private val _countResult = MutableStateFlow<String>("")
    val countResult: StateFlow<String> = _countResult.asStateFlow()
    
    fun startCounting() {
        viewModelScope.launch(Dispatchers.Default) {
            val result = StringBuilder()
            for (i in 1..1_000_000) {
                // Основная логика подсчета
                if (i % 100_000 == 0) {
                    // Обновление UI через главный поток
                    withContext(Dispatchers.Main) {
                        _countResult.value = "Достигнуто: $i"
                    }
                }
            }
            _countResult.value = "Подсчет завершен!"
        }
    }
}

2. Использование RxJava для реактивного подхода

RxJava позволяет работать с асинхронными потоками данных, хотя в новых проектах предпочтительнее Coroutines.

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;

Observable.range(1, 1_000_000)
    .subscribeOn(Schedulers.computation())
    .observeOn(AndroidSchedulers.mainThread())
    .doOnNext(i -> {
        if (i % 100_000 == 0) {
            updateUI("Достигнуто: " + i);
        }
    })
    .doOnComplete(() -> updateUI("Подсчет завершен!"))
    .subscribe();

3. Использование Thread и Handler для базовой многопоточности

Это классический подход, который хорошо демонстрирует основы многопоточности в Android.

import android.os.Handler
import android.os.Looper

class CounterThread : Thread() {
    private val mainHandler = Handler(Looper.getMainLooper())
    
    override fun run() {
        for (i in 1..1_000_000) {
            if (i % 100_000 == 0) {
                mainHandler.post {
                    textView.text = "Достигнуто: $i"
                }
            }
        }
        mainHandler.post {
            textView.text = "Подсчет завершен!"
        }
    }
}

// Запуск потока
CounterThread().start()

4. Использование WorkManager для фоновых задач

Если подсчет должен выполняться в фоне, даже когда приложение закрыто, можно использовать WorkManager.

import androidx.work.Worker
import androidx.work.WorkRequest
import androidx.work.OneTimeWorkRequestBuilder

class CountingWorker : Worker() {
    override fun doWork(): Result {
        for (i in 1..1_000_000) {
            if (i % 100_000 == 0) {
                // Сохранение промежуточных результатов
                setProgressAsync(workDataOf("progress" to i))
            }
        }
        return Result.success()
    }
}

// Запуск работы
val workRequest = OneTimeWorkRequestBuilder<CountingWorker>().build()
WorkManager.getInstance(context).enqueue(workRequest)

Критерии выбора подхода

  1. Корутины — лучший выбор для современных Android-приложений:

    • Интеграция с архитектурными компонентами (ViewModel, LiveData/StateFlow)
    • Отмена операций при уничтожении компонента
    • Простота обработки ошибок
  2. Производительность и оптимизация:

    • Для чистого подсчета без обновления UI можно использовать Dispatchers.Default
    • Избегайте частых обновлений UI (раз в 100к итераций в примере)
    • Используйте StringBuilder для конкатенации строк в циклах
  3. Обработка прерываний:

    viewModelScope.launch {
        val job = launch(Dispatchers.Default) {
            repeat(1_000_000) { i ->
                ensureActive() // Проверка отмены корутины
                // Логика подсчета
            }
        }
        // Отмена через 5 секунд
        delay(5000)
        job.cancel()
    }
    

Практические рекомендации

  • Всегда выполняйте длительные операции вне главного потока
  • Используйте прогресс-индикаторы для информирования пользователя
  • Обрабатывайте повороты экрана через ViewModel и сохранение состояния
  • Тестируйте производительность с помощью Android Profiler
  • Для чисто вычислительных задач рассмотрите использование Kotlin Flow:
fun countNumbers(): Flow<Int> = flow {
    for (i in 1..1_000_000) {
        emit(i)
        delay(1) // Искусственная задержка для демонстрации
    }
}

// Использование
viewModelScope.launch {
    countNumbers()
        .flowOn(Dispatchers.Default)
        .collect { number ->
            if (number % 100_000 == 0) {
                _countResult.value = "Обработано: $number"
            }
        }
}

Выбор конкретного подхода зависит от архитектуры приложения, версии Android и требований к функциональности. Для большинства современных приложений рекомендуется использовать Kotlin Coroutines вместе с архитектурными компонентами Jetpack.

Как выполнить задачу подсчета от 1 до 1 млн | PrepBro