由于FirebaseMessagingService
不使用Main Thread
,我只是想知道我的所有活动或片段中的所有代码都在UI thread(Main Thread
中运行。现在假设我的活动onCreate
方法正在执行,然后我收到push notification
。这两个代码块是否会并行运行 ,或者推送通知代码会在队列中等待,直到onCreate()
方法或Activity的最后一个生命周期方法被执行?
编辑 - 正如您所说,代码将并行运行,然后假设我在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
}
}
现在您可以在上面的代码中看到,如果push notif代码与fun()
并行执行,则会出现问题。我希望push_notif
和fun()
能够按顺序运行,其中顺序并不重要但并非并行。
答案 0 :(得分:1)
怎么样?
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;
}
}
}
答案 1 :(得分:1)
这是我的2美分。你说,
假设我的活动的onCreate方法正在执行,然后收到推送通知。这两个代码块将并行运行,还是将推送通知代码在队列中等待,直到执行onCreate方法或Activity的最后一个生命周期方法?
摘自FirebaseMessagingService的官方文档:
需要扩展此类,以便能够处理下游消息。它还提供了自动显示通知的功能,并具有被调用以提供上游消息状态的方法。重写基类方法以处理应用程序所需的任何事件。 在后台线程上调用方法。
因此,两种方法可能同时执行。如果要对var storageref = firebase.storage().ref('gallery/' + litrato.name);
var uploadTask = storageref.put(litrato);
uploadTask.on('state_changed', function(snapshot){
}, function(error){
console.error(error);
}, function() {
uploadTask.snapshot.ref.getDownloadURL().then(function(downloadURL) {
console.log('File available at', downloadURL);
});
});
类中的共享变量执行操作,则可以使用Application
执行线程安全操作。参见How to synchronize or lock upon variables in Java?。这样可以确保一次只有一个线程对该变量进行更改。如果有新线程进入,它将等待锁释放,然后对该变量进行更改。但是,这不能保证订单。这只是意味着一个线程可以同时对其进行操作,并且处于FIFO顺序。
答案 2 :(得分:1)
正如parallel answer中已经指出的那样,FirebaseMessagingService
的替代方法在后台线程中运行,因此您应该使用同步策略,以便从不同的线程访问/使用可变对象。
但是我要回答的问题有点不同。让我们先假设一下,被重写的方法在主线程上运行。这样执行的顺序是否可能是STEP 1
然后是STEP 2
然后是STEP 3
?
Android使用一种称为MessageQueue
的技术,基本上在该队列上发布了Message
个,其中Looper
循环并“解析/执行” 他们。
现在,如果我们假设您当前位于STEP 1
上,则意味着当前正在执行一个特定的Message
(假设,我们假设操作为-执行{{ 1}}。
在此消息完全执行之前,不能再有另一个onCreate()
可能会被执行的机会。因此,如果我们假设Firebase在后台线程上调度了一个事件,但实际的重写方法正在主线程上运行,则只有在当前Message
(活动的Message
之后,该重写方法才有机会执行) 已完成。换句话说,将在onCreate()
上发布另一个Message
,当MessageQueue
为执行此消息提供机会时,它将执行onMessageReceived()
。
因此,从理论上讲,排序是不可能的Looper
-> STEP 1
-> STEP 2
。
如果已经执行过STEP 3
,它将继续执行STEP 1
和STEP 3
(在将来的某个时候,因为您不知道其他STEP 2
s已发布在Message
上。
有关MessageQueue
和相关类的更多详细信息,请参见this article。
答案 3 :(得分:0)
我建议您使用其他方法,因为使用这些全局变量可能会导致意外行为。 如果您的点击率变量与您的活动有关,则将其保留在内部。如果您在其他活动中需要使用它,请考虑通过Intent额外传递它。
使用LocalBroadcastManager通知您的活动,您已收到推送消息
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
}
}
然后在活动中
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);
}
}