推送通知是否可以与 UI 线程并行执行代码?
Can push notification execute code in parallel with UI thread or not?
因为FirebaseMessagingService
没有使用Main Thread
,我只是想知道我所有的代码在我所有的活动中还是在UI thread(Main Thread
中的片段运行)。现在假设我的 activity 的 onCreate
方法正在执行,然后我收到 push notification
。这两个代码块 运行 并行 还是推送通知代码会在队列中等待,直到 onCreate()
方法或 Activity 的最后一个生命周期方法被执行?
Edit- 正如你所说代码将 运行 并行然后假设我在 App.java
中有一个变量
public class App extends Application {
int ctr = 100;
}
StatusActivity.java
public class StatusActivity extends BaseActivity {
public void onCreate() {
fun();
}
public void fun() {
int d = App.ctr - 1;//Step 1 Here d = 99
int m = App.ctr - 1; // Step 3 Here m = 98
}
}
FcmListener.java
public class FcmListener extends FirebaseMessagingService {
Override
public void onMessageReceived(RemoteMessage mssg) {
App.ctr = App.ctr - 1;//STEP 2 // Now App.ctr = 99
}
}
现在你可以在上面的代码中看到,如果推送通知代码与 fun()
并行执行,将会出现问题。我希望 push_notif
和 fun()
到 运行 串行,顺序无关紧要但不是并行的。
怎么样?
class Sample {
private String message = null;
private final Object lock = new Object();
public void newMessage(String x) {
synchronized (lock) {
message = x;
}
}
public String getMessage() {
synchronized (lock) {
String temp = message;
message = null;
return temp;
}
}
}
这是我的 2 美分。你说,
Suppose my activity's onCreate method is executing and then I receive the push notification. Will these two blocks of code run parallelly or will the push notification code wait in the queue until onCreate method OR Activity's last life cycle method gets executed?
来自FirebaseMessagingService的官方文档:
Extending this class is required to be able to handle downstream messages. It also provides functionality to automatically display notifications, and has methods that are invoked to give the status of upstream messages. Override base class methods to handle any events required by the application. Methods are invoked on a background thread.
所以有可能两种方法同时执行。如果您想对 Application
class 中的共享变量执行操作,您可以使用 synchronize
执行线程安全操作。参见 How to synchronize or lock upon variables in Java?。这将确保一次只有一个线程对该变量进行更改。如果有新线程进入,它会等待锁释放,然后对该变量进行更改。但是,这并不能保证顺序。只是表示一个线程在同一时刻对其进行操作,并且是先进先出的顺序。
我建议您采用不同的方法,因为使用这些全局变量可能会导致意外行为。
如果您的 ctr var 与您的 activity 相关,则将其保留在内部。如果您在其他活动中需要它,请考虑通过 Intent 将其作为额外传递。
使用 LocalBroadcastManager 通知您的 activity 您收到了推送消息
public class FcmListener extends FirebaseMessagingService {
public static final String ACTION_MESSAGE_RECEIVED = "ACTION_MESSAGE_RECEIVED"
@Override
public void onMessageReceived(RemoteMessage mssg) {
Intent intent = new Intent(ACTION_MESSAGE_RECEIVED) // put extra vars as needed
boolean delivered = LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
// 'delivered' is true if there is at least someone listening to the broadcast, eg. your activity
// If your activity is not running, then 'delivered' is false so you can act accordingly
}
}
然后在你的activity
里面
public class StatusActivity extends BaseActivity {
private BroadcastReceiver messageReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (TextUtils.equals(FcmListener.ACTION_MESSAGE_RECEIVED, action)) {
// do stuff with 'ctr'
}
}
};
@Override
protected void onStart() {
super.onStart();
IntentFilter filter = new IntentFilter(FcmListener.ACTION_MESSAGE_RECEIVED);
LocalBroadcastManager.getInstance(this).registerReceiver(messageReceiver, filter);
}
@Override
protected void onStop() {
super.onStop();
LocalBroadcastManager.getInstance(this).unregisterReceiver(messageReceiver);
}
}
正如在 parallel answer 中已经指出的那样,FirebaseMessagingService
运行 的重写方法在后台线程中,因此您应该使用同步策略以便 access/use来自不同线程的可变对象。
但我要回答的问题有点不同。让我们暂时假设,在主线程上覆盖方法 运行。那么有没有可能,执行顺序是STEP 1
然后STEP 2
然后STEP 3
?
Android 使用一种称为 MessageQueue
, basically there are Message
s posted on that queue, on which Looper
循环的技术和 "parses/executes" 它们。
现在,如果我们假设您当前位于 STEP 1
,这意味着有一个特定的 Message
当前正在执行(假设,让我们假设操作是 - 执行onCreate()
个 activity).
在这条消息被完全执行之前,不可能存在另一个可能有机会被执行的 Message
。因此,如果我们假设 Firebase 在后台线程上调度一个事件,但实际覆盖的方法在主线程上 运行,那么这个覆盖的方法将有机会仅在当前 Message
之后执行(activity 的 onCreate()
) 已经完成。换句话说,将在 MessageQueue
上发布另一个 Message
,当 Looper
将有机会执行此消息时,它将执行 onMessageReceived()
。
因此,从理论上讲,排序不可能是 STEP 1
-> STEP 2
-> STEP 3
.
如果 STEP 1
已经执行,那么它会继续执行 STEP 3
和 STEP 2
(在将来的某个时候,因为你不知道其他 Message
s 已经发布在 MessageQueue
).
有关 MessageQueue
和相关 类 的更多详细信息,请参见 this article。
因为FirebaseMessagingService
没有使用Main Thread
,我只是想知道我所有的代码在我所有的活动中还是在UI thread(Main Thread
中的片段运行)。现在假设我的 activity 的 onCreate
方法正在执行,然后我收到 push notification
。这两个代码块 运行 并行 还是推送通知代码会在队列中等待,直到 onCreate()
方法或 Activity 的最后一个生命周期方法被执行?
Edit- 正如你所说代码将 运行 并行然后假设我在 App.java
中有一个变量public class App extends Application {
int ctr = 100;
}
StatusActivity.java
public class StatusActivity extends BaseActivity {
public void onCreate() {
fun();
}
public void fun() {
int d = App.ctr - 1;//Step 1 Here d = 99
int m = App.ctr - 1; // Step 3 Here m = 98
}
}
FcmListener.java
public class FcmListener extends FirebaseMessagingService {
Override
public void onMessageReceived(RemoteMessage mssg) {
App.ctr = App.ctr - 1;//STEP 2 // Now App.ctr = 99
}
}
现在你可以在上面的代码中看到,如果推送通知代码与 fun()
并行执行,将会出现问题。我希望 push_notif
和 fun()
到 运行 串行,顺序无关紧要但不是并行的。
怎么样?
class Sample {
private String message = null;
private final Object lock = new Object();
public void newMessage(String x) {
synchronized (lock) {
message = x;
}
}
public String getMessage() {
synchronized (lock) {
String temp = message;
message = null;
return temp;
}
}
}
这是我的 2 美分。你说,
Suppose my activity's onCreate method is executing and then I receive the push notification. Will these two blocks of code run parallelly or will the push notification code wait in the queue until onCreate method OR Activity's last life cycle method gets executed?
来自FirebaseMessagingService的官方文档:
Extending this class is required to be able to handle downstream messages. It also provides functionality to automatically display notifications, and has methods that are invoked to give the status of upstream messages. Override base class methods to handle any events required by the application. Methods are invoked on a background thread.
所以有可能两种方法同时执行。如果您想对 Application
class 中的共享变量执行操作,您可以使用 synchronize
执行线程安全操作。参见 How to synchronize or lock upon variables in Java?。这将确保一次只有一个线程对该变量进行更改。如果有新线程进入,它会等待锁释放,然后对该变量进行更改。但是,这并不能保证顺序。只是表示一个线程在同一时刻对其进行操作,并且是先进先出的顺序。
我建议您采用不同的方法,因为使用这些全局变量可能会导致意外行为。 如果您的 ctr var 与您的 activity 相关,则将其保留在内部。如果您在其他活动中需要它,请考虑通过 Intent 将其作为额外传递。
使用 LocalBroadcastManager 通知您的 activity 您收到了推送消息
public class FcmListener extends FirebaseMessagingService {
public static final String ACTION_MESSAGE_RECEIVED = "ACTION_MESSAGE_RECEIVED"
@Override
public void onMessageReceived(RemoteMessage mssg) {
Intent intent = new Intent(ACTION_MESSAGE_RECEIVED) // put extra vars as needed
boolean delivered = LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
// 'delivered' is true if there is at least someone listening to the broadcast, eg. your activity
// If your activity is not running, then 'delivered' is false so you can act accordingly
}
}
然后在你的activity
里面public class StatusActivity extends BaseActivity {
private BroadcastReceiver messageReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (TextUtils.equals(FcmListener.ACTION_MESSAGE_RECEIVED, action)) {
// do stuff with 'ctr'
}
}
};
@Override
protected void onStart() {
super.onStart();
IntentFilter filter = new IntentFilter(FcmListener.ACTION_MESSAGE_RECEIVED);
LocalBroadcastManager.getInstance(this).registerReceiver(messageReceiver, filter);
}
@Override
protected void onStop() {
super.onStop();
LocalBroadcastManager.getInstance(this).unregisterReceiver(messageReceiver);
}
}
正如在 parallel answer 中已经指出的那样,FirebaseMessagingService
运行 的重写方法在后台线程中,因此您应该使用同步策略以便 access/use来自不同线程的可变对象。
但我要回答的问题有点不同。让我们暂时假设,在主线程上覆盖方法 运行。那么有没有可能,执行顺序是STEP 1
然后STEP 2
然后STEP 3
?
Android 使用一种称为 MessageQueue
, basically there are Message
s posted on that queue, on which Looper
循环的技术和 "parses/executes" 它们。
现在,如果我们假设您当前位于 STEP 1
,这意味着有一个特定的 Message
当前正在执行(假设,让我们假设操作是 - 执行onCreate()
个 activity).
在这条消息被完全执行之前,不可能存在另一个可能有机会被执行的 Message
。因此,如果我们假设 Firebase 在后台线程上调度一个事件,但实际覆盖的方法在主线程上 运行,那么这个覆盖的方法将有机会仅在当前 Message
之后执行(activity 的 onCreate()
) 已经完成。换句话说,将在 MessageQueue
上发布另一个 Message
,当 Looper
将有机会执行此消息时,它将执行 onMessageReceived()
。
因此,从理论上讲,排序不可能是 STEP 1
-> STEP 2
-> STEP 3
.
如果 STEP 1
已经执行,那么它会继续执行 STEP 3
和 STEP 2
(在将来的某个时候,因为你不知道其他 Message
s 已经发布在 MessageQueue
).
有关 MessageQueue
和相关 类 的更多详细信息,请参见 this article。