问题在于,在从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
中进行。