I have a problem trying to manipulate GameObjects inside the ContinueWith method of a Task instance. The code below worked pretty well until we switched to .NET 4.x in Unity 2018.2.
I've searched a lot and tought I found what it seems to be a workaround (using UnityThread), I could't find the reason why this code doesn't work anymore and since the same pattern is used a lot in my project I want to know if there is in fact no other solution.
FirebaseDatabaseManager.Instance.GetPrivateChatMessages(chatId)
.ContinueWith(messagesTask =>
{
if (messagesTask.IsCompleted && messagesTask.Result != null && messagesTask.Result.Exists)
{
// Go over the dictionary in reverse.
foreach (var message in messagesTask.Result.Children.OrderByDescending(x => x.Key))
{
Debug.Log("Message " + message.Key);
// Insert the message as the first element.
StartCoroutine(AddMessageItem(message));
}
}
});
EDIT: This is the method GetPrivateChatMessages
.
/// <summary>
/// Returns the private chats' messages or null if the database is not initialized.
/// </summary>
/// <returns></returns>
public Task<DataSnapshot> GetPrivateChatMessages(string chatId, int limit, string lastItemKey, long lastItemTimestamp)
{
if (!Initialized) return null;
return DatabaseRoot.Child("messages").Child(chatId).OrderByChild("timestamp").EndAt(lastItemTimestamp, lastItemKey).LimitToLast(limit).GetValueAsync();
}
Before the update the line StartCoroutine(AddMessageItem(message)); used to work just fine, now it throws an exception
01-08 13:47:15.376 23882-24991/com.fhacktions E/Unity:
IsObjectMonoBehaviour can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)
Fhacktions.c__AnonStorey2:<>m__0(Task`1)
System.Threading.Tasks.Task:Execute()
System.Threading.ExecutionContext:RunInternal(ExecutionContext, ContextCallback, Object, Boolean)
System.Threading.ExecutionContext:Run(ExecutionContext, ContextCallback, Object, Boolean)
System.Threading.Tasks.Task:ExecuteWithThreadLocal(Task&)
System.Threading.Tasks.Task:ExecuteEntry(Boolean)
System.Threading.ThreadPoolWorkQueue:Dispatch()
[/Users/builduser/buildslave/unity/build/Runtime/Scripting/ScriptingThreadAndSerializationSafeCheck.cpp line 85]
(Filename: /Users/builduser/buildslave/unity/build/Runtime/Scripting/ScriptingThreadAndSerializationSafeCheck.cpp Li
EDIT: Passing TaskScheduler.FromCurrentSynchronizationContext() as a parameter to the ContinueWith method solved the problem, I guess the default implementation changed and that caused the problem after the switch. Thanks.