I was not able to find some existing solution to my enigmatic issue. Here it is: I've got a volley request that populates some fields in my fragment. Sometimes, and here is the problem (it does not occur always), it throws a NullPointerException due to "String.length()" method. I can't find where the bug is.
Here is the error:
com.android.volley.VolleyError: java.lang.NullPointerException: Attempt to invoke virtual method "int java.lang.String.length()" on a null object reference.
Here is my volley request:
private void loadFormBody() {
StringRequest stringRequest = new StringRequest(Request.Method.POST, FORMBODY_PHP, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
try {
JSONArray jsonFormBody = new JSONArray(response);
for (int i = 0; i < jsonFormBody.length(); i++) {
JSONObject jsonObject1 = jsonFormBody.getJSONObject(i);
String mezzo = jsonObject1.getString("mezzo");
String casa_lavoro = jsonObject1.getString("casa_lavoro");
String lavoro_casa = jsonObject1.getString("lavoro_casa");
String rawData = jsonObject1.getString("timestamp");
String rawPunti = jsonObject1.getString("punti_passaggio");
int punti = Integer.parseInt(rawPunti);
if (casa_lavoro.equals("1") && lavoro_casa.equals("0")) {
tipoPassaggio = "Casa > Lavoro";
} else if (lavoro_casa.equals("1") && casa_lavoro.equals("0")) {
tipoPassaggio = "Lavoro > Casa";
}
try {
String[] date = rawData.split("-|:| ");
yearPassaggio = date[0];
monthPassaggio = date[1];
dayPassaggio = date[2];
hourPassaggio = date[3];
minutePassaggio = date[4];
secondPassaggio = date[5];
dataPassaggio = dayPassaggio + "/" + monthPassaggio + "/" + yearPassaggio;
} catch (ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
}
listTable.add(new ObjUserTable(mezzo, tipoPassaggio, dataPassaggio, punti));
}
adapterUserTable = new AdapterUserTable(getContext(), listTable);
lvUserTable.setAdapter(adapterUserTable);
} catch (JSONException e) {
Toast.makeText(getContext(), "Decodifica JSON Fallita: " + e.toString(), Toast.LENGTH_SHORT).show();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getContext(), "Popolamento FallitoB: " + error.toString(), Toast.LENGTH_LONG).show();
}
}) {
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("email", KEY_EMAIL);
return params;
}
};
SingletonVolley.getInstance(getActivity().getApplicationContext()).addToRequestQueue(stringRequest);
}
Here is logcat:
09-19 08:49:23.242 21225-21253/? E/Volley: [523] NetworkDispatcher.processRequest: Unhandled exception java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference
java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference
at java.net.URLEncoder.encode(URLEncoder.java:204)
at com.android.volley.Request.encodeParameters(Request.java:491)
at com.android.volley.Request.getBody(Request.java:477)
at com.android.volley.toolbox.HurlStack.addBodyIfExists(HurlStack.java:245)
at com.android.volley.toolbox.HurlStack.setConnectionParametersForRequest(HurlStack.java:219)
at com.android.volley.toolbox.HurlStack.executeRequest(HurlStack.java:97)
at com.android.volley.toolbox.BasicNetwork.performRequest(BasicNetwork.java:131)
at com.android.volley.NetworkDispatcher.processRequest(NetworkDispatcher.java:120)
at com.android.volley.NetworkDispatcher.run(NetworkDispatcher.java:87)
09-19 08:49:23.298 1882-1896/system_process E/memtrack: Couldn't load memtrack module
Bare in mind that if I go back to my main activity and then re-open the fragment, everything works fine. I thought it may be a server-delay issue, but how to sort it out?
Thank you everyone. So let me update:
About Response
this is my php code
<?php
require('connection.php');
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$email = $_POST['email'];
$sql = "SELECT mezzo, timestamp, casa_lavoro, lavoro_casa, punti_passaggio FROM passaggi WHERE email_userdata='$email'";
if ($stmt = mysqli_prepare($conn, $sql)) {
mysqli_stmt_execute($stmt);
$userstable = mysqli_stmt_get_result($stmt);
$json = mysqli_fetch_all($userstable, MYSQLI_ASSOC);
echo json_encode($json);
}
mysqli_stmt_free_result($stmt);
mysqli_stmt_close($stmt);
} else {
echo "Error";
}
mysqli_close($conn);
?>
this is my response
[{"mezzo":"Skate","timestamp":"2018-07-15 16:37:00","casa_lavoro":1,"lavoro_casa":0,"punti_passaggio":55},{"mezzo":"Bici","timestamp":"2018-07-20 10:14:03","casa_lavoro":0,"lavoro_casa":1,"punti_passaggio":50},{"mezzo":"Skate","timestamp":"2018-07-25 17:30:00","casa_lavoro":0,"lavoro_casa":1,"punti_passaggio":60},{"mezzo":"Carpooling","timestamp":"2018-09-12 22:38:34","casa_lavoro":1,"lavoro_casa":0,"punti_passaggio":20},{"mezzo":"A Piedi","timestamp":"2018-09-17 10:24:17","casa_lavoro":1,"lavoro_casa":0,"punti_passaggio":90},{"mezzo":"A Piedi","timestamp":"2018-09-17 10:24:36","casa_lavoro":0,"lavoro_casa":1,"punti_passaggio":90}]
Server-Side, everything works as expected.
About Debug
try {
DP JSONArray jsonFormHeader = new JSONArray(response);
for (int i = 0; i < jsonFormHeader.length(); i++) { ...
Setting debug point in the JSON conversion, I've noticed that debug won't start if the exception is thrown. Obviously this is not helping.
Also, I've tried to add this if statement as soon as onResponse method starts, but did not help too.
public void onResponse(String response) {
if (response != null && response.length() > 0) {
try {
JSONArray jsonFormHeader = new JSONArray(response);
for (int i = 0; i < jsonFormHeader.length(); i++) { ...
KEY_EMAIL
this is a String imported via SharedPreferences, it's fine, it's just an email address, it's always populated.
Volley Request
Requests are sent by singleton pattern
import android.content.Context;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.Volley;
public class SingletonVolley {
private static SingletonVolley mInstance;
private static Context mCtx;
private RequestQueue requestQueue;
private SingletonVolley(Context context) {
mCtx = context;
requestQueue = getRequestQueue();
}
public static synchronized SingletonVolley getInstance(Context context) {
if (mInstance == null) {
mInstance = new SingletonVolley(context);
}
return mInstance;
}
public RequestQueue getRequestQueue() {
if (requestQueue == null) {
requestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());
}
return requestQueue;
}
public void addToRequestQueue(Request request) {
getRequestQueue().add(request);
}
}
in request method: SingletonVolley.getInstance(getActivity().getApplicationContext()).addToRequestQueue(stringRequest);
and this is the php url
private static String FORMBODY_PHP = "http://towmyride.000webhostapp.com/php/form_body.php";
I guess it's not concerning about code itself like variables, but it has something to do with context. I'm calling this method in a fragment onViewCreated method, is it right?