Making a simple request to the server giving me different response data. Volley and HttpURLConnection is giving me same response which I expected, however, when I request using retrofit its giving me totally different data.
Please bear in mind that it happens only when I use our WIFI and only in Mobile application. When I use browser and make same request I get expected data.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val alarmManger = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(this, AlarmReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0)
alarmManger.setRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime(),
60 * 1000, pendingIntent)
Thread {
var conn = URL("$BASE_URL/home").openConnection() as HttpURLConnection
var inputStream = conn.inputStream
val br = BufferedReader(InputStreamReader(inputStream))
var sB = StringBuilder()
var line = br.readLine();
if (line != null) {
sB.append(line)
}
print(sB.toString())
}.start()
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.build()
val service = retrofit.create(GitHubService::class.java)
service.listRepos().enqueue(object : Callback<ResponseBody> {
override fun onFailure(call: Call<ResponseBody>?, t: Throwable?) {
println(t)
}
override fun onResponse(call: Call<ResponseBody>?, response: Response<ResponseBody>?) {
println(response?.body())
}
})
val queue = Volley.newRequestQueue(this)
val stringRequest = StringRequest(Request.Method.GET, BASE_URL + "/home",
com.android.volley.Response.Listener<String> { response ->
println(response)
},
com.android.volley.Response.ErrorListener { })
queue.add(stringRequest)
}
}
val BASE_URL = "myserviceurl";
interface GitHubService {
#GET("home")
fun listRepos(): Call<ResponseBody>
}
Related
I want to make a POST request but using data class like json (request body) but is not working... (bad request 400 error). This is my code................
It seems that the connection is good but the parameters go wrong in the body
data class Login(val correo:String="",val password:String="",val nombre:String="",val apellido:String="",val direccion:String="",val telefono:String="")
interface Service {
#POST("api/Auth/SignIn")
suspend fun post(#Body request: Login): Response<Login>
}
object Server {
private const val URL = "xxxxxxxxxurl/"
private fun getRetrofit():Retrofit{
return Retrofit.Builder()
.baseUrl(URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
suspend fun postreq(){
val request = Login( correo = "kotlin#sfa.com", password = "12345", nombre ="kotlin" , apellido = "cr" , direccion ="heredia" , telefono = "888888" )
val retrofit= getRetrofit().create(Service::class.java)
val call = retrofit.post(request)
//Log.d("correo body",call.body()!!.correo)
//Log.d("password body",call.body()!!.password)
if(call.isSuccessful){
val body = call.body()!!
// Log.d("body",body.correo)
}else{
Log.d("ERROR","ERROR")
//Log.d("correo body",call.body()!!.correo)
//Log.d("password body",call.body()!!.password)
throw Exception(call.errorBody()?.charStream()?.readText())
}
}
}
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
CoroutineScope(Dispatchers.Main).launch {
val res = Server.postreq()
Log.d("cor", "Thread is ${Thread.currentThread().name}")
}
setContent {
MyApplicationTheme {
Greeting()
}
}
}
}
I'm making cryptocurrency information viewer using Retrofit. Everything is okay, but have a problem.
One exchange demands me execute retrofit twice.
https://api.upbit.com/v1/market/all
https://api.upbit.com/v1/ticker?markets=KRW-BTC,KRW-ETH,KRW-BTG,KRW-BSV,KRW-ETC ..., KRW-(Some cryptocurrency)
Base url is "https://api.upbit.com/v1/". And I have to get 'markets' from first api, and get cryptocurrency's information by using 'markets' as query value.
But there are problem. I thought first and second execution. Get markets from first execution, and get infomations by using markets. But Retrofit basically runs asynchronously, So usually skip first execution and there are no markets in second executions. (markets = "")
How can I run Retrofit in Retrofit? Did I approach wrong? Or there are solution for this problem?
This is Retrofit parts in my code.
var markets = ""
val publishSubject: PublishSubject<String> = PublishSubject.create()
init {
publishSubject.subscribe {
markets = it
}
}
fun getData(exchange: String) {
// var markets = "Basic"
val url = when(exchange) {
coinone -> "https://api.coinone.co.kr/"
bithumb -> "https://api.bithumb.com/"
upbit -> {
getMarketsUpbit()
"https://api.upbit.com/v1/"
}
else -> "https://api-cloud.huobi.co.kr/"
}
val parser = DataParser()
val builder = Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(RetrofitService::class.java)
val call: retrofit2.Call<Any> =
when (exchange) {
coinone ->
builder.getTickersCoinone("all")
bithumb ->
builder.getTickersBithumb()
upbit ->
builder.getTickersUpbit(markets)
else ->
builder.getTickersHuobi()
}
call.enqueue(object : retrofit2.Callback<Any> {
override fun onResponse(call: retrofit2.Call<Any>, response: retrofit2.Response<Any>) {
coinInfos.value = parser.getParsedData(
if (exchange != "upbit") exchange
else markets
,
response.body().toString()
)
}
override fun onFailure(call: retrofit2.Call<Any>, t: Throwable) {
println("Retrofit process is failed.")
}
})
}
private fun getMarketsUpbit() {
val parser = DataParser()
var markets = ""
val builder = Retrofit.Builder()
.baseUrl("https://api.upbit.com/v1/")
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(RetrofitService::class.java)
val call: retrofit2.Call<Any> = builder.getMarketsUpbit()
call.enqueue(object : retrofit2.Callback<Any> {
override fun onResponse(call: retrofit2.Call<Any>, response: retrofit2.Response<Any>) {
publishSubject.onNext(parser.parseUpbitMarkets(response.body().toString()))
}
override fun onFailure(call: retrofit2.Call<Any>, t: Throwable) {
println("Retrofit process is failed.")
}
})
}
I am trying to call an API using Retrofit in an Android application using Kotlin. The API requires a
a header and body similar to the following sample input:
Sample Input
Header:
loginName: 65848614-6697-4cf7-a64a-e0b9374c4aee
Body:
clientId: DKOKTrykIQ987yQcLNehT8SWJRMyQLdP
secret: 6Jt1ENlDn9gxPu5f
The content type has to be passed as application/x-www-form-urlencoded.
Currently, I am using the following classes:
YodleeService.kt
interface YodleeService {
#Headers(
"loginName: de5559cc-5375-4aca-8224-990343774c08_ADMIN",
"Api-Version: 1.1",
"Content-Type: application/x-www-form-urlencoded"
)
#POST("auth/token")
fun generateLoginToken(
#Body postBody: PostBody
) : Call<LoginToken>
}
AccountRetriever.kt
class AccountRetriever {
private val service: YodleeService
companion object {
const val BASE_URL = "https://sandbox.api.yodlee.com:443/ysl/"
}
init {
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
service = retrofit.create(YodleeService::class.java)
}
fun login(callback: Callback<LoginToken>) {
val postBody = PostBody("TG86ljAk6lt28GYZlRTQWssaLmGpS6jV", "A2P9ZPEqB4uos1nv")
val call = service.generateLoginToken(postBody)
call.enqueue(callback)
}
}
PostBody
data class PostBody(
val clientId: String?,
val secret: String?
)
MainActivity
class MainActivity : AppCompatActivity() {
private val accountRetriever = AccountRetriever()
private val loginCallback = object : Callback<LoginToken> {
override fun onFailure(call: Call<LoginToken>, t: Throwable) {
Log.e("MainActivity", "Problem calling Yodlee API {${t.message}")
}
override fun onResponse(call: Call<LoginToken>?, response: Response<LoginToken>?) {
response?.isSuccessful.let {
Log.i("MainActivity", "errorBody - Content = ${response?.raw()}")
val loginToken = LoginToken(
response?.body()?.accessToken ?: "",
response?.body()?.expiresIn ?: "",
response?.body()?.issuedAt ?: "")
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
accountsList.layoutManager = LinearLayoutManager(this)
if (isNetworkConnected()) {
accountRetriever.login(loginCallback)
} else {
AlertDialog.Builder(this).setTitle("No Internet Connection")
.setMessage("Please check your internet connection and try again")
.setPositiveButton(android.R.string.ok) { _, _ -> }
.setIcon(android.R.drawable.ic_dialog_alert).show()
}
}
private fun isNetworkConnected(): Boolean {
val connectivityManager =
getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val activeNetwork = connectivityManager.activeNetwork
val networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork)
return networkCapabilities != null &&
networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
}
}
When I debug my application, I am getting a response of [size=213 text=\n {\n "errorCode": "Y303",\n …]. The documentation for the API says that this error code means the clientId or secret is missing.
When I dig through the debugger, I am seeing that the raw call reads as
Request {
method = POST, url = https: //sandbox.api.yodlee.com/ysl/auth/token,
tags = {
class retrofit2.Invocation =
com.example.budgettracker.api.YodleeService.generateLoginToken()[PostBody(
clientId = TG86ljAk6lt28GYZlRTQWssaLmGpS6jV, secret = A2P9ZPEqB4uos1nv)]
}
}
I cannot determine why the API is not seeing the POST body contents.
Any help would be greatly appreciated.
I need to send the first POST request to the server, insert the received response into the second POST request and send it back to the server. How can I implement this with RxJava? At the moment, everything works, but the second question does not have time to get an answer from the first request and the imageMediaId field is sent empty.
My function:
fun uploadNewImageAndContact(toPath: String?, newContactApi: ContactsApi) {
val file = File(toPath)
val fileReqBody: RequestBody = file.asRequestBody("image/*".toMediaTypeOrNull())
val part: MultipartBody.Part =
MultipartBody.Part.createFormData("upload", file.name, fileReqBody)
// First Request
imagesService.postImage(part).enqueue(object : Callback<ResponseBody> {
override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
}
override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
if (response.code() == 201) {
// Get Image response Id
val gson = Gson()
val imageResponse =
gson.fromJson(response.body()?.string(), ImageResponse::class.java)
imageMediaId = imageResponse.ids[0]
// Second Request
contactsService.postNewContact(newContactApi)
.enqueue(object : Callback<ContactsApi> {
override fun onFailure(call: Call<ContactsApi>, t: Throwable) {
}
override fun onResponse(call: Call<ContactsApi>, response: Response<ContactsApi>) {
}
})
}
}
})
}
My ViewModel function:
val newContactsApi = ContactsApi(id = "", firstName = mFirstName, lastName = mLastName, phone = mPhone,
email = mEmail, notes = mNotes, images = "https://mydb.site.io/media/${apiRepository.imageMediaId}")
apiRepository.uploadNewImageAndContact(toPath, newContactsApi)
I'm new in Kotlin.
I have a problem, with "The application may be doing too much work on its main thread".
I have 2 different activity. The principal I use for login, the second for send a get http and receive a json object.
Where is my problem? I wrong to use 2 different activity o the problem is asyncdo? I am in deep sea.
class GitActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.git_activity)
Recycle_view.layoutManager = LinearLayoutManager(this)
Recycle_view.adapter = MainAdapter()
var url = intent.getStringExtra("URL")
doAsync {
fetchJson(url)
uiThread { longToast("Request performed") }
}
}
fun fetchJson(url: String) : List<NameFileList> {
var request = Request.Builder().url(url).build()
val client = OkHttpClient()
client.newCall(request).enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
print("sono qui")
print(url)
val body = response?.body()?.string()
print(body)
}
override fun onFailure(call: Call, e: IOException) {
print("Error Failure")
}
})
}
and my Main Class
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
SearchButton.setOnClickListener {
verifyNetwork()
}
}
private fun getUsername(): String {
val username = Username_editText.text.toString()
Log.d("MainActivity", "UserName is + $username")
return username
}
private fun getRepositoryName(): String {
val nameRepository = RepositoryName_editText.text.toString()
Log.d("MainActivity", "UserName is + $nameRepository")
return nameRepository
}
private fun verifyNetwork()
{
if(isConnected(this)){
val url = CreateUrl().createUrl(getUsername(), getRepositoryName())
print(url)
var intent = Intent(this, GitActivity::class.java)
intent.putExtra("URL", url)
startActivity(intent)
}
else {
//POPUP DI ERRORE NETWORK
}
}
private fun isConnected(context: Context): Boolean {
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val activeNetwork = cm.activeNetworkInfo
return activeNetwork != null && activeNetwork.isConnectedOrConnecting
}
}
Are your icons / resources appropriately sized for a mobile application? If your assets are too large, inflation could take over the main thread.
You'd better to use Retrofit + Rxjava for handling Network call.
Retrofit :
https://square.github.io/retrofit/
RxJava :
https://github.com/ReactiveX/RxJava
You can also refer this link for check example: How to get the response URL from Retrofit?