mapf mapf -4 years ago 86
Android Question

ArrayList Length gets 0 in Singleton

I am using a singleton for fetching data from a web service and storing the resulting data object in an ArrayList. It looks like this:

public class DataHelper {

private static DataHelper instance = null;

private List<CustomClass> data = null;

protected DataHelper() {
data = new ArrayList<>();
}

public synchronized static DataHelper getInstance() {
if(instance == null) {
instance = new DataHelper();
}
return instance;
}

public void fetchData(){

BackendlessDataQuery query = new BackendlessDataQuery();
QueryOptions options = new QueryOptions();
options.setSortBy(Arrays.asList("street"));
query.setQueryOptions(options);

CustomClass.findAsync(query, new AsyncCallback<BackendlessCollection<CustomClass>>() {
@Override
public void handleResponse(BackendlessCollection<CustomClass> response) {

int size = response.getCurrentPage().size();

if (size > 0) {
addData(response.getData());
response.nextPage(this);
} else {
EventBus.getDefault().post(new FetchedDataEvent(data));
}

}

@Override
public void handleFault(BackendlessFault fault) {
EventBus.getDefault().post(new BackendlessFaultEvent(fault));
}
});

}

public List<CustomClass> getData(){
return this.data;
}

public void setData(List<CustomClass> data){
this.data = data;
}

public void addData(List<Poster> data){
this.data.addAll(data);
}

public List<CustomClass> getData(FilterEnum filter){

if(filter == FilterEnum.NOFILTER){
return getData();
}else{
// Filtering and returning filtered data
}

return getData();
}
}


The data is fetched correctly and the list actually contains data after it. Also, only one instance is created, as intended. However, whenever I call getData later, the length of this.data is 0. Because of this I also tried it with a subclass of Application holding the DataHelper object, resulting in the same problem.


  1. Is there a good way of debugging this? Is there something like global watches in Android Studio?

  2. Is there something wrong with my approach? Is there a better approach? I am mainly an iOS developer, so Android is pretty new to me. I am showing the data from the ArrayList in different views, thus I want to have it present in an the ArrayList as long as the application runs.



Thanks!

EDIT: Example use in a list view fragment (only relevant parts):

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
filter = FilterEnum.NOFILTER;
data = DataHelper.getInstance().getData(filter);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
customClassListAdapter = new customClassListAdapter(getActivity(), data);}


EDIT2: Added code where I fetch the data from Backendless, changed reference of DataHelper to reference of data in first EDIT

EDIT3: I usa a local EventBus for notifying the list view about the new data. This looks like this and works (initially the data gets populated, but after e.g. applying a filter, the ArrayList I get with getData is empty):

@Subscribe
public void onMessageEvent(FetchedDataEvent event) {
customClassListAdapter.notifyDataSetChanged();
}

Answer Source

Okay I finally found the problem. It was not about the object or memory management at all. Since I give the reference on getData to my ArrayAdapter, whenever I call clear (which I do when changing the filter) on the ArrayAdapter, it empties the reference. I basically had to create a copy of the result for the ArrayAdapter:

data = new ArrayList<>(DataHelper.getInstance().getData(filter));

I was not aware of the fact that this is a reference at all. So with this the data always stays in the helper entirely. I only did this because this:

 customClassListAdapter.notifyDataSetChanged();

does hot help here, it does not call getData with the new filter again.

Thanks everyone for your contributions, you definitely helped me to debug this.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download