Recylerview blank when using ViewModel in fragment - android

Here, the flow first in a screen there are three buttons which are also created using recycler view. View Model is passing the data to fill the button content ie image and text. This is working fine. On click of button a new screen/fragment loads which should show list. Using below method to fetch API data:
public class TrackRepository {
MutableLiveData<TrackData> trackData;
RestClient restClient;
SharedPreferences sharedPreferences;
public TrackRepository() {
trackData = new MutableLiveData<>();
this.restClient = new RestClient();
sharedPreferences = SessionManager.getPreferences();
}
public void getTrackList(String startDate,String endDate,String searchTest){
int centerId = ClientInfo.getCenterId(sharedPreferences);
String auth = ClientInfo.getAuthToken(sharedPreferences);
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("CenterId",centerId);
jsonObject.addProperty("SearchText",searchTest);
jsonObject.addProperty("StartDate",startDate);
jsonObject.addProperty("EndDate",endDate);
restClient.getEndpoints().getTrackReports(auth,jsonObject).enqueue(new Callback<TrackData>() {
#Override
public void onResponse(Call<TrackData> call, Response<TrackData> response) {
if (response.isSuccessful()){
boolean success = response.body().isSuccess();
String message = response.body().getMessage();
try {
if (success) {
trackData.postValue(response.body());
}else {
trackData.postValue(response.body());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Override
public void onFailure(Call<TrackData> call, Throwable t) {
trackData.postValue(null);
}
});
}
public LiveData<TrackData> getTrackDataMutableLiveData() {
return trackData;
}
}
After this, the TrackHomeViewModel is created which is used by both fragment TrackHome and TrackScreen like below
public class TrackHomeViewModel extends ViewModel {
ArrayList<String> btName;//button text
ArrayList<Integer> btImage; //button image
int FLAG;
SimpleDateFormat inFormat;
private TrackRepository trackRepository;
List<TrackData> trackList;
LiveData<TrackData> track;
public TrackHomeViewModel() {
btName = new ArrayList<>();
this.btName.add("Previous Day");
this.btName.add("Previous Three Days");
btImage = new ArrayList<>();
this.btImage.add(R.drawable.ic_baseline_calendar_today_24);
this.btImage.add(R.drawable.ic_baseline_calendar_view_day_24);
trackRepository = new TrackRepository();
track = trackRepository.getTrackDataMutableLiveData();
}
public void captureCardClick(int adapterPosition) {
String selectedChoice;
String searchTest,startDate,endDate;
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
inFormat = new SimpleDateFormat("HH:mm:ss", Locale.US);
Calendar cal = Calendar.getInstance();
selectedChoice = btName.get(adapterPosition);
if (selectedChoice.equals("Previous Day")) {
FLAG = 1;
searchTest = "";
endDate = dateFormatter.format(cal.getTime()); // get current date
cal.add(Calendar.DATE, -1); //ONE day before of current date
startDate = dateFormatter.format(cal.getTime()); // get PREVIOUS date
// int centerId = ClientInfo.getCenterId(preferences);
getTrackList(startDate,endDate,searchTest);
}else if(selectedChoice.equals("Previous Three Days")){
FLAG = 2;
searchTest = "";
endDate = dateFormatter.format(cal.getTime()); // get current date
cal.add(Calendar.DATE, -3); //Three day before of current date
startDate = dateFormatter.format(cal.getTime()); // get PREVIOUS date
// int centerId = ClientInfo.getCenterId(preferences);
getTrackList(startDate,endDate,searchTest);
}
}
public void getTrackList(String startDate,String endDate,String searchTest) {
trackRepository.getTrackList(startDate, endDate, searchTest);
}
public LiveData<TrackData> getTrackLiveData() {
return track;
}
}
in the TrackScreen fragment, loading the RecyclerView like below:
public class TrackScreen extends Fragment {
private TrackHomeViewModel trackHomeViewModel;
RecyclerView recyclerView;
TrackAdapter trackAdapter;
LinearLayoutManager linearLayoutManager;
Fragment trackHome;
SearchView searchView;
List<TrackData> trackDataList;
TextView currentFragment;
MaterialToolbar toolbar;
ImageButton back;
TrackInterface trackInterface;
TrackData trackD;
public static TrackScreen newInstance() {
return new TrackScreen();
}
#Override
public void onCreate(#Nullable Bundle saveInstanceState) {
super.onCreate(saveInstanceState);
trackHomeViewModel = new ViewModelProvider(this).get(TrackHomeViewModel.class);
trackHomeViewModel.getTrackLiveData().observe(this, new Observer<TrackData>() {
#Override
public void onChanged(TrackData trackData) {
trackD = trackData;
}
});
trackInterface = new TrackInterface() {
#Override
public void captureRowClick(TrackData trackData, int adapterPosition) {
String patId = trackData.getPatientId();
Toast.makeText(getContext(), "Patient ID is " + patId, Toast.LENGTH_SHORT).show();
}
};
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_track_screen,container,false);
toolbar = view.findViewById(R.id.toolbar);
searchView = view.findViewById(R.id.search_report);
recyclerView = view.findViewById(R.id.track_recycler);
currentFragment = view.findViewById(R.id.current_fragment);
currentFragment.setText("Reports");
back = view.findViewById(R.id.back_screen);
trackHome = getParentFragmentManager().findFragmentByTag("TrackHome");
linearLayoutManager = new LinearLayoutManager(getContext());
recyclerView.setLayoutManager(linearLayoutManager);
if(trackAdapter==null) {
trackHomeViewModel.getTrackLiveData().observe(getViewLifecycleOwner(), new Observer<TrackData>() {
#Override
public void onChanged(TrackData trackData) {
trackAdapter = new TrackAdapter(getContext(),trackData.getTrackData(),trackInterface);
}
});
recyclerView.setAdapter(trackAdapter);
}else{
Toast.makeText(getContext(), "No Data Found", Toast.LENGTH_SHORT).show();
}
// other code
}
}
Data is loaded from API, but blank screen displayed by TrackScreen with
E/RecyclerView: No adapter attached; skipping layout message, i tested all other things still same message. Issue is when the TrackScreen fragment loads the list is empty and after executing the getTrackLiveData() method it loads the API data therefore at load list is empty so this message coming. I am not getting how to workaround this.
When the button is clicked it should load the TrackScreen fragment with list. Tried as above.

You need to move
recyclerView.setAdapter(trackAdapter);
inside
public void onChanged(TrackData trackData) {
...
}
Now the trackAdapter field is null when you set it to the recyclerView because onChanged is called asynchronously.

Resolved
The issue was using same viewmodel for two fragments. When using single model for two fragments it should be
viewModel = new ViewModelProvider(requireActivity()).get(ListViewModel.class);
not getlifecyclerowner when initializing the viewmodel.
After, wasting hours turned to Android official doc and found this here Communicating with fragments
Since, i was using trackHomeViewModel = new ViewModelProvider(this).get(TrackHomeViewModel.class);the code for retrieving the list from viewmodel was not executing(repository code running passing data to viewmodel but not to next fragment here TrackScreen) therefore empty list. Used Log.d and found trackData is empty. Changed to requireActivity() and everything resolved.

Related

Updating Elements of Listview in a Fragment from a Catalog within another Fragment

The title might be a little confusing so I hope that I can express my problem correctly. So I'm working on a simple workout log app. I have fragment ActiveWorkout as in Image 1. When I press the pink add button I am directed to another fragment, which contains different exercises as a List, which is shown in Image 2. Then I am to select an exercise(with the onItemClickListener) and the title of that exercise should be sent back to the ActiveWorkoutFragment and added to the Active Workout, so it should be like Image 3. So the problem here is, I don't exactly know how to keep my Active Workout 'alive', it should be updated if I want to add another exercise and not be blank when I press the pink add button again, so in the end it should be something like in Image 4. I was thinking about sending data with a Bundle, which I also tried in the code but the more difficult part is updating the Workout list without deleting the previous added exercises. Btw the reason I am trying to do something like this is because the data is actually in Firebase Database, so in a sense I'm trying to retrieve data from the Workout database.
Images:
Image 1 Image 2 Image 3 Image 4
This is the Exercise List or the Catalog:
public class ExercisesFragment extends Fragment {
private ListView lv;
private FirebaseListAdapter adapter;
private ArrayList<Exercise> exerciseList;
private ArrayList<String> nameList;
//private Adapter adapter;
public ExercisesFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_exercises, container, false);
lv = v.findViewById(R.id.lv);
Query query = FirebaseDatabase.getInstance().getReference().child("exerciseList");
FirebaseListOptions<ExerciseElement> options = new FirebaseListOptions.Builder<ExerciseElement>()
.setLayout(R.layout.exercise)
.setQuery(query, ExerciseElement.class)
.build();
adapter = new FirebaseListAdapter(options) {
#Override
protected void populateView(#NonNull View v, #NonNull Object model, int position) {
TextView bodypart = v.findViewById(R.id.bodypart);
TextView title = v.findViewById(R.id.title);
ExerciseElement el = (ExerciseElement) model;
bodypart.setText(el.getBodypart().toString());
title.setText(el.getTitle().toString());
}
};
lv.setAdapter(adapter);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ExerciseElement el = (ExerciseElement) lv.getItemAtPosition(position);
String item = el.getTitle();
ActiveWorkoutFragment awf = new ActiveWorkoutFragment();
Bundle args = new Bundle();
args.putString("ExerciseTitle", item);
awf.setArguments(args);
getFragmentManager().beginTransaction().replace(R.id.nav_host_fragment, awf).commit();
//Navigation.findNavController(v).navigate(R.id.activeWorkoutFragment);
}
});
return v;
}
#Override
public void onStart() {
super.onStart();
adapter.startListening();
}
#Override
public void onStop() {
super.onStop();
adapter.stopListening();
}
}
Then there is the ActiveWorkoutFragment, which is a little longer but the upper part is not the concern. The addNewExercise() method is being called when I click on the pink add button, so I was trying to retrieve the data somehow there.
public class ActiveWorkoutFragment extends Fragment {
private Workout workout;
private TextView emptyRecyclerView;
private RecyclerView exerciseRecyclerView;
private ExerciseRecyclerViewAdapter adapter;
private WorkoutHistory workoutHistory;
private FloatingActionButton fab;
private FirebaseAuth mAuth;
private DatabaseReference databaseWorkouts;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_active_workout, container, false);
fab = v.findViewById(R.id.fab);
fab.setOnClickListener(this::addNewExercise);
setHasOptionsMenu(true);
workout = new Workout("WORKOUT");
if(savedInstanceState != null) {
workout = savedInstanceState.getParcelable("key");
}
emptyRecyclerView = v.findViewById(R.id.empty_recycler_view);
//buildRecyclerView(workout);
exerciseRecyclerView = v.findViewById(R.id.recycler_view_exercise);
// improves performance if size of RecyclerView content is fixed
// taken from developer.android.com
exerciseRecyclerView.setHasFixedSize(true);
// use a linear layout manager for RecyclerView
LinearLayoutManager layoutManager = new LinearLayoutManager(this.getContext());
exerciseRecyclerView.setLayoutManager(layoutManager);
// add divider
RecyclerView.ItemDecoration itemDecoration = new
DividerItemDecoration(this.getContext(), DividerItemDecoration.VERTICAL);
exerciseRecyclerView.addItemDecoration(itemDecoration);
// Create adapter and set its data set to workout
adapter = new ExerciseRecyclerViewAdapter(workout, this);
// Set up swipe to dismiss and ability to move RecyclerView items around
// Create callback object for ItemTouchHelper
ItemTouchHelper.Callback callback = new CustomItemTouchHelperCallback(adapter);
// Implement object created above
ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
touchHelper.attachToRecyclerView(exerciseRecyclerView);
if (adapter.getItemCount() == 0)
{
showEmptyRecyclerViewText();
}
else
{
exerciseRecyclerView.setAdapter(adapter);
}
return v;
}
// Adds save button (check mark) to action bar
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.active_workout_action_bar, menu);
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_save: {
List<Exercise> exercises = workout.getExercises();
mAuth = FirebaseAuth.getInstance();
String user_id = mAuth.getCurrentUser().getUid();
databaseWorkouts = FirebaseDatabase.getInstance().getReference("Workouts").child(user_id);
String id = databaseWorkouts.push().getKey();
workout = new Workout("abc", user_id, exercises);
databaseWorkouts.child(id).setValue(workout);
Toast.makeText(getContext(), "Workout saved", Toast.LENGTH_SHORT).show();
return true;
}
case R.id.action_delete: {
exerciseRecyclerView.requestFocus();
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle("Confirm deletion").setMessage("Are you sure you want to delete" +
" this workout?");
builder.setPositiveButton(android.R.string.yes, (dialog, which) -> {
try {
workoutHistory.removeWorkout(workout);
} catch (IOException e) {
e.printStackTrace();
}
Toast.makeText(getContext(), "Workout deleted", Toast.LENGTH_SHORT).show();
});
builder.setNegativeButton(android.R.string.no, (dialog, which) -> {
dialog.dismiss();
});
builder.show();
return true;
}
default:
// unrecognized button pressed
return super.onOptionsItemSelected(item);
}
}
public void showEmptyRecyclerViewText()
{
emptyRecyclerView.setVisibility(View.VISIBLE);
}
public void addNewExercise(View view) {
Bundle bundle = getArguments();
String value = "";
if(bundle != null) {
value = bundle.getString("ExerciseTitle");
}
System.out.println("lala");
System.out.println(value);
Exercise newExercise = new Exercise(value, -1, -1);
if (exerciseRecyclerView.getAdapter() == null) {
exerciseRecyclerView.setAdapter(adapter);
}
emptyRecyclerView.setVisibility(View.INVISIBLE);
workout.addExercise(newExercise);
adapter.notifyItemInserted(workout.getExercises().size() - 1);
}
private void hideKeyboard(Context context, View view) {
InputMethodManager imm = (InputMethodManager) context.getSystemService
(Activity.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
#Override
public void onSaveInstanceState(#NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable("key", workout);
}
}
Try this as a base for your project. add views to it and other necessary methods however it will provide you with the flow of module
//contract to update Framgents
public interface FragUpdater {
public void updateExerciseFrag(Exercise exercise);
}
public class ExerciseActiity extends AppCompatActivity implements FragUpdater {
FragmentManager fm;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_exercise_actiity);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
gotoActiveWorkoutFragment();
}
});
fm = getSupportFragmentManager();
gotoExercisesFragment();
}
private void gotoActiveWorkoutFragment() {
ActiveWorkoutFragment activeWorkoutFragment = new ActiveWorkoutFragment();
Bundle bundle = new Bundle();
activeWorkoutFragment.setArguments(bundle);
fm.beginTransaction().add(R.id.content_frame, activeWorkoutFragment, "ExerciseSelectionFrag").addToBackStack(null).commit();
}
private void gotoExercisesFragment() {
ExercisesFragment exercisesFragment = new ExercisesFragment();
Bundle bundle = new Bundle();
exercisesFragment.setArguments(bundle);
fm.beginTransaction().replace(R.id.content_frame, exercisesFragment, "ExerciseDisplayFrag").commit();
}
#Override
public void updateExerciseFrag(Exercise exercise) {
// Get Fragment ExercisesFragment
ExercisesFragment frag = (ExercisesFragment)
fm.findFragmentByTag("ExerciseDisplayFrag");
if (frag == null) {
return;
}
frag.updateList(exercise);
}
}
public class ExercisesFragment extends Fragment {
//here update your list in ExerciseFragment
public void updateList(Exercise exercise) {}
}
public class ActiveWorkoutFragment extends Fragment {
FragUpdater fragUpdater;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fragUpdater = (ExerciseActiity) getActivity();
}
private void selectListItem(Exercise exercise) {
fragUpdater.updateExerciseFrag(exercise);
getActivity().getSupportFragmentManager().popBackStack();
}
}

