Andre Roque Andre Roque - 1 month ago 9
Java Question

Android Update View after JSONRequest success

I'm building an Android app (I'm using Kotlin not JAVA, but if you can get me the Java approach is fine) that's supposed to show the weather information using the OpenWeather API. I already set the view:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/activity_horizontal_margin">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/layCity">
<TextView
android:id="@+id/txtCity"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="PORTO"
android:textSize="25sp"
android:textStyle="bold"/>
<TextView
android:id="@+id/txtCountry"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="(PT)"
android:textSize="25sp"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/layTempDetail"
android:layout_below="@+id/layCity"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/txtCurTemp"
android:text="20º"
android:textSize="40sp"
android:textStyle="bold"
android:layout_marginTop="20dp"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/lblMinTemp"
android:text="Min:"
android:textStyle="bold"
android:textSize="20sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/txtMinTemp"
android:text="10º"
android:textSize="20sp"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/lblMaxTemp"
android:text="Max:"
android:textStyle="bold"
android:textSize="20sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/txtMaxTemp"
android:text="30º"
android:textSize="20sp"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/lblPressure"
android:text="Pressure:"
android:textStyle="bold"
android:textSize="20sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/txtPressure"
android:text="100"
android:textSize="20sp"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/lblHumidity"
android:text="Humidity:"
android:textStyle="bold"
android:textSize="20sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/txtHumidity"
android:text="30%"
android:textSize="20sp"/>
</LinearLayout>
</LinearLayout>
</RelativeLayout>


Then I have another class responsible to make the request and change each field individually like this:

public fun getCityInfo(name: String){
val URI = String.format("http://api.openweathermap.org/data/2.5/weather?q=%s&appid=", name)
Log.d("uri", URI)
var cityName: String = ""
queue.add(JsonObjectRequest(
URI,
null,
{

cityName = it.getString("name")
var main = it.getJSONObject("main")
var temp: Double = main.getDouble("temp")
//getting the rest of the info


//I save the info that I need in a class

var currTemp = CurrentTemperature(temp,press,humidity,min,max,state,desc,icon)
var city = City(name, currTemp)


//then set each field individually
var detailsview = (context as AppCompatActivity).findViewById(R.id.layDetails) as View

(detailsview.findViewById(R.id.txtCity) as TextView).setText(city.name)
(detailsview.findViewById(R.id.txtCurTemp) as TextView).setText(city.currTemp.curr.toString())
},
{
Toast.makeText(context, "Failed to get weather", Toast.LENGTH_LONG).show()
}


But what I wanted is to return the city instance on success, then I have some kind of bind in my fields that automatically update the view.

How can I achieve that?

Answer

Don't know Kotlin at all, but I'll try to explain enough using Java terms.

Redefine your method to accept the Volley listener as a callback to the Activity.

public fun getCityInfo(name: String, callback: Response.Listener<JSONObject>)

Then, you call that function, passing in this closure as that callback

getCityInfo("Chicago", 
{
    var cityName = it.getString("name")
    var main = it.getJSONObject("main")
    var temp: Double = main.getDouble("temp")
    //getting the rest of the info

    var currTemp = CurrentTemperature(temp,press,humidity,min,max,state,desc,icon)
    var city = City(name, currTemp)

    setCity(city) // TODO: implement method within Activity 
}) 

Notice a added setCity. You'll need to implement that to update whatever views you have.

Now, in that other class, simply pass along the response listener from the Activity

queue.add(JsonObjectRequest(
            URI,
            null, 
            callback, 
            { ... } // error handle 
Comments