1

I am developing an app and I use Socket.io on it, I initialize the socket in a class that extends Application and looks like this:

public class Inicio extends Application{
    private Socket mSocket;
    private SharedPreferences spref;

    @Override
    public void onCreate(){
        super.onCreate();
        try{
            spref = getSharedPreferences("accountData", Context.MODE_PRIVATE);
            IO.Options op = new IO.Options();
            op.forceNew = true;
            op.reconnection = true;
            op.query = "tok=" + spref.getString("sessiontoken", "") + "&usr=" + spref.getString("userid", "");
            mSocket = IO.socket(Constants.serverAddress, op);
        }catch(URISyntaxException e){
            throw new RuntimeException(e);
        }
    }

    public Socket getmSocket(){
        return mSocket;
    }
}

So I can get and use the same socket instance in other parts of my application's code calling the following way:

Inicio appClass = (Inicio) getApplication();
mSocket = appClas.getmSocket();
mSocket.connect();

But there is a small problem that motivated me to post this question, can you see when I call to SharedPreferences in the Application class? I do this because I need to send the session token and user account ID to properly start the socket connection with my server, the problem is:

Imagine that a user opens the app for the first time and does not have an account yet, he will login or register and then the session token and user ID will be saved to SharedPreferences, but when the app started and ran the Application class, SharedPreferences was still empty and did not have the required token and user ID to establish the connection, so the user would have to reopen the app now to be able to use the socket successfully.

So I ask you: What are my alternative options for solving the problem? Is there another structure besides the Application class that I could use to not suffer from this problem? Or is there some way to bypass this problem?

What I'm doing to get around the problem for now is to restart the app programmatically when login occurs but I believe this is looks like a sad joke and not the ideal way to do it.

Thanks, I apologize for this long question of mine, but I'll be grateful for any help.

  • From where you store the `sessiontoken `? – Md. Asaduzzaman Dec 04 '19 at 20:03
  • @Md.Asaduzzaman, It's successfully stored during user login, but as I call this in the Application class, it's empty when the app is opened for the first time, then the user would need to login and then reopen the app then it will always work. But the application class runs before anything else in app's startup, so the user need to reopen it to the Application class to read the populated SharedPreferences. – deniable_encryption Dec 04 '19 at 20:13

1 Answers1

1

Separate your soket creation logic like below:

private void createSoket() {
    spref = getSharedPreferences("accountData", Context.MODE_PRIVATE);
    String sessiontoken = spref.getString("sessiontoken", "");
    String userId = spref.getString("userid", "");

    if(!(TextUtils.isEmpty(sessiontoken) || TextUtils.isEmpty(userId))) {
        try {

            IO.Options op = new IO.Options();
            op.forceNew = true;
            op.reconnection = true;
            op.query = "tok=" + sessiontoken + "&usr=" + userId;
            mSocket = IO.socket(Constants.serverAddress, op);
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
    }
}

And when required soket check null and create before pass the instance.

public Socket getmSocket(){
    if(mSoket == null)
        createSoket();

    return mSocket;
}

N.B: Without valid settionToken and userId, soket is null

This is complete Application class:

public class Inicio extends Application{
    private Socket mSocket;
    private SharedPreferences spref;

    @Override
    public void onCreate(){
        super.onCreate();
        createSoket();
    }

    private void createSoket() {
        spref = getSharedPreferences("accountData", Context.MODE_PRIVATE);
        String sessiontoken = spref.getString("sessiontoken", "");
        String userId = spref.getString("userid", "");

        if(!(TextUtils.isEmpty(sessiontoken) || TextUtils.isEmpty(userId))) {
            try {

                IO.Options op = new IO.Options();
                op.forceNew = true;
                op.reconnection = true;
                op.query = "tok=" + sessiontoken + "&usr=" + userId;
                mSocket = IO.socket(Constants.serverAddress, op);
            } catch (URISyntaxException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public Socket getmSocket(){
        if(mSoket == null)
            createSoket();

        return mSocket;
    }
}
Md. Asaduzzaman
  • 14,963
  • 2
  • 34
  • 46
  • Thanks for the answer, I will test and then I will reply to you here afterwards. – deniable_encryption Dec 04 '19 at 20:17
  • With this will I be able to use the socket instance anywhere in the application? How should I call this class of yours where I want to use the socket? Should I place your code in a separate normal class or what? Thanks for the support. – deniable_encryption Dec 04 '19 at 20:18
  • 1
    Right now go with your `Inicio` class – Md. Asaduzzaman Dec 04 '19 at 20:20
  • But if I keep Inicio class as a Application-extended class, it will run when the app starts and the SharedPreferences always will be empty if the user isn't logged in and the user will still have to reset the app after login to have the socket working – deniable_encryption Dec 04 '19 at 20:24
  • 1
    Check the complete application class in my answer – Md. Asaduzzaman Dec 04 '19 at 20:27
  • It didn't work, but I have already found another way by myself. Anyway, thanks for replying. – deniable_encryption Dec 04 '19 at 20:40
  • 1
    You are welcome. Please post your answer also. I need the idea – Md. Asaduzzaman Dec 04 '19 at 20:42
  • Yours is good, but I would like to know how to initialize the socket when a user that is using the app for the first time log in, since Application class runs once when app starts and when the app starts for a new user, his SharedPreferences are empty, so this new user needs to login and reopen the app – deniable_encryption Dec 04 '19 at 21:03
  • 1
    Soket is initialize whenever your call `getSoket()` if is not initialize before. No relation with application class load. Application class load one time but it remain alive all the time till you close the application – Md. Asaduzzaman Dec 04 '19 at 21:08
  • Awww, wait, I think I understood what you meant. I apologize for taking so long to understand the point. – deniable_encryption Dec 04 '19 at 21:13
  • Okay, upvoted. I thought I had upvoted before, but there wasn't, but now I did. Thanks again for your help. – deniable_encryption Dec 06 '19 at 16:28