可以推送通知执行代码与UI线程并行吗?

时间:2018-06-16 21:25:04

标签: android multithreading firebase firebase-cloud-messaging android-lifecycle

由于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_notiffun()能够按顺序运行,其中顺序并不重要但并非并行。

4 个答案:

答案 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 1STEP 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);
    }

}