beginner992
beginner992

Reputation: 719

I have to convert the list of the objects to the object and vice versa in Room Database

I have to convert the list of objects to the Event object and vice versa. I need it for the Room Database to store data from web. I created two converters, but they don't work. Converters class is set in database, data from web works well, I can download one object from the list, so there is no problem with an api and database.

Converters:

public class Converters {

@TypeConverter
public static ArrayList<Event> fromEvent(String event) {
    Type listType = new TypeToken<ArrayList>() {}.getType();
    return new Gson().fromJson(event, listType);
}

@TypeConverter
public static String fromList(ArrayList<Event> events) {
    Gson gson = new Gson();
    String json = gson.toJson(events);
    return json;
}
}

Fragment:

 private void getEvents() {
    eventsViewModel.getEvents().observe(getViewLifecycleOwner(), new Observer<Event>() {
        @Override
        public void onChanged(Event events) {
            if (events == null) {
                Log.e(TAG, "EVENTS NULL");
            }
            else {
                Log.e(TAG, "EVENTS OK");
            }

            List<Event> events1 = (List) events;
            adapter.setEvents(events1);
            adapter.notifyDataSetChanged();
        }
    });
}

I am trying here parse Object events to the Event list but there is an error: java.lang.ClassCastException: com.example.data.model.Event cannot be cast to java.util.List

Maybe I can't convert an object itself and I have to create another POJO and then put Event POJO to them as a list?

Repository:

public class EventRepository {

private final EventsApi apiInterface;
private EventDao eventDao;

@Inject
public EventRepository(EventsApi apiInterface, EventDao eventDao) {
    this.apiInterface = apiInterface;
    this.eventDao = eventDao;
}

public LiveData<ArrayList<Event>> fetchEvents() {

    final MutableLiveData<ArrayList<Event>> data = new MutableLiveData<>();
    apiInterface.getEvents().enqueue(new Callback<ArrayList<Event>>() {
        @Override
        public void onResponse(Call<ArrayList<Event>> call, Response<ArrayList<Event>> response) {
            data.setValue(response.body());
                persistFetchedEvents(response.body());
        }

        @Override
        public void onFailure(Call<ArrayList<Event>> call, Throwable t) {
            data.setValue(null);
        }
    });
    return data;

}

public LiveData<List<Event>> getEvents() {
    initEvents();
    return eventDao.getEvents();
}

private void persistFetchedEvents(List<Event> events) {
    new InsertEventsAsyncTask(eventDao).execute(events);
}

private static class InsertEventsAsyncTask extends AsyncTask<List<Event>, Void, Void> {
    private EventDao eventDao;

    private InsertEventsAsyncTask(EventDao eventDao) {
        this.eventDao = eventDao;
    }

    @SafeVarargs
    @Override
    protected final Void doInBackground(List<Event>... events) {
        eventDao.insertAll(events);
        return null;
    }
}

private void initEvents() {
    if (isFetchEventsNeeded(ZonedDateTime.now().minusHours(1))) {
        fetchEvents();
    }
}

private Boolean isFetchEventsNeeded(ZonedDateTime lastfetchTime) {
    ZonedDateTime thirtyMinutesAgo = ZonedDateTime.now().minusMinutes(30);
    return lastfetchTime.isBefore(thirtyMinutesAgo);
}

}

Dao:

@Dao
 public interface EventDao {

@Insert(onConflict = OnConflictStrategy.REPLACE)
void updateEvent(Event event);

@Query("SELECT * FROM events WHERE idKey = 0")
LiveData<Event> getEvents();
}

Event:

@Entity(tableName = "events")

@TypeConverters(Converters.class) public class Event {

@SerializedName("id")
@Expose
private int id;
@SerializedName("title")
@Expose
private String title;
@SerializedName("subtitle")
@Expose
private String subtitle;
@SerializedName("date")
@Expose
private String date;
@SerializedName("imageUrl")
@Expose
private String imageUrl;
@SerializedName("videoUrl")
@Expose
private String videoUrl;

@PrimaryKey(autoGenerate = false)
private int idKey = 0;

public Event(int id, String title, String subtitle, String date, String imageUrl, String videoUrl) {
    this.id = id;
    this.title = title;
    this.subtitle = subtitle;
    this.date = date;
    this.imageUrl = imageUrl;
    this.videoUrl = videoUrl;
}

public int getIdKey() {
    return idKey;
}

public void setIdKey(int idKey) {
    this.idKey = idKey;
}

public int getId() {
    return id;
}

public void setId(int id) {
    this.id = id;
}

public String getTitle() {
    return title;
}

public void setTitle(String title) {
    this.title = title;
}

public String getSubtitle() {
    return subtitle;
}

public void setSubtitle(String subtitle) {
    this.subtitle = subtitle;
}

public String getDate() {
    return date;
}

public void setDate(String date) {
    this.date = date;
}

public String getImageUrl() {
    return imageUrl;
}

public void setImageUrl(String imageUrl) {
    this.imageUrl = imageUrl;
}

public String getVideoUrl() {
    return videoUrl;
}

public void setVideoUrl(String videoUrl) {
    this.videoUrl = videoUrl;
}
}

