Error occuring on some Android devices involving GSON - android

The problem appears to happen only on Samsung devices. However it did happen on one non Samsung device. I've been trying to replicate the issue on my phone (Nexus 5, vanilla lollipop) but it doesn't happen.
This saves an ArrayList of an ArrayList of an ArrayList of BusEntrys
private static void saveDataList(ArrayList<ArrayList<ArrayList<BusEntry>>> list, String key1){
SharedPreferences appSharedPrefs = PreferenceManager
.getDefaultSharedPreferences(RO.mainActivity.getApplicationContext());
SharedPreferences.Editor prefsEditor = appSharedPrefs.edit();
ArrayList<ArrayList<ArrayList<BusEntry>>> entries = list;
Gson gson = new Gson();
String jsonEntries = gson.toJson(entries);
//Log.d("TAG", "jsonCars = " + jsonEntries);
prefsEditor.putString(key1, jsonEntries);
prefsEditor.commit();
}
This loads an ArrayList of an ArrayList of an ArrayList of BusEntrys
private static Object getDataList(String key, int task){
SharedPreferences appSharedPrefs = PreferenceManager
.getDefaultSharedPreferences(RO.mainActivity.getApplicationContext());
String jsonString = appSharedPrefs.getString(key, ""); // TODO use empty string as an if statement to determine if you need to recache
Type type;
type = new TypeToken<ArrayList<ArrayList<ArrayList<BusEntry>>>>(){}.getType();
Gson gson = new Gson();
return gson.fromJson(jsonString, type);
}
Error Stack
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.joltimate.umdshuttle/com.joltimate.umdshuttle.MainActivity}: com.google.a.aa: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was NUMBER at line 1 column 7 path $[0].b
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3119)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3218)
at android.app.ActivityThread.access$1000(ActivityThread.java:198)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1676)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:6837)
at java.lang.reflect.Method.invoke(Method.java)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)
Caused by: com.google.a.aa: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was NUMBER at line 1 column 7 path $[0].b
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read()
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write()
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read()
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read()
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read()
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read()
at com.google.gson.Gson.doubleAdapter()
at com.google.gson.Gson.doubleAdapter()
at com.google.gson.Gson.doubleAdapter()
at com.joltimate.umdshuttle.Data.DataStorage.saveDataList()
at com.joltimate.umdshuttle.Data.DataStorage.getAllData()
at com.joltimate.umdshuttle.Data.DataStorage.saveDataList()
at com.joltimate.umdshuttle.MainActivity.onCreate()

You have:
Type type;
type = new TypeToken<ArrayList<ArrayList<ArrayList<BusEntry>>>>(){}.getType();
Gson gson = new Gson();
return gson.fromJson(jsonString, type);
From the documentation:
Gson gson = new Gson();
int[] ints = {1, 2, 3, 4, 5};
(Serialization)
gson.toJson(ints); ==> prints [1,2,3,4,5]
(Deserialization)
int[] ints2 = gson.fromJson("[1,2,3,4,5]", int[].class);
==> ints2 will be same as ints
It would seem you are not returning the expected type.
I would suggest something like the following:
class SpecialArrayType{
private ArrayList<ArrayList<BusEntry>> specialArrayType;
public void setSpecialArrayType(ArrayList<ArrayList<BusEntry>> list){
this.specialArrayType = list;
}
public ArrayList<ArrayList<BusEntry>> getSpecialArrayType(){
return specialArrayType;
}
}
// Get the array list as a special type, then deal with the nested lists.
ArrayList<SpecialArrayType> lists = new ArrayList<SpecialArrayType>();
Type type = new TypeToken<ArrayList<SpecialArrayType>>(){}.getType();
Gson gson = new Gson();
lists = gson.fromJson(jsonString, type);
ArrayList<ArrayList<ArrayList<BusEntry>>> returnList = new ArrayList<ArrayList<ArrayList<BusEntry>>>();
// Loop through special array list to populate info from nested array lists.
for(SpecialArrayType list1: lists){
// We have these items in our outer array list, we want to add them to our
// return list.
returnList.Add(list1);
// The next nested array list.
list1 = new ArrayList<ArrayList<BusEntry>>();
for(ArrayList<BusEntry> list2: list1){
// Populate each specialArrayType with an array list of array list of BusEntries.
list1.Add(list2);
// Find each nested array list of bus entries.
list2= new ArrayList<BusEntry>> ();
for(BusEntry entry: list2){
list2.Add(entry);
}
}
}
return returnList;
So you are returning the fully nested data.

Add following library in your android studio project instead of putting manual library in library folder.
compile 'com.google.code.gson:gson:2.3.1'
and if you are trying to store arraylist or class object in sharedpreferences using GSON then try this tutorial : click here

Related

How to create array of classes in android

I have a list of classes that i would like to store in an Array or any data structure that would suite my problem. The array should be available across all the package and each element of the classes should be accessible from within the array. Its an Android app.
In Kotlin:
val class1 = Class1()
val class2 = Class2()
val list = ArrayList<Any>()
list.add(class1)
list.add(class2)
Any means you can store any type of object in it. Kotlin SmartCast allows you to check from ArrayList as well
In Java:
Class1 class1 = new Class1()
Class2 class2 = new Class2()
ArrayList list = new ArrayList<Object>()
list.add(class1)
list.add(class2)
You can store ArrayList in SharedPreferences and can use it in the whole application.
Here is sample code (You can optimize it)
public void saveArrayList(ArrayList<Object> list, String key){
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
SharedPreferences.Editor editor = prefs.edit();
Gson gson = new Gson();
String json = gson.toJson(list);
editor.putString(key, json);
editor.apply(); // This line is IMPORTANT !!!
}
public ArrayList<Object> getArrayList(String key){
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
Gson gson = new Gson();
String json = prefs.getString(key, null);
Type type = new TypeToken<ArrayList<Object>>() {}.getType();
return gson.fromJson(json, type);
}
Here you fetch the object from ArrayList:
ArrayList list = getArrayList("some key");
for (int counter = 0; counter < list.size(); counter++) {
if(list[counter] instance of class1) {
// you have class1 object
}
if(list[counter] instance of class2){
// you have class2 object
}
}
if you don't need to persist the list, i think it will be better to use a singelton that contains a class list

How can I save and load from preferences the entries of a listview that has multiple types of entries?

I have a listview that displays a list of interfaces, where the interface is implemented by two types of classes:
1) An entry with a date
2) A header that break up the entries by day
My issue is being able to save and load the list of interfaces into preferences when the app is opened/closed. From what I understand, I need to use an interface adapter to serialize/deserialize the list of interfaces.
I tried following the tutorial but I'm getting an error
Caused by: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
from the line "gson.fromJson(json, type)" in the "loadCLEntries" function below. Below is my relevant code.
Interface:
public interface CallLogListViewItem {
//These are so the list view can tell if an entry is a header or an entry
public int getViewType();
public View getView(LayoutInflater inflater, View convertView);
}
List being displayed in listview:
private static List<CallLogListViewItem> callLogEntries = new ArrayList<>();
Code that loads the entries + headers from preferences when app is opened:
private static ArrayList<CallLogListViewItem> loadCLEntries() {
SharedPreferences pref = App.getApp().getSharedPreferences("info", MODE_PRIVATE);
String json = pref.getString("CallLogEntries", "[]");
Type type = new TypeToken<ArrayList<CallLogListViewItem>>(){}.getType();
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(CallLogListViewItem.class, new InterfaceAdapter<>());
Gson gson = builder.create();
return gson.fromJson(json, type);
}
Code to save the headers + entries when app is closed:
private static void saveCLEntries() {
//Save entries
SharedPreferences pref = App.getApp().getSharedPreferences("info", MODE_PRIVATE);
SharedPreferences.Editor editor = pref.edit();
Gson gson = new Gson();
String json = gson.toJson(callLogEntries, CallLogListViewItem.class);
editor.putString("CallLogEntries", json);
editor.apply();
}
It turns out the problem is that I'm saving the list of interfaces incorrectly.
When serializing the list, I need to also use the interface adapter:
private static void saveCLEntries() {
//Save entries
SharedPreferences pref = App.getApp().getSharedPreferences("info", MODE_PRIVATE);
SharedPreferences.Editor editor = pref.edit();
Type type = new TypeToken<ArrayList<CallLogListViewItem>>(){}.getType();
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(CallLogListViewItem.class, new InterfaceAdapter<>());
Gson gson = builder.create();
String json = gson.toJson(callLogEntries, type);
editor.putString("CallLogEntries", json);
editor.apply();
}
And that was it.

How can I cast a stringarray to an ArrayList in Android?

I'm saving a list with json in SharedPreferences. This works just fine, but when I try to load it Android Studio tells me I can't
private List<AppInfo> apps;
apps = new ArrayList<AppInfo>();
// Storing in method
ArrayList<String> lollist = new ArrayList<>();
lollist = new ArrayList<>(Arrays.asList(String.valueOf(apps)));
setStringArrayPref(this, "urls", lollist);
// Loading which doesn't work
lollist = getStringArrayPref(this, "urls");
apps = (String[]) lollist.toArray();
The error I get is
Required: java.util.list <com.....AppInfo>
Found: java.lang.String[]
How may I do this?
You might wanna use Gson library for this.
Which provides you easier one line options to convert a data structure to Json and vice versa.
Usage :
private Gson gson = new Gson();
private List<AppInfo> apps = new ArrayList<AppInfo>();
String jsonString = gson.toJson(apps); //You may store this string in your shared preference
Type type = new TypeToken<List<AppInfo>>() {}.getType();
apps = gson.fromJson(jsonString, type);
NOTE :
You should Expose the variables in your Data model class to use Gson. Like this.
#Expose
private String name;

