问题
I'm developing an android app that reads data from API then show these data in multi-choice dialog. However, when I click the button the dialog is empty. I think that maybe the program executes the next lines of code before volley returns the response. I searched a lot but I didn't understand how to fix this, I'm a beginner in using Volley.
Here is the dialog code where I get the data from API:
public class LevelsDialog extends DialogFragment {
ArrayList<String> list = new ArrayList<>();
static String[] array;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
array = getLevels();
final boolean[] checkedItems = new boolean[array.length];
builder.setTitle("Select Levels").setMultiChoiceItems(array, checkedItems, new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
if(isChecked) {
list.add(array[which]);
checkedItems[which] =true;
} else if(list.contains(array[which])) {
list.remove(array[which]);
checkedItems[which] = false;
}
}
}).setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
for(int i=0 ; i<list.size(); i++)
Log.e("After", "onClick: "+ list.get(i) );
}
});
return builder.create();
}
public String[] getLevels() {
final ArrayList<String> LevelsList = new ArrayList<>();
String url = Connection.URL + "/getAllLevels";
JsonArrayRequest objectRequest = new JsonArrayRequest(
Request.Method.GET,
url,
null,
new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray response) {
if (response.length() != 0) {
int length = response.length();
for (int i = 0; i < length; i++) {
try {
LevelsList.add(response.get(i).toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("Rest Response Error ", error.toString());
}
});
Connection.getConnection(getActivity()).addToRequestQueue(objectRequest);
String[] Levels = LevelsList.toArray(new String[LevelsList.size()]);
return Levels;
}
}
Any idea? Thanks.
回答1:
You need to wait for the data to be received from your volley request and then allow the users to hit the multi-choice dialog.
I would like to suggest keeping a ProgressDialog in your case, which will be shown until the level data is received. Hence, your onCreateDialog will be looking something like this.
private ProgressDialog pD;
private final boolean[] checkedItems;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
pD = new ProgressDialog(context);
pD.setMessage("Getting the levels information");
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Select Levels").setMultiChoiceItems(array, checkedItems, new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
if(isChecked) {
list.add(array[which]);
checkedItems[which] =true;
} else if(list.contains(array[which])) {
list.remove(array[which]);
checkedItems[which] = false;
}
}
}).setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
for(int i=0 ; i<list.size(); i++)
Log.e("After", "onClick: "+ list.get(i) );
}
});
getLevels();
pD.show(); // Start showing the progress dialog
return builder.create();
}
Now modify your getLevels function like this.
public void getLevels() {
final ArrayList<String> LevelsList = new ArrayList<>();
String url = Connection.URL + "/getAllLevels";
JsonArrayRequest objectRequest = new JsonArrayRequest(
Request.Method.GET, url, null, new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray response) {
if (response.length() != 0) {
int length = response.length();
array = new int[length]; // Re-initialize the array
for (int i = 0; i < length; i++) {
try {
array[i] = response.get(i).toString();
} catch (JSONException e) {
e.printStackTrace();
}
}
pD.cancel();
checkedItems = new boolean[array.length];
}
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("Rest Response Error ", error.toString());
}
});
Connection.getConnection(getActivity()).addToRequestQueue(objectRequest);
}
Hope that helps.
回答2:
The method public String[] getLevels() cannot return instantly the array, because you are doing a request to the internet (and this takes time), so, you need to use a callback interface, when the volley complete the request, it will call it back and only in this time you will write in the screen
The generic callback:
public interface ICallback<T> {
void onSucess(T result);
void onError(int code);
}
The method getLevels will be void, and with a callback parameter
public void getLevels(final ICallback<String[]> callback) {
String url = Connection.URL + "/getAllLevels";
JsonArrayRequest objectRequest = new JsonArrayRequest(
Request.Method.GET,
url,
null,
new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray response) {
final ArrayList<String> LevelsList = new ArrayList<>();
if (response.length() != 0) {
int length = response.length();
for (int i = 0; i < length; i++) {
try {
LevelsList.add(response.get(i).toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
}
String[] Levels = LevelsList.toArray(
new String[LevelsList.size()]);
callback.onSucess(Levels); //<-------- CALL IT BACK
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("Rest Response Error ", error.toString());
int code = -1;
if(error!=null){
if(error.networkResponse!=null){
code = error.networkResponse.statusCode;
}
}
callback.onError(code); // <-- ERROR
}
});
Connection.getConnection(getActivity()).addToRequestQueue(objectRequest);
}
So, you will have the levels only in the callback:
getLevels(
new ICallback<String[]>(){
@Override
public void onSucess(String[] result) {
// Create or update the dialog here...
}
@Override
public void onError(int errorCode) {
//error treatment...
}
}
);
来源:https://stackoverflow.com/questions/49079389/how-to-wait-for-volley-response-end-before-executing-next-lines