简体   繁体   English

活动布局滞后,直到下一次转换到另一个活动之前

[英]Activity layout lagging behind until before next transition to another activity

The problem is that, during transition from firstActivity to thisServiceActivity, the screen will freeze and then turn black.问题是,在从 firstActivity 过渡到 thisServiceActivity 的过程中,屏幕会冻结然后变黑。 If service has performed it process and send the broadcast and receive by the broadcast receiver of thisServiceActivity, then it will finally show the layout of the thisServiceActivity and quickly transition to ResultActivity.如果service已经执行了它的处理和发送广播并由thisServiceActivity的广播接收器接收,那么它最终会显示thisServiceActivity的布局并快速过渡到ResultActivity。

Is it because there is something I do wrong in its UI thread?是不是因为我在它的 UI 线程中做错了什么? I try to find similar discussion to this problem but can't find it.我试图找到与此问题类似的讨论,但找不到。

firstActivity class will start a new activity which is thisServiceActivity class. firstActivity 类将启动一个新活动,即 thisServiceActivity 类。 thisServiceActivity have a layout that show a progressbar and textview. thisServiceActivity 有一个显示进度条和文本视图的布局。 At the same time, it will start a service class name as myForegroundService with pending intent notification.同时,它将启动一个名为 myForegroundService 的服务类,并带有挂起的意图通知。

If the process in the service completed, the service will send a local broadcast that will be pickup by thisServiceActivity using broadcast receiver and it then stop the service and transition to resultActivity and finish its activity.如果服务中的进程完成,服务将发送一个本地广播,该广播将由 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 output 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/android.hardware.graphics.mapper@2.0-impl.so 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.

You're blocking the UI thread for 10 seconds by waiting for the result of your AsyncTask:通过等待 AsyncTask 的结果,您将 UI 线程阻塞了 10 秒钟:

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

The Javadoc for get() states: get()的 Javadoc 指出:

Waits if necessary for the computation to complete, and then retrieves its result.如有必要,等待计算完成,然后检索其结果。

This is eliminating any advantage to running it on a background thread and causing your app to freeze.这消除了在后台线程上运行它并导致您的应用程序冻结的任何优势。 If you need to do something with the result, you should do it in AsyncTask.onPostExecute .如果你需要对结果做一些事情,你应该在AsyncTask.onPostExecute做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM