Вызов Методов Обратного Вызова В Главном Потоке Unity
Функции обратного вызова плагина Appodeal запускаются в главном потоке iOS или Android, но не в главном потоке Unity. Так как любые изменения UI (изменение цвета, позиции объектов, размеров, текстов и т.д.) разрешены только в главном потоке, нельзя выполнять их из функций обратного вызова напрямую.
Важно понимать, что невозможно получить уведомления о каких-либо событиях в главном потоке Unity в тот момент,
когда отображается любая полноэкранная реклама. Все потому, что Unity останавливает основной поток в тот момент,
когда сцену что-либо перекрывает. Поэтому ваш скрипт получит уведомления о некоторых событиях (например
OnInterstitialShown
или OnRewardedVideoFinished
) в главном потоке только после закрытия рекламы. Но те же самые
функции обратного вызова будут работать без каких-либо задержек в главных потоках Android и iOS.
Как же правильно обработать события Appodeal плагина, чтобы избежать проблем с изменением UI из неправильного потока?
Наиболее простой путь - использовать логические флаги и метод Update
класса MonoBehaviour
:
- UPM Дистрибуция
- Manual Дистрибуция
public class SomeClass : MonoBehaviour
{
bool videoFinished = false;
double rewardAmount;
string rewardName;
public void OnRewardedVideoFinished(object sender, RewardedVideoFinishedEventArgs e)
{
rewardAmount = e.Amount;
rewardName = e.Currency;
// It's important to set flag to true only after all required parameters
videoFinished = true;
}
// Update method always performs in the main Unity thread
void Update()
{
if(videoFinished)
{
// Don't forget to set flag to false
videoFinished = false;
// Do something with rewardAmount and rewardName
}
}
}
public class SomeClass : MonoBehaviour, IRewardedVideoAdListener
{
bool videoFinished = false;
double rewardAmount;
string rewardName;
public void onRewardedVideoFinished(double amount, string name)
{
rewardAmount = amount;
rewardName = name;
// It's important to set flag to true only after all required parameters
videoFinished = true;
}
// Update method always performs in the main Unity thread
void Update()
{
if(videoFinished)
{
// Don't forget to set flag to false
videoFinished = false;
// Do something with rewardAmount and rewardName
}
}
}
Другой, возможно более комфортный способ - UnityMainThreadDispatcher. Для того, чтобы воспользоваться им:
- Скачайте скрипт и префаб.
- Импортируйте скачанные файлы в проект.
- Добавьте
UnityMainThreadDispatcher.prefab
на вашу сцену (или все сцены, на которых вы собираетесь делать какие-либо изменения UI после событий плагина). - Используйте метод
UnityMainThreadDispatcher.Instance().Enqueue()
, чтобы выполнить необходимые изменения:
- UPM Дистрибуция
- Manual Дистрибуция
public void OnRewardedVideoFinished(object sender, RewardedVideoFinishedEventArgs e)
{
UnityMainThreadDispatcher.Instance().Enqueue(()=> {
Debug.Log($"Appodeal. Video Finished: {e.Amount} {e.Currency}")
});
}
public void onRewardedVideoFinished(double amount, string name)
{
UnityMainThreadDispatcher.Instance().Enqueue(()=> {
Debug.Log($"Appodeal. Video Finished: {amount} {name}")
});
}
И, наконец, официальный способ передать сообщение в главный поток Unity - метод UnitySendMessage
. Этот метод
платформозависимый, поэтому для его применения необходимо сделать изменения в нативном Android и iOS коде.
Больше информации об этом методе вы можете найти в официальной документации Android и iOS.