问题在于,在从firstActivity过渡到thisServiceActivity的过程中,屏幕将冻结,然后变黑。如果服务执行了此服务,并广播了此ServiceActivity的广播接收器,并进行广播发送和接收,则它将最终显示thisServiceActivity的布局,并快速过渡到ResultActivity。

是因为我的UI线程有问题吗?我试图找到与此问题类似的讨论,但找不到它。

firstActivity类将启动一个新的活动,它是thisServiceActivity类。 thisServiceActivity的布局显示进度条和textview。同时,它将以未决的意图通知启动服务类名称为myForegroundService。

如果服务中的过程完成,则该服务将发送一个本地广播,该广播将由thisServiceActivity使用广播接收器进行接收,然后它将停止该服务并过渡到resultActivity并完成其活动。

public class firstActivity extends AppCompatActivity {

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

    //using button onclick
    public void startActivity(View view) {
        Intent startService = new Intent(this, thisServiceActivity.class);
        startActivity(startService);
    }
}


package example.myapplication;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;

public class thisServiceActivity extends AppCompatActivity {

    Intent goToResult, stopMyService, startMyService;

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

        LocalBroadcastManager.getInstance(this).registerReceiver(myForegroundReceiver,
            new IntentFilter("end-of-process"));
        startService();
    }

    public void startService() {
        startMyService = new Intent(this, myForegroundService.class);
        ContextCompat.startForegroundService(this, startMyService);
    }

    public void stopService() {
        stopMyService = new Intent(this, myForegroundService.class);
        stopService(stopMyService);
    }

    @Override
    protected void onDestroy() {
        LocalBroadcastManager.getInstance(this).unregisterReceiver(myForegroundReceiver);
        super.onDestroy();
    }

    private BroadcastReceiver myForegroundReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.i("onReceive", "Received");
            stopService();
            goToResult = new Intent(getApplication(), ResultActivity.class);
            startActivity(goToResult);
            finish();
        }
    };
}



package example.myapplication;

import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.IBinder;
import android.os.SystemClock;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;

import java.util.concurrent.ExecutionException;

import static example.myapplication.App.CHANNEL_ID;

public class myForegroundService extends Service {

    Boolean process;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        Log.i("Service Running", "True");

        Intent toThisServiceActivity = new Intent(this, thisServiceActivity.class);
        PendingIntent servicePendingIntent = PendingIntent.getActivity(this, 0, toThisServiceActivity, 0);

        Notification notify = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle("Sit back and relax, process is in progress")
                .setContentText("You look more charming if you have patient, please wait")
                .setContentIntent(servicePendingIntent)
                .build();

        startForeground(1, notify);

        try {
            process = new MyLoop().execute().get();
        } catch (ExecutionException | InterruptedException e) {
            e.printStackTrace();
        }

        if (process) {
            Intent killswitch = new Intent("end-of-process");
            Log.i("Finish", "Service");
            LocalBroadcastManager.getInstance(this).sendBroadcast(killswitch);
        }
        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private class MyLoop extends AsyncTask<Void, String, Boolean> {

        @Override
        protected Boolean doInBackground(Void... voids) {

            for (int i = 0; i < 10; i++) {
                publishProgress("i = " + i);
                SystemClock.sleep(1000);
            }
            return true;
        }

        @Override
        protected void onProgressUpdate(String... values) {
            String value = values[0];
            Log.i("Foreground Service", value);
        }
    }

}


Logcat输出

02/25 17:41:41: Launching 'app' on  Google.
$ adb shell am start -n "example.myapplication/example.myapplication.firstActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Waiting for process to come online...
Connected to process 5060 on device '-google-192.168.42.106:5555'.
Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
I/Zygote: seccomp disabled by setenforce 0
I/e.myapplicatio: Late-enabling -Xcheck:jni
W/e.myapplicatio: Unexpected CPU variant for X86 using defaults: x86
D/libEGL: Emulator has host GPU support, qemu.gles is set to 1.
I/example.myapplication: type=1400 audit(0.0:1122): avc: denied { write } for comm=45474C20496E6974 name="property_service" dev="tmpfs" ino=9335 scontext=u:r:untrusted_app:s0:c96,c256,c512,c768 tcontext=u:object_r:property_socket:s0 tclass=sock_file permissive=1
    type=1400 audit(0.0:1123): avc: denied { connectto } for comm=45474C20496E6974 path="/dev/socket/property_service" scontext=u:r:untrusted_app:s0:c96,c256,c512,c768 tcontext=u:r:init:s0 tclass=unix_stream_socket permissive=1
