Home > database >  Android Studio Login Token Request Error using Retrofit and SharedPreferences
Android Studio Login Token Request Error using Retrofit and SharedPreferences

Time:01-21

A token is sent to the client when I login, so I'm going to use the retrofit library to take the token and include it in the header of the request and send the data to the server.

When I login, I want to save data through the SharedPreferences library to store tokens delivered to the client locally.

But there is error :

FATAL EXCEPTION: main
                                                                                                    Process: com.example.todo_android, PID: 7323
                                                                                                    java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.SharedPreferences android.content.Context.getSharedPreferences(java.lang.String, int)' on a null object reference
                                                                                                        at android.content.ContextWrapper.getSharedPreferences(ContextWrapper.java:217)
                                                                                                        at com.example.todo_android.MainActivity.saveData(MainActivity.kt:30)
                                                                                                        at com.example.todo_android.Screen.LoginScreenKt$sendLogin$1.onResponse(LoginScreen.kt:64)
                                                                                                        at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall$1$1.run(DefaultCallAdapterFactory.java:83)
                                                                                                        at android.os.Handler.handleCallback(Handler.java:942)
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:99)
                                                                                                        at android.os.Looper.loopOnce(Looper.java:201)
                                                                                                        at android.os.Looper.loop(Looper.java:288)
                                                                                                        at android.app.ActivityThread.main(ActivityThread.java:7872)
                                                                                                        at java.lang.reflect.Method.invoke(Native Method)
                                                                                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
                                                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)

Actually When I login only with body json without Header and SharedPreferences, its working and it gives me token and resultCode.

resultCode : 200
token : e91389ca537f481d1937a43c49da0d5b827e5cfd

There is code:

Login Model

package com.example.todo_android.Data.Profile

data class Login(
    val email: String,
    val password: String
    )

LoginRequest

package com.example.todo_android.Request.ProfileRequest

import com.example.todo_android.Data.Profile.Login
import com.example.todo_android.Response.ProfileResponse.LoginResponse
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.POST

interface LoginRequest {
    @POST("/account/login/")
    fun requestLogin(
//        @Header("Authorization") token: String,
        @Body loginRequest: Login
    ) : Call<LoginResponse>
}

LoginResponse

package com.example.todo_android.Response.ProfileResponse

import com.google.gson.annotations.SerializedName

data class LoginResponse(
    @SerializedName("resultCode")
    val resultCode: String,
    @SerializedName("token")
    val token: String
)



**LoginScreen**

package com.example.todo_android.Screen

import android.util.Log
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.unit.dp
import com.example.todo_android.Data.Profile.Login
import com.example.todo_android.MainActivity
import com.example.todo_android.Navigation.Action.RouteAction
import com.example.todo_android.Navigation.NAV_ROUTE
import com.example.todo_android.R
import com.example.todo_android.Request.ProfileRequest.LoginRequest
import com.example.todo_android.Response.ProfileResponse.LoginResponse
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

fun goCalendar(route: NAV_ROUTE, routeAction: RouteAction) {
    routeAction.navTo(route)
}

@ExperimentalMaterial3Api
fun sendLogin(email: String, password: String, routeAction: RouteAction) {

    var loginResponse: LoginResponse? = null

    var retrofit = Retrofit.Builder()
        .baseUrl("https://plotustodo-ctzhc.run.goorm.io/")
        .addConverterFactory(GsonConverterFactory.create())
        .build()

    var loginRequest: LoginRequest = retrofit.create(LoginRequest::class.java)

    loginRequest.requestLogin(Login(email, password)).enqueue(object : Callback<LoginResponse> {

        //실패할 경우
        override fun onFailure(call: Call<LoginResponse>, t: Throwable) {
            Log.e("LOGIN", t.message.toString())
        }

        //성공할 경우
        override fun onResponse(call: Call<LoginResponse>, response: Response<LoginResponse>) {
            loginResponse = response.body()

            when (loginResponse?.resultCode) {
                "200" -> {
                    goCalendar(NAV_ROUTE.CALENDAR, routeAction)

                    Log.d("LOGIN", "resultCode : "   loginResponse?.resultCode)
                    Log.d("LOGIN", "token : "   loginResponse?.token)
                    Log.d("LOGIN", "메인 화면으로 갑니다.")

                    MainActivity().saveData(loginResponse?.token.toString())
                }
                "500" -> {
                    Log.d("LOGIN", "non_field_errors:[Check Your Email or Password]")
                }
            }
        }
    })
}

