@uzolenta

Как запустить цикл с okhttp3 в фоновом режиме Android?

Файл ForegroundService. Всё работает, оповещение появляется и данные отправляются в FirstActivity
class ForegroundService : Service() {
    
    private var myCallback: MyCallback? = null
    // Метод для установки объекта MyCallback
    private fun setCallback(callback: MyCallback, data: String) {
        myCallback = callback
        myCallback!!.updateUI(data)
    }

    private val CHANNEL_ID = "1"
    companion object {
        fun startService(context: Context, message: String) {
            val startIntent = Intent(context, ForegroundService::class.java)
            startIntent.putExtra("inputExtra", message)
            ContextCompat.startForegroundService(context, startIntent)
        }
        fun stopService(context: Context) {
            val stopIntent = Intent(context, ForegroundService::class.java)
            context.stopService(stopIntent)
        }
    }
    @RequiresApi(Build.VERSION_CODES.O)
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        //do heavy work on a background thread
        val input = intent?.getStringExtra("inputExtra")
        createNotificationChannel()
        val notificationIntent = Intent(this, PostingVKActivity::class.java)
        val pendingIntent = PendingIntent.getActivity(
            this,
            0, notificationIntent, PendingIntent.FLAG_IMMUTABLE
        )

        val notification = NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle("Foreground Service Kotlin Example")
            .setContentText(input)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentIntent(pendingIntent)
            .build()

        val firstActivity = PostingVKActivity()
        val activity = ForegroundService()
        activity.setCallback(firstActivity, "9999")

        startForeground(2, notification)

        return START_NOT_STICKY
    }
    override fun onBind(intent: Intent): IBinder? {
        return null
    }
    @RequiresApi(Build.VERSION_CODES.O)
    private fun createNotificationChannel() {
            val serviceChannel = NotificationChannel(CHANNEL_ID, "2",
                NotificationManager.IMPORTANCE_DEFAULT)
            val manager = getSystemService(NotificationManager::class.java)
            manager!!.createNotificationChannel(serviceChannel)
    }
}


файл FirstActivity. При нажатии на Button значение в gEditText Пеняется на "1". Запускается сервис, приходит уведомление. в Функции "updateUI" срабатывает println("data updateUI: $data") и выводит данные из Service. Но в этой функции не хочет срабатывать currentName.value = "8888", точнее значение присваивается и выводится, но не меняется в gEditText, как при нажатии на Button.
Если напрямую делать gEditText.text = data, то выскакивает ошибка об инициализации gEditText.text.

interface MyCallback {
    fun updateUI(data: String)
}

class FirstActivity : AppCompatActivity(), MyCallback {
private lateinit var binding: ActivityFirstBinding

lateinit var gEditText: TextView
lateinit var button: Button


val currentName: MutableLiveData<String> by lazy {
        MutableLiveData<String>()
    }

override fun updateUI(data: String){
            // Здесь вы обновляете ваш интерфейс, например, ваш TextView
            println("data updateUI: $data")
            currentName.value = "8888"
            println("currentName.value updateUI: ${currentName.value}")
            }

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityFirstBinding.inflate(layoutInflater)

gEditText = binding.gEditText
Button = binding.Button


val nameObserver = Observer<String> { newName ->
            // Update the UI, in this case, a TextView.
            gEditText.text = newName
        }
        currentName.observe(this, nameObserver)

Button.setOnClickListener {
currentName.value = "1"
val intentActivity = Intent(this, ForegroundService::class.java)
intentActivity.putExtra("inputExtra", "444");
startService(intentActivity)
}

setContentView(binding.root)
}
}
  • Вопрос задан
  • 212 просмотров
Пригласить эксперта
Ответы на вопрос 2
@rPman
тебе нужно создать фоновый сервис https://developer.android.com/training/run-backgro...
Мои скилы устарели, плюс гугл похоже сильно последние пару лет перелопачивает способ разработки приложений для android и что лучше использовать и будут ли какие либо ограничения судить сложно, информация из гугла очень противоричивая

Есть WorkManager, он более background, но его работа может быть остановлена по каким то причинам (работа выполнится но без гарантий оперативности, что бы это не значило) это больше планировщик задач а функция которая работает в фоне.

С точки зрения длительной загрузки файла мне кажется WorkManager подходит лучше чем Service
Ответ написан
@kitcat2004
Проверьте следующее:

updateUI активируется после gEditText и что gEditText не переинициализируется позже в коде.
Это важно, потому что lateinit свойства должны быть инициализированы до их использования.

Проверьте по коду FirstActivity не должна повторяться, возможно gEditText обращается к ней в нескольких местах, вызывая переинициализацию, таким образом код ходит по циклу снова и снова, вызывая из другого экземпляра .

Проверьте, что FirstActivity не пересоздается в процессе работы. Если это именно так, то создаст проблемы с инициализацией gEditText.

Код вызова updateUI должен быть в том же потоке, в котором и был создан FirstActivity.
обновление UI из другого потока может вызвать подобную ошибку.

===========================================ПРОШЛЫЙ ОТВЕТ ===========================================

вы пытаетесь обратиться к переменной gEditText, которая не была инициализирована.


Сейчас она инициализируется так:

gEditText = binding.gEditText

Убедитесь, что binding.gEditText был успешно инициализирован в вашем Activity.
Это обычно происходит в методе onCreate.

(binding) и gEditText должны быть внутри представления

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityFirstBinding.inflate(layoutInflater)
    setContentView(binding.root)

    gEditText = binding.gEditText

    // Остальной код вашей Activity
}


ПРОВЕРЬТЕ ЭТО!

Если binding.gEditText не был успешно инициализирован, проверяем,
что есть правильное представление и gEditText
имеет правильный идентификатор в макете (ActivityFirstBinding).

====================СТАРОЕ ================

Используйте основной поток, вместо фона.
Ошибка вызвана природой ассинхронки сервиса

Чтобы обновить пользовательский интерфейс из фонового потока, вы должны использовать методы, предоставленные Android для выполнения операций в основном потоке.

Используйте функцию runOnUiThread для обновления gEditText в основном потоке.
Вот как можно изменить вашу функцию updateUI:

override fun updateUI(data: String) {
    // Здесь вы обновляете ваш интерфейс, например, ваш TextView
    println("data updateUI: $data")

    runOnUiThread {
        // Обновление интерфейса в основном потоке
        gEditText.text = "8888"
    }
}


Это обернет обновление gEditText.text в блок, который будет выполнен в основном потоке,
и избежит ошибок, связанных с обновлением интерфейса из фонового потока.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы