5

I am creating a HoloLens app using Unity which has to take data from a REST API and display it. I am currently using WWW datatype to get the data and yield return statement in a coroutine that will be called from the Update() function. When I try to run the code, I get the latest data from the API but when someone pushes any new data onto the API, it does not automatically get the latest data in real time and I have to restart the app to see the latest data. My Code:

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;

public class TextChange : MonoBehaviour {

    // Use this for initialization
    WWW get;
    public static string getreq;
    Text text;
    bool continueRequest = false;

    void Start()
    {
        StartCoroutine(WaitForRequest());
        text = GetComponent<Text>();
    }

    // Update is called once per frame
    void Update()
    {

    }

    private IEnumerator WaitForRequest()
    {
        if (continueRequest)
            yield break;

        continueRequest = true;

        float requestFrequencyInSec = 5f; //Update after every 5 seconds 
        WaitForSeconds waitTime = new WaitForSeconds(requestFrequencyInSec);

        while (continueRequest)
        {
            string url = "API Link goes Here";
            WWW get = new WWW(url);
            yield return get;
            getreq = get.text;
            //check for errors
            if (get.error == null)
            {
                string json = @getreq;
                List<MyJSC> data = JsonConvert.DeserializeObject<List<MyJSC>>(json);
                int l = data.Count;
                text.text = "Data: " + data[l - 1].content;
            }
            else
            {
                Debug.Log("Error!-> " + get.error);
            }

            yield return waitTime; //Wait for requestFrequencyInSec time
        }
    }

    void stopRequest()
    {
        continueRequest = false;
    }
}

public class MyJSC
{
    public string _id;
    public string author;
    public string content;
    public string _v;
    public string date;
}
Programmer
  • 104,912
  • 16
  • 182
  • 271
Killing_Falcon
  • 196
  • 1
  • 9
  • You shouldn't be calling a coroutine function in the Update function like you did in your question. That's like making 60+ requests in a second. I have addressed that in your question by replacing it with a code that waits then makes a request again. If that doesn't solve your problem then see my answer. – Programmer Jul 14 '16 at 07:23
  • Did you try the solution? – Programmer Jul 14 '16 at 09:03
  • 1
    Yes, and it worked like a charm.... – Killing_Falcon Jul 14 '16 at 11:11

1 Answers1

8

This is happening because resources caching is enabled on the Server.

Three possible solutions I know about:

1.Disable resources caching on the server. Instructions are different for every web server. Usually done in .htaccess.

2.Make each request with unique timestamp. The time should in Unix format.

This method will not work on iOS. You are fine since this is for HoloLens.

For example, if your url is http://url.com/file.rar, append ?t=currentTime at the end. currentTime is the actual time in Unix Format.

Full example url: http://url.com/file.rar?t=1468475141

Code:

string getUTCTime()
{
    System.Int32 unixTimestamp = (System.Int32)(System.DateTime.UtcNow.Subtract(new System.DateTime(1970, 1, 1))).TotalSeconds;
    return unixTimestamp.ToString();
}

private IEnumerator WaitForRequest()
{
    string url = "API Link goes Here" + "?t=" + getUTCTime();
    WWW get = new WWW(url);
    yield return get;
    getreq = get.text;
    //check for errors
    if (get.error == null)
    {
        string json = @getreq;
        List<MyJSC> data = JsonConvert.DeserializeObject<List<MyJSC>>(json);
        int l = data.Count;
        text.text = "Data: " + data[l - 1].content;
    }
    else
    {
        Debug.Log("Error!-> " + get.error);
    }
}

3.Disable Cache on the client side by supplying and modifying the Cache-Control and Pragma headers in the request.

Set Cache-Control header to max-age=0, no-cache, no-store then set Pragma header to no-cache.

I suggest you do this with UnityWebRequest instead of the WWW class. First, Include using UnityEngine.Networking;.

Code:

IEnumerator WaitForRequest(string url)
{

    UnityWebRequest www = UnityWebRequest.Get(url);
    www.SetRequestHeader("Cache-Control", "max-age=0, no-cache, no-store");
    www.SetRequestHeader("Pragma", "no-cache");

    yield return www.Send();
    if (www.isError)
    {
        Debug.Log(www.error);
    }
    else
    {
        Debug.Log("Received " + www.downloadHandler.text);
    }
}
Community
  • 1
  • 1
Programmer
  • 104,912
  • 16
  • 182
  • 271
  • As a side note, you should also address the call in Update. At the moment, there are dozens of coroutine started per frame. InvokeRepeating is more appropriate. – Everts Jul 14 '16 at 06:47
  • @Everts Just noticed that and you are correct. My answer is already long and I don't want to make it longer. I have modified his answer to fix that and commented under his question to let him know about that. Note that you can't use all type of Unity `Invoke` functions with coroutines. `while` loop seems to be appropriate for this. Check the updated code in his question to see what I mean. – Programmer Jul 14 '16 at 07:23
  • Make a void method that start the coroutine then you can use InvokeRepeating. – Everts Jul 14 '16 at 07:34
  • Yes, you can do that too. Another reason why `while` loop is appropriate for this is that `StartCoroutine` allocates memory each time it is called. Call it once and let it run forever. The only memory allocation now is the `WWW` class which you can't prevent. For list List, he can put it outside the while loop then re-use it. – Programmer Jul 14 '16 at 07:40
  • Why wouldn't it work on iOS? As long as the URL is different in a GET request or it is a POST request that might or might not have a differing request it should work. – Krzysztof Bociurko Jul 14 '16 at 09:57
  • 1
    @ChanibaL It used to work on iOS. There was an iOS version update that stopped it from working. I can't remember which one but this was years ago and there was a post about this. I can't find it anymore. Also, that method didn't work last time I tried it on iOS. Anyways, that was a heads up for the OP just in-case there is a problem with that method. – Programmer Jul 14 '16 at 10:49