问题
I need to read data from a internet server and display it in MainActivity via ListView. I've decided to use Volley lib to get data. After reading stackoverflow for hours I've achieved to extract data from JSONArray via Volley lib using callback. My code is follows
public class DownloadsManager
{
public interface VolleyCallback
{
void onSuccess(JSONArray result);
}
public static void getVolleyResponse(String url, Context ctx, final VolleyCallback callback)
{
RequestQueue requestQueue = Volley.newRequestQueue(ctx);
JsonArrayRequest request = new JsonArrayRequest(Request.Method.GET, url, null,
new Response.Listener<JSONArray>()
{
@Override
public void onResponse(JSONArray response)
{
callback.onSuccess(response);
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error)
{
// TODO
}
});
requestQueue.add(request);
}
}
Here I parse JSONArray into MyObject Java object
public class JSONParser
{
public static ArrayList <MyObject> parseJSONresponse (JSONArray response)
{
ArrayList<Object> list = new ArrayList<>();
try {
JSONArray array = response;
for (int i=0; i<array.length(); i++)
{
JSONObject object = array.getJSONObject(i);
MyObject obj = new Object();
//Object's string name
channel.setName(object.getString("name"));
list.add(channel);
}
} catch (Exception e)
{ e.printStackTrace();}
return list;
}
}
All above works and gives right value after checking with Debug
And in MainActivity happens some magic, what I don't understand. Please, pay attention to onSuccess(), where I parse JSONArray, assign value to ArrayList list, and create ArrayAdapter and ListView :
public class MainActivity extends AppCompatActivity
{
private static final String URL = "http://someurl/json";
private ListView listView;
private ArrayList <MyObject> list;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.mainlistview);
DownloadsManager.getVolleyResponse(URL, getApplicationContext(),
new DownloadsManager.VolleyCallback()
{
public void onSuccess(JSONArray result)
{
list.addAll(JSONParser.parseJSONresponse(result));
ArrayAdapter <String> adapter =
new ArrayAdapter <>(MainActivity.this, R.layout.channel_item_layout,list);
listView.setAdapter(adapter);
}
});
}
}
But when I try to use ArrayList list, it turn's out that list lost its value after leaving onSuccess():
Toast.makeText(this, list.get(0).getName(), Toast.LONG).show();
//output error, list.size() == 0, impossible to invoke list.get(0).getName()
ArrayList list after returning from onSuccess gives size() == 0, but inside onSuccess it works well.
QUESTION-1: I want to use ArrayList list's values in some next methods, how I can initialize value from onSuccess into ArrayList list and use this list further in my program?
QUESTION-2: Why it happens?
UPDATED: as Gabe Sechan point me about asynchronisation, how I can use Java synchronized keyword on JSONArray inside onSuccess() for to use values outside scopes of onSuccess()?
回答1:
Because Volley, like all network results, is asynchronous. It happens on another thread, at the same time as your program. It then runs the final callbacks (onSuccess or onFailure) on the main thread again. Your call to check the size of the list comes on the main thread, but it comes before Volley is finished (which will likely take a second or so for a small request, a few seconds for a big one). Since Volley isn't finished yet, the list is empty.
Your code would have been just fine for initializing the list. You just can't use it until Volley is ready. That means ALL of the code that requires the list to be filled must occur in onSuccess, or not be called until after onSuccess is.
来源:https://stackoverflow.com/questions/41651343/android-volley-how-to-synchronize-data-from-listener-onrespone-for-to-use-it-o