Getting current fragment variables values

I am using FragmentViewPagerAdapter to create a calendar Activity. Each fragment represents a day, and I have a Switch on my main activity that allows the user to filter results on each fragment.
I am using ViewModel to request data, so when the switch is checked I need to do a new request to my server to get new data for each fragment, My problem is that when I do my request, the day sent is next fragment's date, not the current's one.
I already tried to limit of screen pages to 0 but nothing changed.
public class PoiPlanningFragment extends Fragment implements InitApplicationListener{
MutableLiveData<Boolean> filtered = new MutableLiveData<>();
private Context mContext;
DateTime startTime;
DateTime endTime;
switcher = getActivity().findViewById(R.id.app_switcher);
public PoiPlanningFragment() {
// Required empty public constructor
}
public static Fragment getInstance(int position, String date, String resourceId, String resourceType,boolean filter) {
Bundle bundle = new Bundle();
bundle.putInt("pos", position );
bundle.putString("date", date);
bundle.putString(ARG_RESOURCE_ID, resourceId);
bundle.putString(ARG_RESOURCE_TYPE, resourceType);
PoiPlanningFragment tabFragment = new PoiPlanningFragment();
tabFragment.setArguments(bundle);
return tabFragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
DateTimeFormatter horaire = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm");
startTime = horaire.parseDateTime(date.concat(" " + STARTHOUR));
endTime = horaire.parseDateTime(date.concat(" " + ENDHOUR));
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_poi_planning, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
//Switch my meetings
switcher.setOnCheckedChangeListener(new SwitchClickedListener(this.filtered));
//Observes whether the user has a filter on own meetings or not
filtered.observe(this, filtered -> {
//here startTime always shows next tab startTime and endTime
BookingRepository.getUserPlanning(planning,resourceId,Utility.toTimeStamp(startTime),Utility.toTimeStamp(endTime), filtered);
loader.setVisibility(View.VISIBLE);
});
}
}
private class SwitchClickedListener implements CompoundButton.OnCheckedChangeListener{
MutableLiveData<Boolean> listener;
SwitchClickedListener(MutableLiveData<Boolean> listener){
this.listener = listener;
}
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
//Set filter to true
this.listener.setValue(b);
}
}
public class PoiPlanningViewPagerAdapter extends FragmentStatePagerAdapter {
private final static String TAG = PoiPlanningViewPagerAdapter.class.getName();
private List<Date> dateList;
private Context context;
private String poiId;
private String resouceType;
public PoiPlanningViewPagerAdapter(FragmentManager fm, List<Date> dates, String poidId,String resourceType, Context context) {
super(fm);
this.dateList = dates;
this.context = context;
this.poiId = poidId;
this.resouceType = resourceType;
}
#Override
public Fragment getItem(int position) {
Date datetime = dateList.get(position);
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
String date = df.format(datetime);
PoiPlanningFragment planningFragment = (PoiPlanningFragment) PoiPlanningFragment.getInstance(position, date, poiId,resouceType,false);
return planningFragment;
}
#Override
public int getCount() {
return dateList.size();
}
#Override
public CharSequence getPageTitle(int position) {
Date datetime = dateList.get(position);
DateFormat df = new SimpleDateFormat(context.getString(R.string.date_format));
String date = df.format(datetime);
return date;
}
}
In the previous code, if I check the switch and I am on Monday 02 11th It will load data of Tuesday.
You can use supportFragmentManager for getting current fragment.
below code will help you.
if (getSupportFragmentManager().getBackStackEntryCount() > 1) {
val frag = getSupportFragmentManager().findFragmentById(R.id.container);
if (frag is HomeFragment) {
Fragment currentFragment = (HomeFragment) frag;
//do your code
return
}
}
I hope this will help you.

