Use EditText value as baseUrl in Retrofit

267 views Asked by At

I'm creating an app where the user has to insert a serverurl in an EditText field, and that url should be the baseUrl of the retrofit-request. So, my code works as it should when i use a hardcoded baseurl, but the app crashes when I try to pass the value from the Edittext to the baseUrl.

Thats how I tried to pass the value:

object NetworkLayer {

        var newUrl: String = ""

        val retrofit: Retrofit
            get() = Retrofit.Builder()
                .baseUrl(newUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .build()

        val myApi: MyApi by lazy {
            retrofit.create(MyApi::class.java)
        }
        val apiClient = ApiClient(myApi)
    }

and in my MainActivity:

 var serverUrl = binding.et1.text.toString()
        
        button.setOnClickListener {
            NetworkLayer.newUrl = serverUrl
            viewModel.getServerInformation(headerValue)
        }

I get this error message: Error message: Caused by: java.lang.IllegalArgumentException: Expected URL scheme 'http' or 'https' but no scheme was found for.

So probably retrofit uses the empty "" string for the request. Somehow I should send the information to retrofit that when clicking the button the url from the Edittext (et1) is the baseUrl. When I use a seperate class (f.e. class Constants, with a companion object with a const val baseUrl = "hardcoded url") it works also. Can I create a function to inform the retrofit client to use the Edittext as baseUrl and declare it in the onClickListener? or could it be a way to create the retrofit client in a class instead of an object? (using url: String as parameter in the class and adding the edittext as argument in the MainActivity?) Sadly the @Url annotation for Retrofit doesn't work as I have to use also @Header and @Query in the different requests.

Or is there a compeletey different way for doing this?

Hopefully there is someone who can help me.

1

There are 1 answers

0
Alex Mutschl On BEST ANSWER

I managed to solve it, the only thing I had to change was: val url = binding.etServerUrl.text instead of val url = binding.etServerUrl.text.toString()

and when calling the function on button click I added the toString() to the url argument. When I try to add the toString() to the val url as I always did before it doesn't work, anyone can tell me why?

Here is an example how I use it (I changed the Retrofit client a bit to my first version in the question). So finally I can go ahead with my app, as I was blocked now for a few weeks with this.. :-)

object RetrofitClient{

    var retrofitService: MyApi? = null
    
    fun getInstance(url: String): MyApi{

        if (retrofitService == null) {
            val retrofit = Retrofit.Builder()
                .baseUrl(url)
                .addConverterFactory(GsonConverterFactory.create())
                .build()
            retrofitService = retrofit.create(MyApi::class.java)
        }
        return retrofitService!!
    }
}

I changed the retrofitclient a bit, but it wors Then in the repository:

class MainRepository (){

    suspend fun getToken(cookie: String, url: String): TokenResponse? {
        val request = RetrofitClient.getInstance(url).getToken(cookie)

        if (request?.isSuccessful!!) {
            return request.body()!!
        }

        return null
    }
}

Viewmodel:

class SharedViewModel() : ViewModel() {

    private val repository = MainRepository()


    private val _getTokenLiveData = MutableLiveData<TokenResponse>()
    val getTokenLiveData: LiveData<TokenResponse> = _getTokenLiveData


    fun getToken(cookie: String, url: String) {
        viewModelScope.launch {
            val response = repository.getToken(cookie, url)
            _getTokenLiveData.postValue(response)
        }
    }
}

And finally the MainActivity:

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    val viewModel: SharedViewModel by lazy {
        ViewModelProvider(this)[SharedViewModel::class.java]
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater) //initializing the binding class
        setContentView(binding.root)

        val url = binding.etServerUrl.text
        val headerValue = binding.etMac.text.toString()
        val button = binding.button
        val textView = binding.textView

        button.setOnClickListener {
            viewModel.getToken(headerValue, url = url.toString())
        }


        viewModel.getTokenLiveData.observe(this) { response ->
            if (response == null) {
                Toast.makeText(this@MainActivity, "Fehlerhaft", Toast.LENGTH_SHORT).show()
                return@observe
            }
            textView.text = response.js.token

        }

    }
}