Upvotes: 0

Views: 366

Answers (1)

Networks
Networks

Reputation: 2212

java.lang.ClassCastException is being thrown because you are trying to cast an Event object into a list. Make sure your eventsViewModel.getEvents() returns LiveData<ArrayList<Event>> instead of LiveData<Event>.

Change the return type of getEvents() in EventDao from LiveData<Event> to LiveData<ArrayList<Event>>

@Query("SELECT * FROM events WHERE idKey = 0")
LiveData<ArrayList<Event>> getEvents();

Also your call to your ApiInterface returns a single event. Make sure it returns a list of Events. Then you can persist them all and your LiveData<ArrayList<Event>> from eventDao.getEvents() will update with your newly persisted list of Event objects.

EDIT Per your request I'm adding an example

In your fragment

private void getEvents() {
    eventsViewModel.getEvents().observe(getViewLifecycleOwner(), new Observer<List<Event>>() {
        @Override
        public void onChanged(List<Event> events) {
            if (events == null) {
                Log.e(TAG, "EVENTS NULL");
            }
            else {
                Log.e(TAG, "EVENTS OK");
            }

            adapter.setEvents(events);
            adapter.notifyDataSetChanged();
        }
    });
}

In the Repository

public class EventRepository {

private final EventsApi apiInterface;
private EventDao eventDao;

@Inject
public EventRepository(EventsApi apiInterface, EventDao eventDao) {
    this.apiInterface = apiInterface;
    this.eventDao = eventDao;
}

public LiveData<ArrayList<Event>> fetchEvents() {

    final MutableLiveData<ArrayList<Event>> data = new MutableLiveData<>();
    apiInterface.getEvents().enqueue(new Callback<ArrayList<Event>>() {
        @Override
        public void onResponse(Call<ArrayList<Event>> call, Response<ArrayList<Event>> response) {

                data.postValue(response.body());
                persistFetchedEvents(response.body());
        }

        @Override
        public void onFailure(Call<ArrayList<Event>> call, Throwable t) {

        }
    });
    return data;
}

public LiveData<List<Event>> getEvents() {
    initEvents();
    return eventDao.getEvents();
}

private void persistFetchedEvents(List<Event> events) {
    new InsertEventsAsyncTask(eventDao).execute(events);
}

private static class InsertEventsAsyncTask extends AsyncTask<List<Event>, Void, Void> {
    private EventDao eventDao;

    private InsertEventsAsyncTask(EventDao eventDao) {
        this.eventDao = eventDao;
    }

    @Override
    protected Void doInBackground(List<Event>... events) {
        Event[] eventArray = events[0].toArray(new Event[events[0].size()]);
        eventDao.insertAll(eventArray);
        return null;
    }
}

private void initEvents() {
    if (isFetchEventsNeeded(ZonedDateTime.now().minusHours(1))) {
        fetchEvents();
    }
}

private Boolean isFetchEventsNeeded(ZonedDateTime lastfetchTime) {
    ZonedDateTime thirtyMinutesAgo = ZonedDateTime.now().minusMinutes(30);
    return lastfetchTime.isBefore(thirtyMinutesAgo);
}

}

In your dao(I added a new method to insertAll)

@Dao
 public interface EventDao {

@Insert(onConflict = OnConflictStrategy.REPLACE)
void insertAll(Event... events);

@Insert(onConflict = OnConflictStrategy.REPLACE)
void updateEvent(Event event);

@Query("SELECT * FROM events")
LiveData<List<Event>> getEvents();
}

You will need to change the return type of eventsViewModel.getEvents() to LiveData<List<Event>> and apiInterface.getEvents() to Call<ArrayList<Event>>

Upvotes: 2

Related Questions