Question

I've been struggling for a while with my app structure. And it really seems like this structure give me a lot of pain in the developing of other features. So before going further I'd like to have some advice and see if I'm doing something wrong here.

My app's purpose is to connect to a server, I use the AccountManager mechanism to create an account on the device and store a token which is supposed to be used to request data from the server. In the creation of the account, everything is fine. (It works as well from the device settings -> add an account)

It goes like this :

MainActivity is the activity that, when you launch the app, check if you have an account. If you have an account, I get the token in a static variable so every fragment in the MainActivity can access it. (Supposed to work but doesn't) Else, I create an intent with LoginActivity to create an account on the device. The problem is that my fragments can't get this token because, as i'm recovering the token in a thread using AccountManager.getAuthToken(), the fragments are created before this token is recovered. And therefore i can't request data from my server.

Which led me to think that my app structure might not be that good. So I was thinking, "What if I do like so?" :

  • The user launches the app
  • MainActivity act like a bootstrap which check for account and get token if there's an account on the device but do not generate any kind of view like the current version.
  • MainActivity either redirect to LoginActivity or ContentActivity (let's call it that way, an activity that's supposed to use my token to populate data in my ListViews)

That way lets me think that MainActivity will have the token to pass but I'm not sure it's ideal in terms of UX. (Gotta wait for token before accessing a content). I'm open to every suggestion at this point since I'm really stuck.

Thanks !

Update 1:

It's more of a login/registration app logic than handling AccountManager. I've managed to make them work but I just really struggle with the "best practice" app logic structure so I don't run into many other problems because of it (as I don't really have the time). All I need is a diagram or something to show me a "best practice" example to make my app works the way I explained above. I also ran into a problem because when I start the MainActivity it checks for an account and if not it launches LoginActivity but if I press back, i can see MainActivity (unfilled).

Was it helpful?

Solution

More of a general practice is what you're using:

General Practice

This structure is completely acceptable and is a normal flow of Server-Dependent apps. I prefer the model where logging is is just an option with some content that does not require logging in. Whenever an action that requires login is triggered, the user is shown the login. However, your model should work fine.

I see that your problems are

  1. I also ran into a problem because when I start the MainActivity it checks for an account and if not it launches LoginActivity but if I press back, i can see MainActivity (unfilled).

    This issue can be solved with an invisible Dispatch Activity that launches the MainActivity or the LoginActivity based on the status of the current user. As in the diagram, just finish() the Dispatch Activity after your decision. Your LoginActivity is responsible of relaunching the DispatchActivity which will redecide on the next step. Generally, do not override the onBackPressed of the LoginActivity to launch the Dispatch, just launch the Dispatch in case of successful login.

    However, if you've decided to show some Content in your Activity even if the user is not logged in, you can use the onActivityResult to refresh the Content of the MainActivity after a login request.

  2. The problem is that my fragments can't get this token because, as i'm recovering the token in a thread using AccountManager.getAuthToken(), the fragments are created before this token is recovered.

    This problem is normal. If your activities/fragments are already created when you are processing a login request, you must be able to inform these. Basically, if your fragments do not show "unauthenticated" content, then you should not face this problem because you should not even create these fragments until you are logged in.

    However, again, if you've decided to show some content in your Activities/Fragments even when the user is not logged in, you have to inform these running components about the status change. One way to do that is to implement an onResume in your activities that checks if the user is logged in and does the suitable changes. Another way is to use a Local broadcast to inform running activities/fragments that the state has changed:

    BroadcastReceiver mReciever = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
                //do whatever you want //check state
        }
    };
    
    public void onCreate(Bundle state) {
       //bla bla
       //bla bla
       LocalBroadcastManager.getInstance(mContext).registerReceiver(mReciever, new IntentFilter("your_package_name.LOGIN_STATE_CHANGED"));
    }
    

    Whenever the state changes, send a broadcast:

    Intent intent = new Intent("your_package_name.LOGIN_STATE_CHANGED");
    LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
    

Of course, this can turn out to be case-specific. For example, if you check the Touch App on Google Play, you will notice that I've created a dispatch screen that is visible regardless of the user's login state and then asked the user to login if he enters an Activity that requires login. In this case, any activity that requires login should implement its onActivityResult accordingly and update the ui if the user logged in or finish if the user didn't. On the other hand, the psst app on Google Play uses a splash screen to decide whether to go to the Login Screen or the Main Screen depending on the user's state.

OTHER TIPS

sample code ..

public class DispatchActivity extends ActionBarActivity {


    SharedPreferences prefs = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);


        prefs = getSharedPreferences("me.sanath.megh", MODE_PRIVATE);
        boolean islogin = prefs.getBoolean("islogin",false);
        if(islogin)
        {
            Intent i = new Intent(this,homepageActivity.class);
            startActivity(i);
            finish();
        }else{

            Intent i = new Intent(this,LoginActivity.class);
            startActivityForResult(i,1);
        }
    }

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        if (requestCode == 1) {
            boolean islogin = prefs.getBoolean("islogin",false);
            if(islogin)
            {
                Intent i = new Intent(this,homepageActivity.class);
                startActivity(i);
                finish();
            }else{

                Intent i = new Intent(this,LoginActivity.class);
                startActivityForResult(i,1);

            }
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top