Search code examples
androidlibgdxsaving-data

How do apps save data


This might be a stupid question, and this might also be a duplicate. But, I really do not know and have not been able to find the solution to it, at all. My question is, how do apps save data. I'm making an app with LibGDX and Java for Android devices, and am just stuck pondering on this. How is it that, for example, when I close down Candy Crush and reopen it the day after, it remembers where I'm at even though the app resets? If this does happen to be a duplicate, I would strongly appreciate the other forum, and apologize for duplicating. I just haven't been able to find one. Thanks in advance!


Solution

  • This is a broad question but I try to cover a view elements on the topic. Candy Crush Sage resets itself if you do not register or associate your account with something like Facebook and reinstall the app. They most likely use a database to store things in. If you are not registered things might just be stored locally.

    LibGDX offers a handy feature to store data locally. It's called Preferences and you simply write to it and the next time you open your app it persists.

    Preferences pref = Gdx.app.getPreferences("somefile");
    pref.putString("name", "Menyo");
    pref.putInteger("level", 20);
    

    However when you uninstall this data goes with it and it's neither very secure for players that like to "investigate". Other then that you can store your own created data in some place. If you store it outside the internal app it persists even after deleting the app and as long the data stays and your app looks in the same location after a reinstall you should be able to retrieve the data. But as you might expect this is not fail-proof either.

    The only real way to make sure is to have somekind of login mechanism. The most viable way is a database. I have a similar system running now but there is a server in between the client and the database. You can store any data in the database and link it to the player by his ID.

    • New players can opt to play as a guest. This creates a new account with "Guest" + id as a name. When a player links it's account to something like Facebook or a email address the account will persist and so will the data linked to it.

    • Existing players will login when they install your app and you can store there login information on there device so they automatically login if that data exists and is valid.

    To setup a database I strongly advice to never connect directly to the database through the clients device. Either have a webservice or like I am currently doing a KryoNet server. The reason here is that you need to sanitize data coming from clients. You could do this from a clients device but you do not have full control over a that. Do your sanitizing of user input always on the server side.

    Creating a webservice to connect trough a database is pretty easy if you know a bit of PHP and mysql. All you need is sending a HttpRequest to that php page and let it do the work.

    public class WebTest {
        HttpRequestBuilder builder;
        Net.HttpRequest request;
    
        public WebTest()
        {
            builder = new HttpRequestBuilder();
            request = builder.newRequest().method(Net.HttpMethods.GET).url("http://yourdomain.com/script.php").build();
            request.setHeader("Content-Type", "application/x-www-form-urlencoded");
    
    
            final long start = System.nanoTime();
            Gdx.net.sendHttpRequest(request, new Net.HttpResponseListener() {
                @Override
                public void handleHttpResponse(Net.HttpResponse httpResponse) {
                    Gdx.app.log("Test", "HTTP Response code: " + httpResponse.getStatus().getStatusCode());
                    Gdx.app.log("Test", "HTTP Response code: " + httpResponse.getResultAsString());
                    Gdx.app.log("Test", "Response time: " + ((System.nanoTime() - start) / 1000000) + "ms");
                }
    
                @Override
                public void failed(Throwable t) {
                    Gdx.app.log("Test", "HTTP request failed");
                }
    
                @Override
                public void cancelled() {
                    Gdx.app.log("Test", "HTTP request cancelled");
                }
            });
        }
    }
    

    Put a php script called script.php in yourdomain.com and echo something out in it. Then this code should receive that echo inside your app.

    You can also create xml and parse that with your favorite parser. But you have to set the header of the request to receive xml properly.

    request.setHeader("Content-Type", "text/xml");
    

    Here is a PHP MySQL connection that sends feedback in XML.

    <?php
    $link = mysqli_connect("127.0.0.1", "root", "", "chatapp");
    $xml = new SimpleXMLElement("<?xml version=\"1.0\" encoding=\"utf-8\" ?><mysql></mysql>");
    if (!$link)
    {
        $xml->addChild("error", "Error: Unable to connect to MySQL.");
        $xml->addChild("error", "Debugging errno: " . mysqli_connect_errno());
        $xml->addChild("error", "Debugging error: " . mysqli_connect_error());
        exit;
    }
    
    $xml->addChild("success", "Success: A proper connection to MySQL was made!");
    $xml->addChild("success", "Host information: " . mysqli_get_host_info($link));
    
    //Sends the xml to whoever requested this
    print($xml->asXML());
    
    mysqli_close($link);
    ?>
    

    Now you can simply use PHP to login a user into the database like you would do with a regular web page. There are plenty of php tutorials that cover this subject. Of course you can use any server side scripting for this.

    Your own server to connect to a database is possible too but requires a lot more work. But KryoNet takes a lot of work from you. Your own server does mean you can store data on the server and exchange those very fast through a TCP or UDP connection. You basically have much more control over what is being exchanged.