Two differents request, two differents Calls and One Recycler

I am trying to do this..
.
I am consuming two different requests resources from the same API and in MainActivity doing two different calls. But, I can't show the content I want from both JSON on one RecyclerView view.
MainActivity.java
public class MainActivity extends AppCompatActivity {
private Retrofit retrofit;
private static final String TAG = "Football";
private RecyclerView recyclerView;
private ListaPartidosAdapter listaPartidosAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView)findViewById(R.id.recyclerView);
listaPartidosAdapter = new ListaPartidosAdapter(this);
recyclerView.setAdapter(listaPartidosAdapter);
recyclerView.setHasFixedSize(true);
final LinearLayoutManager layoutManager = new LinearLayoutManager(this, VERTICAL, true);
recyclerView.setLayoutManager(layoutManager);
retrofit = new Retrofit.Builder()
.baseUrl("http://api.football-data.org/v2/")
.addConverterFactory(GsonConverterFactory.create())
.build();
obtenerDatos();
}
private void obtenerDatos() {
Calendar calendar = Calendar.getInstance();
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
String todayDate=df.format(calendar.getTime());
calendar.add(Calendar.DATE,3);
String endDate = df.format(calendar.getTime());
Log.i(TAG, "todayDate : " + todayDate);
Log.i(TAG, "endDate : " + endDate);
footballdataService service = retrofit.create(footballdataService.class);
Call<PartidosRespuesta> partidosRespuestaCall = service.obtenerlistaPartidos(todayDate,endDate);
Call<StandingsRespuesta> standingsRespuestaCall = service.obtenerStandings();
partidosRespuestaCall.enqueue(new Callback<PartidosRespuesta>() {
#Override
public void onResponse(Call<PartidosRespuesta> call, Response<PartidosRespuesta> response) {
if(response.isSuccessful()) {
PartidosRespuesta partidosRespuesta = response.body();
List<Partido> listaPartidos = partidosRespuesta.getMatches();
listaPartidosAdapter.adicionarListaPartidos((ArrayList<Partido>) listaPartidos);
}
else {
Log.e(TAG, "onResponse: " + response.errorBody());
}
}
#Override
public void onFailure(Call<PartidosRespuesta> call, Throwable t) {
Log.e(TAG, "onFailure: " + t.getMessage());
}
});
standingsRespuestaCall.enqueue(new Callback<StandingsRespuesta>() {
#Override
public void onResponse(Call<StandingsRespuesta> call, Response<StandingsRespuesta> response) {
if(response.isSuccessful()) {
StandingsRespuesta standingsRespuesta = response.body();
List<Stand> listaStands = standingsRespuesta.getStandings();
listaPartidosAdapter.adicionarListaStands((ArrayList<Stand>) listaStands);
}
}
#Override
public void onFailure(Call<StandingsRespuesta> call, Throwable t) {
}
});
}
}
As I say before, each request has a different enqueue Call. I don't know if it is the right way of do it but think yes because each call has its own service.
ListaPartidosAdapter.java
public class ListaPartidosAdapter extends RecyclerView.Adapter<ListaPartidosAdapter.ViewHolder> {
private static final String TAG = "Football_Adapter";
private ArrayList<Partido> dataset;
private ArrayList<Stand> dataset_stand;
private Context context;
public ListaPartidosAdapter(Context context) {
this.context = context;
this.dataset = new ArrayList<Partido>();
this.dataset_stand = new ArrayList<Stand>();
}
#Override
public ListaPartidosAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_partidos, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ListaPartidosAdapter.ViewHolder holder, int position) {
Partido p = dataset.get(position);
String status = p.getStatus();
if (status.equals("SCHEDULED")){
String status_ = "SCH";
holder.status.setText(status_);
}
holder.utcDate.setText(p.getUtcDate());
Partido.EquipoCasa homeTeam = p.getHomeTeam();
String id_homeTeam = homeTeam.getId();
holder.homeTeam.setText(homeTeam.getName());
Partido.EquipoVisita awayTeam = p.getAwayTeam();
holder.awayTeam.setText(awayTeam.getName());
Stand s = dataset_stand.get(position);
Stand.Table table = (Stand.Table) s.getTable();
Stand.Table.Equipo team = (Stand.Table.Equipo) table.getEquipo();
String id_equipo = team.getId();
holder.homeTeam.setText(team.getName());
if(id_homeTeam.equals(id_equipo)){
Glide.with(context)
.load(team.getCrestUrl())
.centerCrop()
.crossFade()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(holder.team);
//holder.team.setImageDrawable(team.getCrestUrl());
}
}
#Override
public int getItemCount() {
return dataset.size()+dataset_stand.size();
}
public void adicionarListaPartidos(ArrayList<Partido> listaPartidos){
dataset.addAll(listaPartidos);
notifyDataSetChanged();
}
public void adicionarListaStands(ArrayList<Stand> listaStands){
dataset_stand.addAll(listaStands);
notifyDataSetChanged();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView status;
private TextView utcDate;
private TextView homeTeam;
private TextView awayTeam;
public ImageView team;
public ViewHolder(View itemView) {
super(itemView);
status = (TextView) itemView.findViewById(R.id.status);
utcDate = (TextView) itemView.findViewById(R.id.utcDate);
homeTeam = (TextView) itemView.findViewById(R.id.homeTeam);
awayTeam = (TextView) itemView.findViewById(R.id.awayTeam);
team = (ImageView) itemView.findViewById(R.id.team);
}
}
}
The problem comes in this line. Stand s = dataset_stand.get(position);, if a comment it with code below, It works without using the second JSON or the second request but as I showed on image I want to merge two different requests on the same RecyclerView view.
The problem statement
The problem comes in this line. Stand s = dataset_stand.get(position);, if a comment it with code below, It works without using the second JSON or the second request.
Yes, it's expected. Why? Because you're calling RecyclerView.Adapter#notifyDataSetChanged() method inside adicionarListaPartidos(ArrayList<Partido> listaPartidos) after inserting data to ArrayList in RecyclerView array adapter class which informs ArrayAdapter to redraw/refresh components inside RecyclerView container.
Now RecycelrView starts binding component within the onBindViewHolder(ListaPartidosAdapter.ViewHolder holder, int position) method. So, what's happening here?
#Override
public void onBindViewHolder(ListaPartidosAdapter.ViewHolder holder, int position) {
Partido p = dataset.get(position);
String status = p.getStatus();
if (status.equals("SCHEDULED")){
String status_ = "SCH";
holder.status.setText(status_);
}
holder.utcDate.setText(p.getUtcDate());
Partido.EquipoCasa homeTeam = p.getHomeTeam();
// other code
Stand s = dataset_stand.get(position); // <====== the problem
// other code
}
Your dataset_stand list will be empty (size of the list is 0) until you get data/response from standingsRespuestaCall.enqueue() method in your activity.
Keep in mind that Retrofit's Call#enque() method is Asynchronous. Which means in your case obtenerDatos() method executes top to bottom in a single hit. You only get data when Retrofit returns success response with onResponse() method.
The easiest way to fix this issue is to comment out the notifyDataSetChanged() method inside adicionarListaPartidos(ArrayList<Partido> listaPartidos). Like below
public void adicionarListaPartidos(ArrayList<Partido> listaPartidos){
dataset.addAll(listaPartidos);
// notifyDataSetChanged(); // <====== just COMMENT OUT this line
}
This will prevent onBindViewHolder() being called. When the second request standingsRespuestaCall.enqueue() completes it's operation, as per your code notifies dataset changed. Like below.
public void adicionarListaStands(ArrayList<Stand> listaStands){
dataset_stand.addAll(listaStands);
notifyDataSetChanged(); // <==== DO NOT remove this
}
Side Note: Your code is problematic. You're using multiple request to fill a single RecyclerView container. Your RecyclerView fails to display record if standingsRespuestaCall.enqueue() fails to get response from server.
PS: Please check method names I mentioned in my answer properly and alter the code accordingly. Do not get confused with the method names.