D/vndksupport: Loading /vendor/lib/egl/libGLES_emulation.so from current namespace instead of sphal namespace.
E/libEGL: load_driver(/vendor/lib/egl/libGLES_emulation.so): dlopen failed: library "/vendor/lib/egl/libGLES_emulation.so" not found
D/vndksupport: Loading /vendor/lib/egl/libEGL_emulation.so from current namespace instead of sphal namespace.
D/libEGL: loaded /vendor/lib/egl/libEGL_emulation.so
D/vndksupport: Loading /vendor/lib/egl/libGLESv1_CM_emulation.so from current namespace instead of sphal namespace.
D/libEGL: loaded /vendor/lib/egl/libGLESv1_CM_emulation.so
D/vndksupport: Loading /vendor/lib/egl/libGLESv2_emulation.so from current namespace instead of sphal namespace.
D/libEGL: loaded /vendor/lib/egl/libGLESv2_emulation.so
W/e.myapplicatio: Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (light greylist, reflection)
W/e.myapplicatio: Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (light greylist, reflection)
D/OpenGLRenderer: Skia GL Pipeline
D/: HostConnection::get() New Host Connection established 0xe7b6d5c0, tid 5087
I/RenderThread: type=1400 audit(0.0:1124): avc: denied { connectto } for path=006C6F63616C5F6F70656E676C scontext=u:r:untrusted_app:s0:c96,c256,c512,c768 tcontext=u:r:local_opengl:s0 tclass=unix_stream_socket permissive=1
W/: Unrecognized GLES max version string in extensions:
W/: Process pipe failed
I/ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasWideColorDisplay retrieved: 0
    android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasHDRDisplay retrieved: 0
I/OpenGLRenderer: Initialized EGL, version 1.4
D/OpenGLRenderer: Swap behavior 1
D/EGL_emulation: eglCreateContext: 0xe1fc8e20: maj 2 min 0 rcv 2
D/vndksupport: Loading /vendor/lib/hw/[email protected] from current namespace instead of sphal namespace.
D/vndksupport: Loading /vendor/lib/hw/gralloc.vbox86.so from current namespace instead of sphal namespace.
E/EGL_emulation: tid 5087: eglSurfaceAttrib(1354): error 0x3009 (EGL_BAD_MATCH)
W/OpenGLRenderer: Failed to set EGL_SWAP_BEHAVIOR on surface 0xe1fc8d60, error=EGL_BAD_MATCH
I/Choreographer: Skipped 31 frames!  The application may be doing too much work on its main thread.
W/ActivityThread: handleWindowVisibility: no activity for token android.os.BinderProxy@112c025
E/EGL_emulation: tid 5087: eglSurfaceAttrib(1354): error 0x3009 (EGL_BAD_MATCH)
W/OpenGLRenderer: Failed to set EGL_SWAP_BEHAVIOR on surface 0xe0846b60, error=EGL_BAD_MATCH
I/Service Running: True
I/Finish: Service
W/ViewRootImpl[thisServiceActivity]: Dropping event due to no window focus: KeyEvent { action=ACTION_DOWN, keyCode=KEYCODE_BACK, scanCode=0, metaState=0, flags=0x48, repeatCount=0, eventTime=7949110, downTime=7949110, deviceId=-1, source=0x101 }
W/ViewRootImpl[thisServiceActivity]: Cancelling event due to no window focus: KeyEvent { action=ACTION_UP, keyCode=KEYCODE_BACK, scanCode=0, metaState=0, flags=0x68, repeatCount=0, eventTime=7950511, downTime=7949110, deviceId=-1, source=0x101 }
I/Choreographer: Skipped 625 frames!  The application may be doing too much work on its main thread.
I/chatty: uid=10096(example.myapplication) identical 7 lines
W/ViewRootImpl[thisServiceActivity]: Cancelling event due to no window focus: KeyEvent { action=ACTION_UP, keyCode=KEYCODE_BACK, scanCode=0, metaState=0, flags=0x68, repeatCount=0, eventTime=7950511, downTime=7949110, deviceId=-1, source=0x101 }
I/OpenGLRenderer: Davey! duration=10603ms; Flags=0, IntendedVsync=7941734767100, Vsync=7952151433350, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=7952160308707, AnimationStart=7952160414256, PerformTraversalsStart=7952161151710, DrawStart=7952165102838, SyncQueued=7952174190092, SyncStart=7952180127743, IssueDrawCommandsStart=7952180180543, SwapBuffers=7952293099225, FrameCompleted=7952343853615, DequeueBufferDuration=63000, QueueBufferDuration=161000,
I/Foreground Service: i = 0
    i = 1
I/Foreground Service: i = 2
    i = 3
I/OpenGLRenderer: Davey! duration=10618ms; Flags=0, IntendedVsync=7941734767100, Vsync=7952151433350, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=7952160308707, AnimationStart=7952160414256, PerformTraversalsStart=7952161151710, DrawStart=7952344526709, SyncQueued=7952345327938, SyncStart=7952355852722, IssueDrawCommandsStart=7952355900616, SwapBuffers=7952356170648, FrameCompleted=7952363877516, DequeueBufferDuration=148000, QueueBufferDuration=246000,
I/Foreground Service: i = 4
I/Foreground Service: i = 5
    i = 6
    i = 7
    i = 8
I/Foreground Service: i = 9
I/onReceive: Received
Process 5060 terminated.

最佳答案

通过等待AsyncTask的结果,您将UI线程阻塞了10秒钟:

process = new MyLoop().execute().get();


get()的Javadoc指出:


等待必要的计算完成,然后检索其结果。


这消除了在后台线程上运行它并导致应用程序冻结的任何优势。如果需要对结果进行某些操作,则应在AsyncTask.onPostExecute中进行。

10-08 18:13