This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 5 years ago.
I'm trying to display data from mysql database with recycler-view ans card-view, but i'm facing this error message:
java.lang.NullPointerException: Attempt to invoke interface method
'int java.util.List.size()' on a null object reference
Everything seems to work properly because I'm able to display data retrieved on (Log) in my loop, and when I'm trying to add data on my List data_list, every thing is OK, because I'm able to know the number of lines returned by my data_list
Log.e("number of lines return", String.valueOf(data_list.size()));
But when i'm trying to reach the data_list on my Custom Adapter:
#Override
public int getItemCount() {
return my_data.size();
}
It warns me i can't access my_data because it's null.
The part of my code which retrieves data from my database:
private void load_data_from_server(final int id) {
//Log.e("iddddsss", String.valueOf(id));
AsyncTask<Integer,Void,Void> task =new AsyncTask<Integer, Void, Void>(){
#Override
protected Void doInBackground(Integer... integers) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://www.unhabitatrdcongo.org/Recycler-android-mySQL/index2.php?id="+id)
.build();
try {
Response response = client.newCall(request).execute();
JSONArray array = new JSONArray(response.body().string());
for (int i=0; i<array.length(); i++){
JSONObject object = array.getJSONObject(i);
Integer idd = object.getInt("id");
String des = object.getString("description").toString();
String im =object.getString("image").toString();
MyData data = new MyData(idd, des, im);
Log.e("errr", data.getDescription().toString());
data_list.add(data);
}
Log.e("number of lines read", String.valueOf(data_list.size()));
} catch (IOException e) {
e.printStackTrace();
Log.e("erreur IO EXCEPTION", e.toString());
} catch (JSONException e) {
System.out.print("End of content");
Log.e("erreur JSON",e.toString());
}
return null;
}
Generally, my_data has not been assigned yet while executing getItemCount (). This method is called in the adapter construct this.my_data = data_list;
Most likely the List<MyData> data_listthat the class is getting is null, and then, when this.my_data = data_list; you are doing this this.my_data = null;
Try to check that.
Related
I am doing an app where I synchronize my online DB to the offline DB everytime the user logs in. The table is dropped in offline, recreated then new rows gets added ( Its neccessary to drop it and add new instead of just checking and adding the rows that are not in the table already). I had about 200 rows in my online table and they are synchronised to my offline table relatively fast (in the background, then I tried 3000 and it was still processing. But When I generated 90 000 rows and tried to synchronize it to my offline DB it wouldnt move.
The log in onPreExecute() executed, but none of the logs in my doInBackground. json is not null.
For each retrieved row I am adding a row in offline.
Anyone know what could be the issue?
I tried adding LIMIT 200 in my PHP Scripts and still didnt do it, which was weird, cause when I had 200 rows it executed, but when I limit the output to 200 it does not.
Thank you for any answers, that would bring me closer to the solution.
public class SyncVykresToOffline {
String DataParseUrl = "/scriptsforandroidapplicationofflinemode/SyncVykresToOffline.php";
JSONObject json = null;
String str = "";
HttpResponse response;
DBHelper dbh;
private Context mContext;
public static boolean syncedvykres = false;
int k = 200;
public SyncVykresToOffline(Context context) {
mContext = context;
dbh = new DBHelper(mContext);
}
public class SyncVykres extends AsyncTask<Void, Void, Void>
{
public Context context;
public SyncVykres(Context context)
{
this.context = context;
}
#Override
protected void onPreExecute()
{
super.onPreExecute();
Log.i("Poradie_zacal","ano");
}
#Override
protected Void doInBackground(Void... arg0)
{
HttpClient myClient = new DefaultHttpClient();
HttpPost myConnection = new HttpPost(DataParseUrl);
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("limit", String.valueOf(k)));
try {
myConnection.setEntity(new UrlEncodedFormEntity(nameValuePairs));
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
try {
HttpResponse response = myClient.execute(myConnection);
} catch (IOException e1) {
e1.printStackTrace();
}
try {
response = myClient.execute(myConnection);
str = EntityUtils.toString(response.getEntity(), "UTF-8");
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
int i = 0;
try{
int vykres_version;
JSONArray jArray = new JSONArray(str);
json = jArray.getJSONObject(i);
Log.i("Poradie_json",String.valueOf(jArray.length()));
String
Nazov_vykresu;
int Version,
ID_vykres,
ID_stav,
ID_zakazka,
Poradie;
if(json == null) {
Log.i("Poradie","son is null");
}
while(json != null) {
Log.i("Poradie","been here");
ID_vykres = Integer.parseInt(json.getString("ID_vykres"));
vykres_version = dbh.getVykresVersion(ID_vykres);
Nazov_vykresu = json.getString("Nazov_vykresu");
ID_stav = Integer.parseInt(json.getString("ID_stav"));
ID_zakazka = Integer.parseInt(json.getString("ID_zakazka"));
Version = Integer.parseInt(json.getString("Version"));
Poradie = Integer.parseInt(json.getString("Poradie"));
Log.i("Poradie",json.getString("Poradie"));
dbh.SyncVykresToOffline(new technicky_vykres(ID_vykres,Nazov_vykresu,ID_stav,ID_zakazka,Version,Poradie));
i++;
json = jArray.getJSONObject(i);
}
} catch ( JSONException e) {
e.printStackTrace();
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
protected void onPostExecute(Void result)
{
syncedvykres = true;
}
}
}
Edit: added Logcat logs.
06-25 20:36:07.013 8278-8308/com.example.chris.normitapplication W/System.err: at org.json.JSON.typeMismatch(JSON.java:111)
at org.json.JSONArray.<init>(JSONArray.java:96)
at org.json.JSONArray.<init>(JSONArray.java:108)
at com.example.chris.normitapplication.offline.SyncVykresToOffline$SyncVykres.doInBackground(SyncVykresToOffline.java:102)
at com.example.chris.normitapplication.offline.SyncVykresToOffline$SyncVykres.doInBackground(SyncVykresToOffline.java:44)
at android.os.AsyncTask$2.call(AsyncTask.java:292)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
Edit 2: added PHP Script from where the JSON array is retrieved from:
<?php
include 'DatabaseConfig.php';
$conn = mysqli_connect($HostName,$HostUser,$HostPass,$DatabaseName);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
mysqli_set_charset($conn,"utf8");
$vykres = array();
$sql = "SELECT * FROM `technicky_vykres`";
$result = mysqli_query($conn, $sql) or die("Error in Selecting " . mysqli_error($conn));
while($row =mysqli_fetch_assoc($result))
{
$emparray[] = $row;
}
echo json_encode($emparray);
$conn->close();
?>
Issue identified when logging STR:
<html>
<head><title>502 Bad Gateway</title></head>
<body bgcolor="white">
<center><h1>502 Bad Gateway</h1></center>
<hr><center>openresty</center>
</body>
</html>
My hunch is, its the data that is breaking the loop and causing your program to end without going through the complete data set. I just added simple try/catch (see below) to printout any data objects, that we can't parse and but still continue to process the next row. Of course you'll need to have better error handling in place for production quality code.
while(json != null) {
try{
Log.i("Poradie","been here");
ID_vykres = Integer.parseInt(json.getString("ID_vykres"));
vykres_version = dbh.getVykresVersion(ID_vykres);
Nazov_vykresu = json.getString("Nazov_vykresu");
ID_stav = Integer.parseInt(json.getString("ID_stav"));
ID_zakazka = Integer.parseInt(json.getString("ID_zakazka"));
Version = Integer.parseInt(json.getString("Version"));
Poradie = Integer.parseInt(json.getString("Poradie"));
Log.i("Poradie",json.getString("Poradie"));
dbh.SyncVykresToOffline(new technicky_vykres(ID_vykres,Nazov_vykresu,ID_stav,ID_zakazka,Version,Poradie));
i++;
json = jArray.getJSONObject(i);
}catch(Exception e){
//Something wrong with the data? log it and see if you can find the culprit row/data....
Log.i("The faulty jason obj: " + json);
continue; //Move on the next one....
}
}
The error indicates that JSONArray believes your response is not formed as a Json Array.
Here's the code within JSONArray throwing your error:
public JSONArray(JSONTokener readFrom) throws JSONException {
/*
* Getting the parser to populate this could get tricky. Instead, just
* parse to temporary JSONArray and then steal the data from that.
*/
Object object = readFrom.nextValue();
if (object instanceof JSONArray) {
values = ((JSONArray) object).values;
} else {
throw JSON.typeMismatch(object, "JSONArray");
}
}
So the tokener does not recognize the object as a JSONArray. I would take a look at your raw response and see if adding a limit doesn't change the response to be an object with a result array inside of it (so that it can also include arguments to help web calls handle paging). Either way, there's something in the format of the response that the tokener does not recognize as being a Json array.
Upon realizing that the PHP script stopped working because too many rows & columns were retrieved instead of * I only Selected data that I truly needed (about 1/3 of all columns), then I added a where clause where ID would be above the number I sent from post and I keep repeating the script until finally the response is not "null".
Thank you for everyone who contributed to finding the solution.
I've got this code with fetches the "rate" data from an API, along with "rate", I need to get the "name". If I get "name" it often binds it below the "rate".
I need it to join on the same row of the List View, so it is like [Rate Name].
I need to get two objects of a JSON Array and bind it to the array adapter so I can display two objects in the same row of a List View so it is more user friendly.
The code below is of the AsyncTask, the code works fine but I need to add one more object and make sure it is displayed as one rate - one name and then iterating through the loop and adding more as needed in the same order.
public class AsyncTaskParseJson extends AsyncTask<String, String, String> {
// the url of the web service to call
String yourServiceUrl = "eg: URL";
#Override
protected void onPreExecute() {
}
String filename = "bitData";
#Override
protected String doInBackground(String... arg0) {
try {
// create new instance of the httpConnect class
httpConnect jParser = new httpConnect();
// get json string from service url
String json = jParser.getJSONFromUrl(yourServiceUrl);
// parse returned json string into json array
JSONArray jsonArray = new JSONArray(json);
// loop through json array and add each currency to item in arrayList
//Custom Loop Initialise
for (int i = 1; i < 8; i++) {
JSONObject json_message = jsonArray.getJSONObject(i);
// The second JSONObject which needs to be added
JSONObject json_name = jsonArray.getJSONObject(i);
if (json_message != null) {
//add each currency to ArrayList as an item
items.add(json_message.getString("rate"));
String bitData = json_message.getString("rate");
String writeData = bitData + ',' +'\n';
FileOutputStream outputStream;
File file = getFileStreamPath(filename);
// first check if file exists, if not create it
if (file == null || !file.exists()) {
try {
outputStream = openFileOutput(filename, MODE_PRIVATE);
outputStream.write(writeData.getBytes());
outputStream.write("\r\n".getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
// if file already exists then append bit data to it
else if (file.exists()) {
try {
outputStream = openFileOutput(filename, Context.MODE_APPEND);
outputStream.write(writeData.getBytes());
outputStream.write("\r\n".getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
// below method will run when service HTTP request is complete, will then bind text in arrayList to ListView
#Override
protected void onPostExecute(String strFromDoInBg) {
ListView list = (ListView) findViewById(R.id.rateView);
ArrayAdapter<String> rateArrayAdapter = new ArrayAdapter<String>(BitRates.this, android.R.layout.simple_expandable_list_item_1, items);
list.setAdapter(rateArrayAdapter);
}
}
Just Create Custom Class Messsage:
public class Item{
private String name;
private String rate;
public void Message(String n, String r){
this.name=n;
this.rate=r;
}
// create here getter and setter
}
Now in your background, you have to add name and rate in Message class
Public class MainAcitity extends Activity{
public static List<Item> items= new ArrayList<>();// define in inside the class
// this has to be down on background
Item i=new Item(json_message.getString("name"),json_message.getString("rate"));
items.add(i);
Now pass this listmessge onPostExecute :
ListView list = (ListView) findViewById(R.id.rateView);
ArrayAdapter<String> rateArrayAdapter = new ArrayAdapter<String>(BitRates.this, android.R.layout.simple_expandable_list_item_1, items);
list.setAdapter(rateArrayAdapter);
Is that any helpful for you.
Follow this link.You will get my point.
https://devtut.wordpress.com/2011/06/09/custom-arrayadapter-for-a-listview-android/
I have recently been setting up mobile apps to work with my meteor server. As a part of this I have to pass the meteor web app data from android. Unfortunately I have been receiving a error that tells me that the java object I am passing "would be serialized to null". How do I prevent this?
JSONObject json = new JSONObject();
try{
json.put("Foo", "1");
json.put("Blah", 0);
}catch (JSONException e){
}
Object[] object = new Object[1];
object[0] = json;
System.out.println(object + ", " + object[0] + ", " + object[0].toString());
mMeteor.call("xxx", object, new ResultListener() {
#Override
public void onSuccess(String result) {
}
#Override
public void onError(String error, String reason, String details) {
}
});
}
#Override
public void onError(String error, String reason, String details) {
}
});
Android/Meteor interface Library function
public void callWithSeed(final String methodName, final String randomSeed, final Object[] params, final ResultListener listener) {
// create a new unique ID for this request
final String callId = uniqueID();
// save a reference to the listener to be executed later
if (listener != null) {
mListeners.put(callId, listener);
}
// send the request
final Map<String, Object> data = new HashMap<String, Object>();
data.put(Protocol.Field.MESSAGE, Protocol.Message.METHOD);
data.put(Protocol.Field.METHOD, methodName);
data.put(Protocol.Field.ID, callId);
if (params != null) {
data.put(Protocol.Field.PARAMS, params);
}
if (randomSeed != null) {
data.put(Protocol.Field.RANDOM_SEED, randomSeed);
}
send(data);
}
I was having this same issue, my first error was passing a CharSequence instead a String as a parameter (your Object[]), and my other error was passing an Object[] as another parameter (I solved this by sending a String instead, like : String.valueOf(your_object_list)) Dont forget to handle this on your server side, you will receive a String instead of an Object.
Convert the JSONArray to List & JSONObject to HashMap and then pass those instead of the raw JSONObject or JSONArray.
You can write a recursive function for the conversion in case of nested JSONObject and JSONArray or can use GSON library for the conversion.
For more details about the conversion, this SO post may be helpful.
I'm using Volley however I'm having some problems with the JSON parsed data most likely because volley doesn't implement something like AsyncTask's onPostExecute() and I'm getting some duplicated data on wrong list items.
Then I came across this: https://github.com/yakivmospan/volley-request-manager#custom-listener-implementation-
Has anyone use it? How can I add it to my current Volley code?
More details about my problem here Volley not sending correct data. How to implement an alternative to onPostExecute()?
UPDATE
As requested, some code. Here's a button that calls a method on another class that uses Volley to request some raw JSON data (NovaJSON) and then send the JSON to a parser class (NovaParser):
info.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String instanceDetail = NovaJSON.shared().receiveDetail(getId());
Dialog dialog = new Dialog(v.getContext());
dialog.setContentView(R.layout.instances_info);
TextView image = (TextView) dialog.findViewById(R.id.imageInstance);
TextView flavor = (TextView) dialog.findViewById(R.id.flavorInstance);
dialog.setTitle(name.getText() + " Details");
if (instanceDetail != null) {
image.setText(" \u2022 image : " + NovaParser.shared().parseImages(instanceDetail));
flavor.setText(" \u2022 flavor : " + NovaParser.shared().parseFlavor(instanceDetail));
}
dialog.show();
}
});
This is the method that does the Volley request on the NovaJSON class:
public void getJSONdetail() {
final String authToken = getAuth();
String novaURL = getNova();
novaURL = novaURL+"/servers/"+id;
JsonObjectRequest getRequest = new JsonObjectRequest(Request.Method.GET, novaURL, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.d("Nova on Response", response.toString());
setNovaJSONdetail(response.toString());
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d("Nova on Error", "Error: " + error.getMessage());
setNovaJSONdetail(error.toString());
}
}
) {
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("X-Auth-Token", authToken);
params.put("User-Agent", "stackerz");
params.put("Accept", "application/json");
params.put("Content-Type", "application/json; charset=utf-8");
return params;
}
};
queue = VolleySingleton.getInstance(this).getRequestQueue();
queue.add(getRequest);
}
It then sends the JSON from the server as a string to be parsed using the following methods:
public static String parseImages(String imagesDetail){
ArrayList<HashMap<String, String>> imagesList = NovaParser.shared().getImagesList();
String temp = null;
JSONObject novaDetail = null;
try {
novaDetail = new JSONObject(imagesDetail);
JSONObject server = novaDetail.getJSONObject("server");
JSONObject image = server.getJSONObject("image");
if (imagesList !=null){
temp = image.getString("id");
for (Map<String,String> map : imagesList) {
if (map.containsValue(temp)) {
temp = map.get(NAME);
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
return temp;
}
public static String parseFlavor(String instanceDetail){
ArrayList<HashMap<String, String>> flavorList = NovaParser.shared().getFlavorList();
String temp = null;
JSONObject novaDetail = null;
try {
novaDetail = new JSONObject(instanceDetail);
JSONObject server = novaDetail.getJSONObject("server");
JSONObject flavor = server.getJSONObject("flavor");
if (flavorList !=null){
temp = flavor.getString("id");
for (Map<String,String> map : flavorList) {
if (map.containsValue(temp)) {
temp = map.get(NAME);
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
return temp;
}
When I press the button once the dialog is displayed with empty values. When I press it the second time I get the correct parsed data. Basically first time I click the button the instanceDetail string is null because Volley didn't finish doing its thing then I click the 2nd time it loads the values accordingly because it finally finished the 1st request.
I understand Volley is asynchronous, the requests happen in parallel and the responses sometimes are not immediate however I need some sort of progress bar or spinning wheel to give the user some feedback that the app is waiting for data. It could be done with AsyncTask however it doesn't seem to be possible with Volley.
I think your problem is not because of Volley.
Check the parameters you send and receive.
However if you need onPostExcecute you have Volley's callback:
Response.Listener<JSONObject> and Response.ErrorListener() which are called after the request.
About Volley request manager just switch all your volley calls with appropriate Volley request manager calls
I solved my problem by dumping Volley altogether and moving to Retrofit. I setup all the calls to be sync/blocking, worked out the exceptions/errors using try/catches and setup a short timeout on the OkHTTP client. Now it's working as I wanted.
I'm Trying to save data from Json into SQLite. For now I keep the data from Json into HashMap.
I already search it, and there's said use the ContentValues. But I still don't get it how to use it.
I try looking at this question save data to SQLite from json object using Hashmap in Android, but it doesn't help a lot.
Is there any option that I can use to save the data from HashMap into SQLite?
Here's My code.
MainHellobali.java
// Hashmap for ListView
ArrayList<HashMap<String, String>> all_itemList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_helloballi);
all_itemList = new ArrayList<HashMap<String, String>>();
// Calling async task to get json
new getAllItem().execute();
}
private class getAllItem extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... arg0) {
// Creating service handler class instance
ServiceHandler sh = new ServiceHandler();
// Making a request to url and getting response
String jsonStr = sh.makeServiceCall(url, ServiceHandler.GET);
Log.d("Response: ", "> " + jsonStr);
if (jsonStr != null) {
try {
all_item = new JSONArray(jsonStr);
// looping through All Contacts
for (int i = 0; i < all_item.length(); i++) {
JSONObject c = all_item.getJSONObject(i);
String item_id = c.getString(TAG_ITEM_ID);
String category_name = c.getString(TAG_CATEGORY_NAME);
String item_name = c.getString(TAG_ITEM_NAME);
// tmp hashmap for single contact
HashMap<String, String> allItem = new HashMap<String, String>();
// adding each child node to HashMap key => value
allItem.put(TAG_ITEM_ID, item_id);
allItem.put(TAG_CATEGORY_NAME, category_name);
allItem.put(TAG_ITEM_NAME, item_name);
// adding contact to contact list
all_itemList.add(allItem);
}
} catch (JSONException e) {
e.printStackTrace();
}
} else {
Log.e("ServiceHandler", "Couldn't get any data from the url");
}
return null;
}
}
I have DatabasehHandler.java and AllItem.java too.
I can put it in here if its necessary.
Thanks before
** Add Edited Code **
// looping through All Contacts
for (int i = 0; i < all_item.length(); i++) {
JSONObject c = all_item.getJSONObject(i);
String item_id = c.getString(TAG_ITEM_ID);
String category_name = c.getString(TAG_CATEGORY_NAME);
String item_name = c.getString(TAG_ITEM_NAME);
DatabaseHandler databaseHandler = new DatabaseHandler(this); //error here "The Constructor DatabaseHandler(MainHellobali.getAllItem) is undefined
}
As mentioned by #birdy you can just store the JSON data as String inside your database.
In my case I've already done the same thing you are trying to achieve, in my case I've just created an abstract datasource that will be extended for any JSON object I will set in my database.
But basically you just need a method to convert a JSONObject to a ContentValues object.
public ContentValues jsonToContentValues(JSONObject json) {
ContentValues values = new ContentValues();
values.put("MY_COLUMN", json.optString("MY_JSON_VALUE"));
return values;
}
After you have your content value object all set you just need to insert the values on your database.
return database.insert("MY_TABLE_NAME", null, contentValues);
If what you need is to store JSON data - just store it as a text. Than after taking it back from database you can again parse it into map.