Home > OS >  when application quit, how can i save data to web server with coroutine
when application quit, how can i save data to web server with coroutine

Time:11-10

I searched how to wait coroutine in unity, and i found yield return StartCoroutine(IEnumerator). but when code start yield return, application quited. I want that application quit when every Coroutine finished. how can i fix this?

if can not wait Coroutine, how can i pause application quitting during data saved in web server.

private void OnApplicationQuit()
    {
        SaveGameData(GameManager.Instance.GetSaveData());
    }
public void SaveGameData(SaveData saveData)
    {
        string jsonString = JsonConvert.SerializeObject(saveData);

        UserController.Instance.SaveGameLogInfo02("name", jsonString, timer);
    }
public void SaveGameLogInfo02(string name, string rawdata/*jsonArray형식*/, long time)
    {
        if(saveGameLogInfoCoroutine02 == null)
        {
            saveGameLogInfoCoroutine02 = SaveGameLogInfoCoroutine02(name, rawdata, time);
            StartCoroutine(saveGameLogInfoCoroutine02);
        }
    }

    private IEnumerator SaveGameLogInfoCoroutine02(string name, string rawdata/*jsonArray형식*/, long time)
    {
        yield return StartCoroutine(apiController.SaveGameLogInfo02(saveUserData.GetAccessToken(), name, rawdata, time));

        SetJObject(apiController.RequestText);
        if (GetResult())
        {

            Debug.Log(string.Format("Success saved {0}'s log data", name));
        }
        else
        {
            Debug.Log("code : "   jo["code"]   ", message : "   jo["message"]);
        }

        saveGameLogInfoCoroutine02 = null;
        yield break;
    }
public IEnumerator SaveGameLogInfo02(string accessToken, string name, string rawdata, long time)
    {
        JObject json = new JObject();
        json.Add("name", name);
        json.Add("rawdata", rawdata);
        json.Add("time", time);

        yield return StartCoroutine(SendWebRequestWithTokenAndJson(accessToken, JsonConvert.SerializeObject(json), "/log/2/put"));
    }
private IEnumerator SendWebRequestWithTokenAndJson(string token, string json, string path)
    {
        UnityWebRequest request = new UnityWebRequest(serverURL   path, postMethod);
        byte[] jsonToSend = new UTF8Encoding().GetBytes(json);
        request.uploadHandler = new UploadHandlerRaw(jsonToSend);
        request.downloadHandler = new DownloadHandlerBuffer();
        request.SetRequestHeader("Authorization", "Bearer "   token);
        request.SetRequestHeader(requestName, requestValue);

        yield return request.SendWebRequest();

        RequestText = "";
        if (request.result != UnityWebRequest.Result.Success)
        {
            Debug.LogError("Error While Sending: "   request.error);
        }
        else
        {
            RequestText = request.downloadHandler.text;
        }

        yield break;
    }

CodePudding user response:

You can't really. When the application quits your scene and everything is going to be unloaded -> No Coroutine will execute anymore

What you can try is using a blocking/synchronous call just for that case and do e.g.

private void SendWebRequestWithTokenAndJsonSynchronous(string token, string json, string path)
{
    using(var request = new UnityWebRequest(serverURL   path, postMethod))
    {
        var jsonToSend = new UTF8Encoding().GetBytes(json);
        request.uploadHandler = new UploadHandlerRaw(jsonToSend);
        request.downloadHandler = new DownloadHandlerBuffer();
        request.SetRequestHeader("Authorization", "Bearer "   token);
        request.SetRequestHeader(requestName, requestValue);

        request.SendWebRequest();

        while(!request.isDone)
        {
            // Actually freeze until done
        }

        RequestText = "";
        if (request.result != UnityWebRequest.Result.Success)
        {
            Debug.LogError("Error While Sending: "   request.error);
        }

        Debug.Log("Upload successful!");
    }
}

Or alternatively block the application from quitting using Application.wantsToQuit but that's kind of tricky. (On iPhone this doesn't work! In the Editor this i also ignored!)

The idea here is:

  • Every time you save store the time of the last save
  • User wants to quit
  • Check if the last save was "recently enough" so let's say e.g. within the last 30 seconds
  • If yes, allow to quit
  • If no upload a save now and then automatically quit

For this you would probably need to change your method signatures a bit and e.g. add a callback action you can pass into the routine and invoke it as soon as the upload finished.


Note that there is always still a chance that both doesn't work at all! Some devices (e.g. HoloLens) never really quits the app clean (except you explicitly built a button for it). There all applications are rather hibernated and the User can literally kill them kind of like via the TaskManager.

CodePudding user response:

Handle it with OnApplicationQuit()

public IEnumerator SaveGameLogInfo02(string accessToken, string name, string rawdata, long time)

    {
        JObject json = new JObject();
        json.Add("name", name);
        json.Add("rawdata", rawdata);
        json.Add("time", time);

        yield return StartCoroutine(SendWebRequestWithTokenAndJson(accessToken, JsonConvert.SerializeObject(json), "/log/2/put"));

    allowQuitting = true;
    Application.Quit();

    }

void OnApplicationQuit()
{
    // Delay quit
    {
        SaveGameData(GameManager.Instance.GetSaveData());
    }

    // Check permission to cancel if not done
    if (!allowQuitting)
    {
        Application.CancelQuit();
    }
}
  • Related