@ExperimentalMaterial3Api
@Composable
fun LoginScreen(routeAction: RouteAction) {
    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    )
    {
        var email by remember { mutableStateOf("") }
        var password by remember { mutableStateOf("") }


        TextField(
            modifier = Modifier.width(300.dp),
            value = email,
            colors = TextFieldDefaults.textFieldColors(
                Color(0xff9E9E9E),
                disabledLabelColor = Color(0xff9E9E9E),
                focusedIndicatorColor = Color.Transparent,
                unfocusedIndicatorColor = Color.Transparent
            ),
            singleLine = true,
            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email),
            shape = RoundedCornerShape(20.dp),
            onValueChange = {
                email = it
            })
        Spacer(modifier = Modifier.height(30.dp))
        TextField(
            modifier = Modifier.width(300.dp),
            value = password,
            colors = TextFieldDefaults.textFieldColors(
                Color(0xff9E9E9E),
                disabledLabelColor = Color(0xffE9E9E9),
                focusedIndicatorColor = Color.Transparent,
                unfocusedIndicatorColor = Color.Transparent
            ),
            singleLine = true,
            visualTransformation = PasswordVisualTransformation(),
            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
            shape = RoundedCornerShape(20.dp),
            onValueChange = {
                password = it
            })
        Spacer(modifier = Modifier.height(60.dp))
        Button(
            modifier = Modifier
                .width(300.dp)
                .height(50.dp),
            colors = ButtonDefaults.buttonColors(Color(0xffFFBE3C7)),
            onClick = { sendLogin(email, password, routeAction) }
        ) {
            Text(text = stringResource(id = R.string.login), color = Color.Black)
        }
    }
}

MainActivity

package com.example.todo_android

import android.content.Context
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material3.ExperimentalMaterial3Api
import com.example.todo_android.Navigation.NavigationGraph
import com.example.todo_android.ui.theme.TodoandroidTheme

@ExperimentalMaterial3Api
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            TodoandroidTheme {
                NavigationGraph()
            }
        }
        loadData()
    }


    fun loadData() {
        val pref = getSharedPreferences("UserTokenKey", Context.MODE_PRIVATE) // UserTokenKey: 파일명
        val token = pref.getString("Token", "")
    }

    fun saveData(token: String) {
        val pref = getSharedPreferences("UserTokenKey", Context.MODE_PRIVATE) // UserTokenKey: 파일명
        val edit = pref.edit()
        edit.putString("Token", token) // "Token"라는 이름을 사용하여 token값을 입력한다.
        edit.commit()
    }
}

I would appreciate it if you could tell me which part was implemented incorrectly and how to correct it.

CodePudding user response:

As stated in the log, the exact problem is:

java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.SharedPreferences android.content.Context.getSharedPreferences(java.lang.String, int)' on a null object reference
  at android.content.ContextWrapper.getSharedPreferences(ContextWrapper.java:217)
  at com.example.todo_android.MainActivity.saveData(MainActivity.kt:30)
  at com.example.todo_android.Screen.LoginScreenKt$sendLogin$1.onResponse(LoginScreen.kt:64)

which points to this line

MainActivity().saveData(loginResponse?.token.toString())

You cannot instantiate a new MainActivity class in order to call the function saveData(). The Context used to call getSharedPreferences() will be null if your MainActivity is created like that.

So you can try if the following options address the problem:

  1. Make your saveData() as a callback function, pass it to the necessary class to call
  2. Pass Context to the class you need to call getSharedPreferences(), and call it like Context.getSharedPreferences()
  • Related