CallbackToFutureAdapter 中的调用是在第二次重建项目时执行的

rek*_*yde 8 multithreading android garbage-collection worker android-studio

我在使用 ListenableFuture 时遇到了问题,这是整个代码

主活动.java:

package com.example.app16;

import android.os.Bundle;
import android.view.View;

import androidx.appcompat.app.AppCompatActivity;
import androidx.work.Configuration;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;

public class MainActivity extends AppCompatActivity {
    WorkManager w;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        WorkManager.initialize(this, new Configuration.Builder()
                .setMinimumLoggingLevel(android.util.Log.INFO)
                .build());
        w = WorkManager.getInstance(getApplicationContext());

        OneTimeWorkRequest j = new OneTimeWorkRequest.Builder(lWorker.class).build();
        w.enqueue(j);
    }

    public void click(View view) {
        w.cancelAllWork();
    }
}
Run Code Online (Sandbox Code Playgroud)

lWorker.java:

package com.example.app16;

import android.content.Context;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.concurrent.futures.CallbackToFutureAdapter;
import androidx.work.ListenableWorker;
import androidx.work.WorkerParameters;

import com.google.common.util.concurrent.ListenableFuture;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class lWorker extends ListenableWorker {
    public lWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
    }

    @Override
    public void onStopped() {
        Log.e("LOG", "onStopped()");
    }

    @NonNull
    @Override
    public ListenableFuture<Result> startWork() {
        return CallbackToFutureAdapter.getFuture(completer -> {
            Callback callback = new Callback() {
                int successes = 0;

                @Override
                public void onResponse(@NonNull Call call, @NonNull Response response) {
                    ++successes;
                    Log.e("LOG", successes+"");
                    if (successes >= 100)
                        completer.set(Result.success());
                }

                @Override
                public void onFailure(@NonNull Call call, @NonNull Throwable t) {
                    completer.setException(t);
                }
            };

            completer.addCancellationListener(() -> Log.e("LOG", "run()"),
                    runnable -> Log.e("LOG", "execute()"));

            for (int i = 0; i < 100; ++i)
                Synchronously(i);
            Log.e("LOG", "OK");
            return callback;
        });
    }

    private void Synchronously(int n) {
        for(int i=0;i<10;i++) {
            try {
                Thread.sleep(1);
                Log.e("APP", n+":"+i);
            } catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.app16">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        tools:ignore="AllowBackup,GoogleAppIndexingWarning">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <provider
            android:name="androidx.work.impl.WorkManagerInitializer"
            android:authorities="com.example.app16.workmanager-init"
            tools:node="remove"
            android:exported="false" />
    </application>

</manifest>
Run Code Online (Sandbox Code Playgroud)

所以,当我第一次编译这个项目并在设备上运行它时,一切都很好。我看到循环如何结束并显示 OK。但是当我再次从工作室启动应用程序时,它会结束,再次安装并启动。现在我在日志中看到了这些奇怪的东西,第二个循环正好在 5 秒后发生:

08-23 19:42:36.817 23258-23258/com.example.app16 E/APP: 99:9
08-23 19:42:36.817 23258-23258/com.example.app16 E/LOG: OK
08-23 19:42:36.818 23258-23258/com.example.app16 I/Choreographer: Skipped 76 frames!  The application may be doing too much work on its main thread.
08-23 19:42:45.407 23258-23258/com.example.app16 E/APP: 0:0
...
08-23 19:42:45.417 23258-23274/com.example.app16 W/dalvikvm: getStackTrace() called but no trace available
08-23 19:42:45.418 23258-23258/com.example.app16 E/APP: 0:3
08-23 19:42:45.418 23258-23274/com.example.app16 E/WM-WorkerWrapper: Work [ id=33aea1de-694b-411a-a1a3-a0fc6d523227, tags={ com.example.app16.lWorker } ] failed because it threw an exception/error
    java.util.concurrent.ExecutionException: androidx.concurrent.futures.CallbackToFutureAdapter$FutureGarbageCollectedException: The completer object was garbage collected - this future would otherwise never complete. The tag was: com.example.app16.lWorker$1@418ce6b0
        at androidx.work.impl.utils.futures.AbstractFuture.getDoneValue(AbstractFuture.java:516)
        at androidx.work.impl.utils.futures.AbstractFuture.get(AbstractFuture.java:475)
        at androidx.work.impl.WorkerWrapper$2.run(WorkerWrapper.java:284)
        at androidx.work.impl.utils.SerialExecutor$Task.run(SerialExecutor.java:91)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
        at java.lang.Thread.run(Thread.java:856)
     Caused by: androidx.concurrent.futures.CallbackToFutureAdapter$FutureGarbageCollectedException: The completer object was garbage collected - this future would otherwise never complete. The tag was: com.example.app16.lWorker$1@418ce6b0
08-23 19:42:45.419 23258-23274/com.example.app16 I/WM-WorkerWrapper: Worker result FAILURE for Work [ id=33aea1de-694b-411a-a1a3-a0fc6d523227, tags={ com.example.app16.lWorker } ]
08-23 19:42:45.420 23258-23258/com.example.app16 E/APP: 0:4
08-23 19:42:45.420 23258-23268/com.example.app16 E/LOG: execute()
08-23 19:42:45.421 23258-23258/com.example.app16 E/APP: 0:5
....
08-23 19:42:45.445 23258-23258/com.example.app16 E/APP: 2:0
08-23 19:42:45.448 23258-23275/com.example.app16 E/LOG: onStopped()
....
Run Code Online (Sandbox Code Playgroud)

如您所见,循环进行了第二次,没有什么可以阻止它。我需要了解:我编写的代码或 android studio 中是否有错误?