相关疑难解决方法(0)

Android"只有创建视图层次结构的原始线程才能触及其视图."

我在Android中构建了一个简单的音乐播放器.每首歌曲的视图都包含一个SeekBar,实现方式如下:

public class Song extends Activity implements OnClickListener,Runnable {
    private SeekBar progress;
    private MediaPlayer mp;

    // ...

    private ServiceConnection onService = new ServiceConnection() {
          public void onServiceConnected(ComponentName className,
            IBinder rawBinder) {
              appService = ((MPService.LocalBinder)rawBinder).getService(); // service that handles the MediaPlayer
              progress.setVisibility(SeekBar.VISIBLE);
              progress.setProgress(0);
              mp = appService.getMP();
              appService.playSong(title);
              progress.setMax(mp.getDuration());
              new Thread(Song.this).start();
          }
          public void onServiceDisconnected(ComponentName classname) {
              appService = null;
          }
    };

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.song);

        // ...

        progress = (SeekBar) findViewById(R.id.progress);

        // ...
    }

    public void run() { …
Run Code Online (Sandbox Code Playgroud)

multithreading android

879
推荐指数
18
解决办法
53万
查看次数

Kotlin:coroutineScope 比 GlobalScope 慢

我正在学习协程,我遇到了以下令人惊讶的(对我而言)行为。我想要一张平行地图。我考虑了4个解决方案:

  1. 只是map,没有并行性
  2. pmap这里
  3. 修改第 2 项:我删除coroutineScope并使用GlobalScope.
  4. Java 的parallelStream.

编码:

import kotlinx.coroutines.*
import kotlin.streams.toList
import kotlin.system.measureNanoTime

inline fun printTime(msg: String, f: () -> Unit) =
    println("${msg.padEnd(15)} time: ${measureNanoTime(f) / 1e9}")

suspend fun <T, U> List<T>.pmap(f: (T) -> U) = coroutineScope {
    map { async { f(it) } }.map { it.await() }
}

suspend fun <T, U> List<T>.pmapGlob(f: (T) -> U) =
    map { GlobalScope.async { f(it) } }.map { it.await() …
Run Code Online (Sandbox Code Playgroud)

parallel-processing performance coroutine kotlin kotlin-coroutines

8
推荐指数
1
解决办法
2273
查看次数

使用 GlobalScope.launch 和 CoroutineScope().launch 启动协程有区别吗?

在 Kotlin 中启动协程有多种方法。我发现了几个使用GlobalScope和的例子CoroutineScope。但后一个是在启动协程时直接创建的:

  1. 使用GlobalScope

    fun loadConfiguration() {
        GlobalScope.launch(Dispatchers.Main) {
           val config = fetchConfigFromServer() // network request
           updateConfiguration(config)
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 使用CoroutineScope实例,在启动协程时直接创建:

    fun loadConfiguration() {
        CoroutineScope(Dispatchers.Main).launch {
            val config = fetchConfigFromServer() // network request
            updateConfiguration(config)
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

在这种情况下,这两种方法有区别吗?

第二种情况不是违反了结构化并发的原则吗?

android kotlin kotlin-coroutines coroutinescope structured-concurrency

6
推荐指数
1
解决办法
9684
查看次数

Kotlin Android - 分派到主线程的正确方法

我正在使用 OkHttp 库从互联网下载一些数据,然后androidx.lifecycle.ViewModel 我想更新我的LiveData. 似乎从后台线程执行此操作会引发异常,如下所示:

2022-01-17 15:47:59.589 7354-7396/com.example.myapplication E/AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher
    Process: com.example.myapplication, PID: 7354
    java.lang.IllegalStateException: Cannot invoke setValue on a background thread
        at androidx.lifecycle.LiveData.assertMainThread(LiveData.java:487)
        at androidx.lifecycle.LiveData.setValue(LiveData.java:306)
        at androidx.lifecycle.MutableLiveData.setValue(MutableLiveData.java:50)
        at com.example.myapplication.MainActivityViewModel$getOneMoreCat$1.invoke(MainActivityViewModel.kt:86)
        at com.example.myapplication.MainActivityViewModel$getOneMoreCat$1.invoke(MainActivityViewModel.kt:39)
        at com.example.myapplication.singleton.CommunicationManager$sendRequest$1.onResponse(CommunicationManager.kt:24)
        at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:923)
Run Code Online (Sandbox Code Playgroud)

现在我找到了两种不同的方法来调度到主线程ViewModel(根据 AAC 指南,它没有引用 Context),请参见此处:

            GlobalScope.launch {
                withContext(Dispatchers.Main) {
                    // do whatever, e.g. update LiveData
                }
            }
Run Code Online (Sandbox Code Playgroud)

或者

            Handler(Looper.getMainLooper()).post(Runnable {
                   // do whatever, e.g. update LiveData
            })
Run Code Online (Sandbox Code Playgroud)

哪个是正确的方法?也就是说,在运行时影响最小。

更新我确实发现我也可以这样做myLiveData.post() …

android kotlin android-livedata kotlin-coroutines coroutinescope

0
推荐指数
1
解决办法
5838
查看次数