3

I am building an Android application where one activity is a login screen. When the app is opened, if a user has already logged in, I would like to skip the LoginActivity and have the user be directed to another one. When a user logs into my app (using Google Firebase), I save their username and other data in their device's shared preferences. When they log out, their shared preferences are cleared.

The way I currently have my manifest file is such that the only activity that can be opened when the app is started is the LoginActivity:

        <activity android:name=".LoginActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

In the LoginActivity's OnCreate() method, if there is a username saved in the shared preferences (meaning a user is logged in), I immediately change activities:

public class LoginActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        SharedPreferences userData = getApplicationContext().
                getSharedPreferences("userdata", 0);
        String n = userData.getString("username", "");
        if (!userData.getString("username", "").equals(""))
        {
            Intent myIntent = new Intent(LoginActivity.this, TabbedActivity.class);
            startActivity(myIntent);
        }
}

However, there is a problem with this approach. Many times, the LoginActivity is still shown for a split second before starting the TabbedActivity. I would like to fix this so that the LoginActivity is actually never seen at all if a user is logged in.

I assume that the approach I'm taking is all wrong and there is a much cleaner way of doing it such that the correct activity is immediately opened. Any help on this would be greatly appreciated.

Justin
  • 107
  • 1
  • 10
  • Do you implement splash? – Xid Sep 14 '20 at 18:19
  • I do not. I suppose that could be an option, however, when I use apps like SnapChat for example, they don't use a splash screen. If I'm logged in, I go to the main activity of the app and neither the login screen nor a splash screen is shown. – Justin Sep 14 '20 at 18:21
  • Then I suppose you could set the content view for the login screen only if the user is not logged in. That way your login screen content won't be shown before you navigate to main activity. – Xid Sep 14 '20 at 18:23
  • 1
    This would work in terms of aesthetics, which I will say was my main concern. However, this approach would still lack in performance. There would at least be a black screen before the activity is started. In my SnapChat example in my last comment, there never seems to be a moment where you're waiting for the activity to open - no black screen, no splash screen. – Justin Sep 14 '20 at 19:21
  • That's because Snapchat has a splash. Splash is implemented as a background with the use of a theme. Check [this](https://stackoverflow.com/a/15832037/12313157) – Xid Sep 14 '20 at 19:26
  • I do also want to add that this is the best solution so far though. I do appreciate it and I will use this approach until something better comes along. – Justin Sep 14 '20 at 19:27
  • There would no performance issue with using a theme for the splash and changing it in the activity. However, having a separate activity/fragment for splash is not a good idea unless necessary. As you mentioned a black screen is shown between app launcher click and the first activity being shown. The theme will just replace that black screen. – Xid Sep 14 '20 at 19:31
  • Oh, you're right Snapchat does have a splash. That makes a lot of sense. I will make a splash to make this transition seem more smooth, thank you so much. If I could run another similar issue by you... If I put my app in the background (Pause) then reopen it (Resume), I get a black screen for a moment. I notice in this scenario, Snapchat does NOT use a splash and it doesn't flash a black screen when it's resumed. How could I achieve this? – Justin Sep 14 '20 at 19:38
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/221476/discussion-between-siddharth-sharma-and-justin). – Xid Sep 14 '20 at 19:39

3 Answers3

2

A possible approach:

  1. Create a style for splash theme:
<style name="SplashTheme" parent="Theme.AppCompat.NoActionBar">
    <item name="android:statusBarColor">@color/background_splash</item>
    <item name="android:windowBackground">@drawable/background_splash</item>
</style>
  1. Create a background drawable (drawable/background_splash.xml) for splash:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <color android:color="@color/background_splash"/>
    </item>
    <item>
        <bitmap
            android:src="@drawable/ic_splash_logo"
            android:gravity="center"/>
    </item>
</layer-list>
  1. In your manifest, set the SplashTheme as your application/launcher-activity theme:
<application
    ...
    android:theme="@style/SplashTheme">

<!-- or -->

<activity
    ...
    android:theme="@style/SplashTheme">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

  1. In your LoginActivity in onCreate() set your normal app theme and content view if the user is not logged in and also set app theme in the MainActivity (or set it in the Manifest)
public class LoginActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        val isUserLoggedIn = ...
        if (!isUserLoggedIn)
        {
            setTheme(R.style.AppTheme)
            setContentView(R.layout.activity_login)
        } 
        else {
            //Navigate to Main Activity
        }
    }
}

Splash screen reference

Xid
  • 4,578
  • 2
  • 13
  • 35
1

I'm not sure if this is the best approach, but you could create a Loading activity that start the activity needed in any situation like.

public class LoadingActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        SharedPreferences userData = getApplicationContext().
                getSharedPreferences("userdata", 0);
        String n = userData.getString("username", "");
        if (!userData.getString("username", "").equals(""))
        {
            Intent myIntent = new Intent(LoginActivity.this, TabbedActivity.class);
            startActivity(myIntent);
        }else{
            Intent myIntent = new Intent(OtherActivity.this, TabbedActivity.class);
            startActivity(myIntent);
        }
}

And about the view add a gif or a logo meanwhile.

0

I have an implementation, but no shared preferences, and I don't see the login screen at any time.

My structure is as follows: I have an initial splash screen, then a main activty, which is where I override the onStart method to check if the user has an open section if it is passed to the home activity.

I hope it helps you, if you don't tell me and I'll add more code.

public override fun onStart() {
    super.onStart()
    // if user is loged goto Home Activity
    if (firebaseUser != null) {
        // Name, email address, and profile photo Url
        val name = firebaseUser?.displayName
        val email = firebaseUser?.email
        val photoUrl = firebaseUser?.photoUrl
        val uid = firebaseUser?.uid
        val emailVerified = firebaseUser!!.isEmailVerified
                  
        goToActivity<HomeActivity>()
    }
}
Martin Bove
  • 645
  • 6
  • 11
  • I actually tried this approach in my onCreate first - where I check if the Firebase user is null or not. The same exact behavior occurred. The only difference is that you're doing this in onStart(). This would actually exaggerate the problem a little bit since onStart() is called after onCreate(). – Justin Sep 14 '20 at 19:18
  • Another possibility that occurs to me is that you make the entire layout invisible until the user state is resolved. Or maybe make an application class that would be loaded before the activity to resolve the state of the user. – Martin Bove Sep 14 '20 at 19:49