Используйте значение EditText в качестве baseUrl в модификации

Я создаю приложение, в котором пользователь должен вставить URL-адрес сервера в поле EditText, и этот URL-адрес должен быть базовым URL-адресом запроса на модификацию. Итак, мой код работает как надо, когда я использую жестко заданный базовый URL-адрес, но приложение вылетает, когда я пытаюсь передать значение из Edittext в baseUrl.

Вот как я пытался передать значение:

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)
    }

и в моей MainActivity:

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

Я получаю это сообщение об ошибке: Сообщение об ошибке: Причина: java.lang.IllegalArgumentException: Ожидаемая схема URL-адреса «http» или «https», но схема не найдена.

Так что, вероятно, модификация использует пустую строку "" для запроса. Каким-то образом я должен отправить информацию для модификации, что при нажатии кнопки URL-адрес из Edittext (et1) является baseUrl. Когда я использую отдельный класс (например, константы класса с сопутствующим объектом с const val baseUrl = "жестко закодированный URL-адрес"), он также работает. Могу ли я создать функцию, чтобы сообщить модифицируемому клиенту использовать Edittext в качестве baseUrl и объявить его в onClickListener? или это может быть способ создать модифицированный клиент в классе вместо объекта? (используя url: String в качестве параметра в классе и добавляя текст редактирования в качестве аргумента в MainActivity?) К сожалению, аннотация @Url для Retrofit не работает, так как мне приходится использовать также @Header и @Query в разных запросах.

Или есть другой способ сделать это?

Надеюсь, есть кто-то, кто может мне помочь.

похоже, вы должны добавить http:// или https:// к значению, введенному пользователем. Хотя stackoverflow.com/questions/32559333/retrofit-2-dynamic-url может дать вам несколько альтернативных идей.

Chris 19.12.2022 17:50

Привет, я попробовал приложение с эмулятором. Я вставил тот же URL-адрес в текст редактирования, который я использовал как жестко закодированный. Жестко запрограммировано, но при вставке в edittext нет. Вот почему я думаю, что значение edittext не было передано как baseurl. Спасибо за ссылку, со временем я смогу использовать @Url и добавлять запросы другим способом. Но я не уверен, что делать с заголовками. Не думал, что так сложно использовать текст редактирования в качестве переменной и передавать его в baseurl... :-)

Alex Mutschl 19.12.2022 19:16

Затем вы должны проверить значение, извлеченное из текста редактирования. Если вы используете kotlin, должно быть достаточно оператора `println` или, возможно, точки останова.

Chris 20.12.2022 09:00

Отладка показывает мне "" , а не значение, которое я вставил в поле edittext. Таким образом, текст редактирования не «переносится» в переменную Networklayer. Любой намек, почему это не работает?

Alex Mutschl 20.12.2022 13:53

Возможно, apiClient создается немедленно. И в этот момент URL-адрес представляет собой значение newUrl, которое является пустой строкой. Может, тоже изменить apiClient на лень?

Chris 20.12.2022 15:42

О, это звучит понятно.. Вы имеете в виду val apiClient под lazy {ApiClient(myApi)} Я не уверен, что это так работает, я должен попробовать это завтра. Как насчет создания забавы как: fun getServerUrl() {var serverUrl = binding.et1.text.toString() NetworkLayer.newUrl = serverUrl} и вызовите эту функцию сначала в onclicklistener: button.setOnClickListener { getServerUrl() viewModel.getServerInformation( headerValue) } Может ли это работать?

Alex Mutschl 20.12.2022 19:03

Я думаю, что есть лучшие способы реализовать сетевой уровень. Но вам будет легче работать над этим, если вы знаете, что у вас есть что-то функциональное. Поэтому сначала попробуйте ленивую идею. Тогда вы можете посмотреть developer.android.com/topic/architecture, чтобы узнать, как Google рекомендует. Обратите особое внимание на ссылки на примеры приложений в нижней части страницы.

Chris 20.12.2022 19:11

Я получаю сообщение об ошибке при попытке добавить lazy для apiClient. Я прочитаю статью еще раз (читал ее некоторое время назад), может быть, это поможет :-), поэтому способ использования MVVM с моделью просмотра-представления-репозитория я понимаю более или менее - и я знаю, как сделать f.e. запрос API и передача ответа на текстовое представление в пользовательском интерфейсе. Моя самая большая трудность - противоположное направление. Мне непонятно, как передать значение из пользовательского интерфейса в модель представления и т. д., чтобы использовать его в запросе или около того. Для второго значения, которое используется как часть заголовка в запросах, я смог сделать это с помощью параметров, начиная с интерфейса API.

Alex Mutschl 21.12.2022 13:17

@Chris Я опубликовал ответ о том, как решил проблему. Может быть, вы можете взглянуть на него, это нормально использовать его таким образом? Спасибо за вашу помощь!!! :-)

Alex Mutschl 22.12.2022 14:12
1
9
89
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Мне удалось это решить, единственное, что мне пришлось изменить, это: val url = binding.etServerUrl.text вместо val url = binding.etServerUrl.text.toString()

и при вызове функции при нажатии кнопки я добавил toString() к аргументу URL. Когда я пытаюсь добавить toString() к URL-адресу val, как я всегда делал до того, как он не работает, кто-нибудь может сказать мне, почему?

Вот пример того, как я его использую (я немного изменил клиент Retrofit на свою первую версию в вопросе). Итак, наконец, я могу продолжить свое приложение, так как я был заблокирован на несколько недель с этим.. :-)

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!!
    }
}

Я немного изменил модифицированный клиент, но это плохо Затем в репозиторий:

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
    }
}

Модель просмотра:

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)
        }
    }
}

И, наконец, 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

        }

    }
}

Другие вопросы по теме