Realm and RecyclerView Item sorting and automatic ViewPager Fragment Communication

I'm facing a few problems for a while now which I'm having trouble to solve. So I refer to the Realm and RecyclerView geniuses among the community.
I'm woking on a ToDo-List that sets completed tasks back to the ToDo-List after 2 days. The app uses a ViewPager with two tabs: "TODO" & "DONE".
1. RecyclerView
1.1. I want the completed Tasks from fragment 1 to be sent back to fragment 0 automatically after 2 days.
The Problem: If the counter is at 0 (or below) the item gets sent to fragment 0.
If I delte the item in the next line I get an exception error: "java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling"
So I put the delete function into a handler. Then it's working BUT only if ONE gets sent back. If many items get sent back simultaneously the app crashes. When I reopen the app everything is working because it was successfully saved in realm but one item is always saved twice.
Where's the Problem (in DoneAdapter.java)?
2. Realm
2.1. When I add an Item to the RecyclerView (and simultaneously to Realm), the item gets added at the bottom. But I want to add every new item at position 0.
(I know how to achieve this wih an ArrayList, but I want the items to be stored and displayed when I reopen the app, so I'm using Realm DB.)
Do you have any suggestions to achieve this?
2.2. Is it possible to implement later on the onLongClickListener for dragging and droping items and rearranging the position with Realm?
(I want to use this https://www.youtube.com/watch?v=tNgevYpyA9E)
2.3. I want to add some nice animations when I add and check an item. Realm doesn't support mRecyclerView.setItemAnimator(...); but I heard it is possible by adding mAdapter.setHasStableIds(true);. Unfortunately it throws an Exception: java.lang.IllegalStateException: Cannot change whether this adapter has stable IDs while the adapter has registered observers. (You can see this in my code below)
Do you have any solutions for that?
(optionally 1.4. Can you recommend me any Online DBs (e.g. Firebase) which I can sync with Realm or more generally: is it possible to sync an Online DB with Realm? Do you know any Tutorials (Udemy, YouTube) for setting up this sync process?)
Lastly: I want to update the Database with a background service every Midnight, so the counter in the completed section updates automatically. Does anyone know how to do this as well? Maybe with protected void onHandleIntent(Intent intent)?
Do you also know if there's an option in debugging mode to simulate passing time?
Here is the code:
MainActivity.java
public class MainActivity extends AppCompatActivity implements ToOtherFragmentCommunicator {
private ViewPagerAdapter mViewPagerAdapter;
private ViewPager mViewPager;
private static final int DONE = 1;
private static final int TODO = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mViewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mViewPagerAdapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
mViewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
RealmConfiguration configuration = new RealmConfiguration.Builder(this).build();
Realm.setDefaultConfiguration(configuration);
}
#Override
public void itemToOtherFragment(String data, int fragment) {
if (DONE == fragment) {
Done done = (Done) mViewPagerAdapter.getItem(fragment);
done.createDoneItem(data);
} else if (TODO == fragment) {
ToDo toDo = (ToDo) mViewPagerAdapter.getItem(fragment);
toDo.createToDoItem(data);
}
}
}
ToDo.java
public class ToDo extends Fragment {
private RecyclerView mRecyclerView;
private ToDoAdapter mAdapter;
private EditText taskInput;
private String taskName;
private Realm mRealm;
private RealmResults<ListItems> mResults;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View toDoView = inflater.inflate(R.layout.todo_layout, container, false);
mRecyclerView = (RecyclerView) toDoView.findViewById(R.id.todo_rv);
mRealm = Realm.getDefaultInstance();
mResults = mRealm.where(ListItems.class).equalTo("fragment", 0).findAllAsync();
setRecyclerView();
mRecyclerView.setItemAnimator(null);
//TODO add product to shopping list
final Handler handler = new Handler();
taskInput = (EditText) toDoView.findViewById(R.id.task_input);
taskInput.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (taskInput.getText().length() > 0 && (event.getAction() == KeyEvent.ACTION_DOWN) &&
(keyCode == KeyEvent.KEYCODE_ENTER)) {
// Perform action on key press
taskName = taskInput.getText().toString();
//Problem 2.1
//Code for adding item at the top with mRealm?
mRealm.beginTransaction();
createToDoItem(taskName);
mRealm.commitTransaction();
// mRecyclerView.scrollToPosition(0);
taskInput.setText(null);
handler.postDelayed(new Runnable() {
#Override
public void run() {
taskInput.setFocusableInTouchMode(true);
taskInput.setFocusable(true);
taskInput.requestFocus();
}
}, 200);
return true;
} else if (taskInput.length() == 0 && (event.getAction() == KeyEvent.ACTION_DOWN) &&
(keyCode == KeyEvent.KEYCODE_ENTER)) {
taskInput.clearFocus();
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(taskInput.getWindowToken(), 0);
return true;
}
return false;
}
});
return toDoView;
}
//TODO creates the shopping list item in DB
public void createToDoItem(String taskName) {
ListItems item = mRealm.createObject(ListItems.class);
long now = System.currentTimeMillis();
item.setAddedTime(now);
item.setFragment(0);
item.setTaskName(taskName);
mRealm.copyToRealmOrUpdate(item);
}
public void setRecyclerView() {
mRecyclerView.setHasFixedSize(true);
LinearLayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new ToDoAdapter(getActivity(), mRealm, mResults);
mRecyclerView.setAdapter(mAdapter);
//Problem 2.3.
//Produces "java.lang.IllegalStateException: Cannot change whether this adapter has stable IDs while the adapter has registered observers."
// mAdapter.setHasStableIds(true);
}
private RealmChangeListener mChangeListener = new RealmChangeListener() {
#Override
public void onChange() {
mAdapter.updateItems(mResults);
}
};
#Override
public void onStart() {
super.onStart();
mResults.addChangeListener(mChangeListener);
}
#Override
public void onStop() {
super.onStop();
mResults.removeChangeListener(mChangeListener);
}
}
ToDoAdapter.java
public class ToDoAdapter extends RecyclerView.Adapter<ListItemsViewHolder> {
private Context mContext;
private Realm mRealm;
private RealmResults<ListItems> mResults;
private int focusedItem = 0;
ToOtherFragmentCommunicator comm;
ToDoAdapter(Context context, Realm realm, RealmResults<ListItems> mResults) {
this.mContext = context;
this.mRealm = realm;
updateItems(mResults);
}
public void updateItems(RealmResults<ListItems> mResults) {
this.mResults = mResults;
notifyDataSetChanged();
}
//Problem 2.3.
//needed for mAdapter.setHasStableIds(true); in ToDo.java
// #Override
// public long getItemId(int position) {
// if (position < mResults.size()) {
// return mResults.get(position).getAddedTime();
// } else {
// return RecyclerView.NO_ID;
// }
// }
#Override
public ListItemsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.todo_item, parent, false);
comm = (ToOtherFragmentCommunicator) mContext;
return new ListItemsViewHolder(v);
}
#Override
public void onBindViewHolder(final ListItemsViewHolder holder, final int position) {
final ListItems items = mResults.get(position);
holder.taskName.setText(items.getTaskName());
holder.itemView.setSelected(focusedItem == position);
holder.getLayoutPosition();
holder.itemCheckbox.setOnCheckedChangeListener(null);
holder.itemCheckbox.setChecked(items.isSelected());
holder.itemCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
mRealm.beginTransaction();
items.setSelected(isChecked);
//send item to Done
comm.itemToOtherFragment(items.getTaskName(), 1);
removeItem(position);
mRealm.commitTransaction();
}
});
}
#Override
public int getItemCount() {
return (mResults != null ? mResults.size() : 0);
}
private void removeItem(int position) {
mResults.get(position).removeFromRealm();
notifyDataSetChanged();
}
}
Done.java
public class Done extends Fragment {
private RecyclerView mRecyclerView;
private DoneAdapter mAdapter;
private Calendar calendar = Calendar.getInstance();
private Date date = new Date();
private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd.MM.yyyy");
private Realm mRealm;
private RealmResults<ListItems> mResults;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View doneView = inflater.inflate(R.layout.done_layout, container, false);
mRecyclerView = (RecyclerView) doneView.findViewById(R.id.done_rv);
mRealm = Realm.getDefaultInstance();
mResults = mRealm.where(ListItems.class).equalTo("fragment", 1).findAllAsync();
setRecyclerView();
mRecyclerView.setItemAnimator(null);
return doneView;
}
//TODO creates the fridge item in DB
public void createDoneItem(String taskName) {
TimeZone.getDefault();
ListItems item = mRealm.createObject(ListItems.class);
long now = System.currentTimeMillis();
item.setAddedTime(now);
item.setFragment(1);
item.setTaskName(taskName);
item.setInputDate(simpleDateFormat.format(calendar.getTime()));
calendar.add(Calendar.DATE, 2);
item.setRenewDate(simpleDateFormat.format(calendar.getTime()));
//reset time to current date after adding days
calendar.setTime(date);
item.getRenewDate();
mRealm.copyToRealmOrUpdate(item);
}
public void setRecyclerView() {
mRecyclerView.setHasFixedSize(true);
LinearLayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new DoneAdapter(getActivity(), mRealm, mResults, Done.this);
mRecyclerView.setAdapter(mAdapter);
}
private RealmChangeListener mChangeListener = new RealmChangeListener() {
#Override
public void onChange() {
mAdapter.updateItems(mResults);
}
};
#Override
public void onStart() {
super.onStart();
mResults.addChangeListener(mChangeListener);
}
#Override
public void onStop() {
super.onStop();
mResults.removeChangeListener(mChangeListener);
}
}
DoneAdapter.java
public class DoneAdapter extends RecyclerView.Adapter<ListItemsViewHolder> {
private Context mContext;
private Done done;
private Realm mRealm;
private RealmResults<ListItems> mResults;
private int focusedItem = 0;
protected ToOtherFragmentCommunicator comm;
DoneAdapter(Context context, Realm realm, RealmResults<ListItems> results, Done done) {
this.mContext = context;
this.mRealm = realm;
this.done = done;
updateItems(results);
}
public void updateItems(RealmResults<ListItems> mResults) {
this.mResults = mResults;
notifyDataSetChanged();
}
#Override
public ListItemsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.done_item, parent, false);
comm = (ToOtherFragmentCommunicator) mContext;
return new ListItemsViewHolder(v);
}
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
#Override
public void onBindViewHolder(final ListItemsViewHolder holder, final int position) {
final ListItems items = mResults.get(position);
holder.taskName.setText(items.getTaskName());
try {
if (items.getRenewCounter() == 1) {
holder.renewCounter.setText(mContext.getString(R.string.show_days_till_renew, items.getRenewCounter(), mContext.getString(R.string.day)));
} else {
holder.renewCounter.setText(mContext.getString(R.string.show_days_till_renew, items.getRenewCounter(), mContext.getString(R.string.days)));
}
holder.renewCounter.setTextColor(ContextCompat.getColor(mContext, R.color.colorAccent));
if (items.getRenewCounter() <= 0) {
mRealm.beginTransaction();
//Problem 1.1.
//send item back to todo list
comm.itemToOtherFragment(items.getTaskName(), 0);
// Produces "java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling" if there is no Handler
Handler handler = new Handler();
final Runnable r = new Runnable() {
public void run() {
mRealm.beginTransaction();
removeItem(position);
mRealm.commitTransaction();
}
};
handler.post(r);
mRealm.commitTransaction();
}
} catch (ParseException e) {
e.printStackTrace();
}
holder.itemView.setSelected(focusedItem == position);
holder.getLayoutPosition();
}
#Override
public int getItemCount() {
return (mResults != null ? mResults.size() : 0);
}
private void removeItem(int position) {
mResults.get(position).removeFromRealm();
notifyDataSetChanged();
}
}
ListItems.java
public class ListItems extends RealmObject {
public ListItems(long addedTime, String taskName, String inputDate, String renewDate, int fragment) {
this.addedTime = addedTime;
this.taskName = taskName;
this.inputDate = inputDate;
this.renewDate = renewDate;
this.fragment = fragment;
}
#PrimaryKey
private long addedTime;
private int fragment;
#Ignore
private long renewCounter;
private String taskName, inputDate, renewDate;
private boolean selected;
public ListItems() {
}
public long getAddedTime() {
return addedTime;
}
public void setAddedTime(long addedTime) {
this.addedTime = addedTime;
}
public int getFragment() {
return fragment;
}
public void setFragment(int fragment) {
this.fragment = fragment;
}
public String getTaskName() {
return taskName;
}
public void setTaskName(String taskName) {
this.taskName = taskName;
}
public String getInputDate() {
return inputDate;
}
public void setInputDate(String inputDate) {
this.inputDate = inputDate;
}
public String getRenewDate() {
return renewDate;
}
public void setRenewDate(String renewDate) {
this.renewDate = renewDate;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
public long getRenewCounter() throws ParseException {
TimeZone.getDefault();
SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy");
Date todayDate = new Date();
Date exDate = dateFormat.parse(renewDate);
this.renewCounter = daysBetween(todayDate, exDate);
return renewCounter;
}
private static long daysBetween(Date startDate, Date endDate) {
Calendar sDate = getDatePart(startDate);
Calendar eDate = getDatePart(endDate);
long daysBetween = 0;
while (sDate.before(eDate)) {
sDate.add(Calendar.DAY_OF_MONTH, 1);
daysBetween++;
}
while (eDate.before(sDate)) {
eDate.add(Calendar.DAY_OF_MONTH, 1);
daysBetween--;
}
return daysBetween;
}
private static Calendar getDatePart(Date date) {
Calendar cal = Calendar.getInstance(); // get calendar instance
cal.setTime(date);
cal.set(Calendar.HOUR_OF_DAY, 0); // set hour to midnight
cal.set(Calendar.MINUTE, 0); // set minute in hour
cal.set(Calendar.SECOND, 0); // set second in minute
cal.set(Calendar.MILLISECOND, 0); // set millisecond in second
return cal; // return the date part
}
}
Here's a Screenshot on how the app looks like:
DailyTaskRepeater
That's it! It would mean the world to me if someone could help me with all that (especially Problem 1.1!).
Thank you!
The current practice Realm supports is to add an index (e.g. timestamp) and to reverse sort your list for having the latest item at the top and achiving the rearranging effect you are seeking for.
Please consider taking a reference from an adapter example provided in the official repository.

UnsupportedOperationException when adding element to List (no Arrays.asList)

I cant figure out whats the problem here. Im trying to add an Object "idea" from type Idea to the list ideaList. And then it throws this exception. Anyone knows?
java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:404)
at java.util.AbstractList.add(AbstractList.java:425)
at smoca.ch.kreagen.Fragments.VotingFragment.(VotingFragment.java:50)
at smoca.ch.kreagen.FragmentStateHandler.chooseAndShowForVoting(FragmentStateHandler.java:69)
at smoca.ch.kreagen.Adapters.ArchiveAdapter$1.onClick(ArchiveAdapter.java:50)
at android.view.View.performClick(View.java:5155)
I want to add it after the list has been created and filled by realm-data.
right in the first constructor with Idea as param.
Class-Code:
public class VotingFragment extends Fragment implements VotingAdapter.ClickListener{
private RecyclerView recyclerView;
private VotingAdapter votingAdapter;
private Realm realm;
private List<Idea> ideaList;
private List<Vote> voteList;
private List<Owner> ownerList;
private FragmentStateHandler fragmentStateHandler;
private TextView status;
private Button startVoting;
private Button stopVoting;
public VotingFragment(Idea idea) {
getData();
ideaList.add(idea);
setStatus(true);
}
public VotingFragment() {
getData();
setStatus(false);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
super.onCreateView(inflater, container, savedInstanceState);
View layout = inflater.inflate(R.layout.voting_fragment_layout, container, false);
recyclerView = (RecyclerView) layout.findViewById(R.id.votingDrawerList);
realm = Realm.getInstance(getActivity());
fragmentStateHandler = FragmentStateHandler.getInstance();
// get buttons and views
status = (TextView) layout.findViewById(R.id.statusTextView);
startVoting = (Button) layout.findViewById(R.id.startButton);
stopVoting = (Button) layout.findViewById(R.id.stopButton);
// clicklisteners for start/stop
startVoting.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
setStatus(true);
// put ideas in List
// put votes in List
// put Owners in List
// sort Voting
// set timestamp (24h)
}
});
stopVoting.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
setStatus(false);
// clear ideas from List
// put voting in History
}
});
votingAdapter = new VotingAdapter(getActivity(), ideaList, voteList, ownerList); // params: context, idealist, votelist, ownerlist
votingAdapter.setClickListener(this); // set clicklistener on this
recyclerView.setAdapter(votingAdapter);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
return layout;
}
public void getData() {
ideaList = Collections.emptyList();
voteList = Collections.emptyList();
ownerList = Collections.emptyList();
try {
RealmQuery<Idea> ideaQuery = realm.where(Idea.class);
RealmResults<Idea> ideaQueryResult = ideaQuery.findAll();
RealmQuery<Vote> voteQuery = realm.where(Vote.class);
RealmResults<Vote> voteQueryResult = voteQuery.findAll();
RealmQuery<Owner> ownerQuery = realm.where(Owner.class);
RealmResults<Owner> ownerQueryResult = ownerQuery.findAll();
ideaList = ideaQueryResult;
voteList = voteQueryResult;
ownerList = ownerQueryResult;
} catch (Exception e) { e.printStackTrace();}
Log.d("joris", "" + ideaList);
Log.d("joris", "" + voteList);
Log.d("joris", "" + ownerList);
}
// items clicked in recyclerview
#Override
public void itemClicked(View view, int position) {
Idea current = ideaList.get(position);
fragmentStateHandler.showIdeaFrag(current);
}
public void setStatus(boolean val) {
if(val) {
status.setText("OPEN");
status.setTextColor(getResources().getColor(R.color.Green));
} else {
status.setText("CLOSED");
status.setTextColor(getResources().getColor(R.color.Red));
}
}
}
You can't modify the Lists you get back as RealmResult
Instead you probably want to copy the results of your queries to get mutable lists.
Something like
ideaList = new ArrayList<>();
voteList = Collections.emptyList();
ownerList = Collections.emptyList();
try {
RealmQuery<Idea> ideaQuery = realm.where(Idea.class);
RealmResults<Idea> ideaQueryResult = ideaQuery.findAll();
RealmQuery<Vote> voteQuery = realm.where(Vote.class);
RealmResults<Vote> voteQueryResult = voteQuery.findAll();
RealmQuery<Owner> ownerQuery = realm.where(Owner.class);
RealmResults<Owner> ownerQueryResult = ownerQuery.findAll();
ideaList.addAll(ideaQueryResult);
voteList = voteQueryResult;
ownerList = ownerQueryResult;
} catch (Exception e) { e.printStackTrace();}
As you see you can no longer use the Collections.emptyList as default value as it is immutable, and instead of using the ideaQueryResult directly we copy all the elements from the list to our own mutable ArrayList.

Categories

Resources