Android JSON parsing with GSON crash: LinkedTreeMap cannot be cast to Object

I am trying to store a list of objects into SharedPreferences, so therefore am using Gson to convert the list of objects into JSON and back again. However, when I store then retrieve the list of objects and the ListView's adapter is applied to the new List, I get the following error:
java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to appuccino.simplyscan.Objects.Folder
at appuccino.simplyscan.Extra.DocumentAdapter.getView(DocumentAdapter.java:117)
where the error points at this line in the list's adapter:
Folder folder = folderList.get(position);
When storing the object list, I am using the following:
//folderList is a List<Folder> folderList = new ArrayList<>();
folderList.add(0, newFolder);
Gson gson = new Gson();
String newFoldersJson = gson.toJson(folderList);
PrefManager.putString(PrefManager.FOLDER_JSON, newFoldersJson);
where the last line simply stores the string into SharedPreferences. When retrieving the list from SharedPreferences, I am using the following:
public static List<Folder> loadFolders(MainActivity main){
//JSON containing a list of folder objects
String foldersJSON = PrefManager.getString(PrefManager.FOLDER_JSON, "");
if(!foldersJSON.isEmpty()){
Gson gson = new Gson();
List<Folder> folderList = gson.fromJson(foldersJSON, List.class);
return folderList;
}
return new ArrayList<>();
}
If it helps, here is how my Folder class is defined:
public class Folder {
private String name;
private List<String> docNameList;
private transient List<Document> docList;
public Folder(String n) {
name = n;
docList = new ArrayList<>();
docNameList = new ArrayList<>();
}
}
Not a answer to your question, but a suggestion. I am also trying to work with json in Android recently and researched a lot about which one to use jackson or gson. Seems like there are 2 advantages of jackson:
Performance of jackson is better than gson.
If you are using the same on server side then you get consistency.
Ref:
[be-lazy-productive-android][1]
http://java.dzone.com/articles/be-lazy-productive-android

Android JSon error "Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2"

I am getting JSon data from a web service, the sample data is given below:
[
{
"SectionId": 1,
"SectionName": "Android"
}
]
When i try to convert it, it throws an error, i am doing it as:
Data data = new Gson().fromJson(jsonDataFromWebService, Data.class);
My Section Class is:
class Section
{
public int SectionId;
public String SectionName;
}
class Data {
public List<Section> sections;
}
The LogCat says:
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException:
Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2
You're trying to create an non-Array(Collection) object from a JSONArray. The error is pretty clear: GSON was expecting the beginning of an object but found the beginning of an array instead.
Take a look at the documentation page below to see how to work with Array and Collection types with GSON
https://sites.google.com/site/gson/gson-user-guide#TOC-Collections-Examples
From the docs:
Array Examples
Gson gson = new Gson(); int[] ints = {1, 2, 3, 4, 5}; String[] strings
= {"abc", "def", "ghi"};
(Serialization) gson.toJson(ints); ==> prints [1,2,3,4,5]
gson.toJson(strings); ==> prints ["abc", "def", "ghi"]
(Deserialization) int[] ints2 = gson.fromJson("[1,2,3,4,5]",
int[].class);
==> ints2 will be same as ints
We also support multi-dimensional arrays, with arbitrarily complex
element types
Collections Examples
Gson gson = new Gson(); Collection ints =
Lists.immutableList(1,2,3,4,5);
(Serialization) String json = gson.toJson(ints); ==> json is
[1,2,3,4,5]
(Deserialization) Type collectionType = new
TypeToken>(){}.getType(); Collection
ints2 = gson.fromJson(json, collectionType); ints2 is same as ints
Fairly hideous: note how we define the type of collection
Unfortunately, no way to get around this in Java
Collections Limitations
Can serialize collection of arbitrary objects but can not deserialize
from it Because there is no way for the user to indicate the type of
the resulting object While deserializing, Collection must be of a
specific generic type All of this makes sense, and is rarely a problem
w> hen following good Java coding practices
The error explains whats wrong... u r returning an array and not a JSon object
try as following:
JSONArray ja = new JSONArray(jsonStringReturnedByService);
Data sections = new Data();
for (int i = 0; i < ja.length(); i++) {
Section s = new Section();
JSONObject jsonSection = ja.getJSONObject(i);
s.SectionId = Integer.ValueOf(jsonSection.getString("SectionId"));
s.SectionName = jsonSection.getString("SectionName");
//add it to sections list
sections.add(s);
}
return sections;
Use Section class only as follows:
Section[] sectionArray = new Gson().fromJson(jsonDataFromWebService, Section[].class);
for (Section section: sectionArray) {
Log.e("Debug", section.toString());
}

Categories

Resources