Я создаю приложение, в котором пользователь должен вставить 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 в разных запросах.
Или есть другой способ сделать это?
Надеюсь, есть кто-то, кто может мне помочь.
Привет, я попробовал приложение с эмулятором. Я вставил тот же URL-адрес в текст редактирования, который я использовал как жестко закодированный. Жестко запрограммировано, но при вставке в edittext нет. Вот почему я думаю, что значение edittext не было передано как baseurl. Спасибо за ссылку, со временем я смогу использовать @Url и добавлять запросы другим способом. Но я не уверен, что делать с заголовками. Не думал, что так сложно использовать текст редактирования в качестве переменной и передавать его в baseurl... :-)
Затем вы должны проверить значение, извлеченное из текста редактирования. Если вы используете kotlin, должно быть достаточно оператора `println` или, возможно, точки останова.
Отладка показывает мне "" , а не значение, которое я вставил в поле edittext. Таким образом, текст редактирования не «переносится» в переменную Networklayer. Любой намек, почему это не работает?
Возможно, apiClient
создается немедленно. И в этот момент URL-адрес представляет собой значение newUrl
, которое является пустой строкой. Может, тоже изменить apiClient
на лень?
О, это звучит понятно.. Вы имеете в виду val apiClient под lazy {ApiClient(myApi)} Я не уверен, что это так работает, я должен попробовать это завтра. Как насчет создания забавы как: fun getServerUrl() {var serverUrl = binding.et1.text.toString() NetworkLayer.newUrl = serverUrl} и вызовите эту функцию сначала в onclicklistener: button.setOnClickListener { getServerUrl() viewModel.getServerInformation( headerValue) } Может ли это работать?
Я думаю, что есть лучшие способы реализовать сетевой уровень. Но вам будет легче работать над этим, если вы знаете, что у вас есть что-то функциональное. Поэтому сначала попробуйте ленивую идею. Тогда вы можете посмотреть developer.android.com/topic/architecture, чтобы узнать, как Google рекомендует. Обратите особое внимание на ссылки на примеры приложений в нижней части страницы.
Я получаю сообщение об ошибке при попытке добавить lazy для apiClient. Я прочитаю статью еще раз (читал ее некоторое время назад), может быть, это поможет :-), поэтому способ использования MVVM с моделью просмотра-представления-репозитория я понимаю более или менее - и я знаю, как сделать f.e. запрос API и передача ответа на текстовое представление в пользовательском интерфейсе. Моя самая большая трудность - противоположное направление. Мне непонятно, как передать значение из пользовательского интерфейса в модель представления и т. д., чтобы использовать его в запросе или около того. Для второго значения, которое используется как часть заголовка в запросах, я смог сделать это с помощью параметров, начиная с интерфейса API.
@Chris Я опубликовал ответ о том, как решил проблему. Может быть, вы можете взглянуть на него, это нормально использовать его таким образом? Спасибо за вашу помощь!!! :-)
Мне удалось это решить, единственное, что мне пришлось изменить, это: 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
}
}
}
похоже, вы должны добавить
http://
илиhttps://
к значению, введенному пользователем. Хотя stackoverflow.com/questions/32559333/retrofit-2-dynamic-url может дать вам несколько альтернативных идей.