I have a view pager with an adapter that has a number of items fetched from the cloud. I add the pages to the adapter through the fragment.
I am trying to pass a variable to the Item's view model every time a new page is instantiated from the adapter so as to notify one of the views that depend on this view model. I have tried a few workarounds but nothing has been successful so far. Would anyone please advice how I may pass this data.
Below is my adapter
public class HelpPagerAdapter extends PagerAdapter {
private final List<HelpPage> mHelpPages;
private int currentPage = 0;
public HelpPagerAdapter(Context context) {
mPages = new ArrayList<>();
}
#Override
public int getCount() {
return mHelpPages.size();
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
HelpPage helpPage = mHelpPages.get(position);
currentPage = position;
LayoutInflater inflater = (LayoutInflater) container.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ViewDataBinding binding = DataBindingUtil.inflate(inflater, helpPage.getLayout(), container, false);
binding.setVariable(helpPage.getViewModelBindingId(), helpPage.getViewModel());
container.addView(binding.getRoot());
return binding.getRoot();
}
public void addPage(#LayoutRes int layout, Object viewModel, int viewModelBindingId) {
mHelpPages.add(new HelpPage(layout, viewModel, viewModelBindingId));
}
private class HelpPage {
private final #LayoutRes int mLayout;
private final Object mViewModel;
private final int mViewModelBindingId;
HelpPage(#LayoutRes int layout, Object viewModel, int viewModelBindingId) {
mLayout = layout;
mViewModel = viewModel;
mViewModelBindingId = viewModelBindingId;
}
#LayoutRes int getLayout() {
return mLayout;
}
Object getViewModel() {
return mViewModel;
}
int getViewModelBindingId() {
return mViewModelBindingId;
}
}
}
Part of my fragment code
#Override
public void onAttach(Context context) {
super.onAttach(context);
Bundle bundle = getArguments();
if (bundle == null || (!bundle.containsKey(ARG_STEPS) && !bundle.containsKey(ARG_VIEWS))) {
throw new IllegalStateException("HelpFragment cannot be initialised without views");
}
HelpPagerAdapter adapter = new HelpPagerAdapter(getContext());
if (bundle.containsKey(ARG_STEPS)) {
List<Step> steps = Parcels.unwrap(bundle.getParcelable(ARG_STEPS));
adapter = addHelpPages(steps, adapter);
}
mHelpViewModel = new HelpViewModel(adapter);
}
private HelpPagerAdapter addHelpPages(List<Step> steps, HelpPagerAdapter adapter) {
for (Step step : steps) {
adapter.addPage(R.layout.layout_help, new HelpItemViewModel(step), BR.viewModel);
}
return adapter;
}
Part of my ViewModel
public class HelpItemViewModel {
private final String mText;
private final String mVideoId;
private final String mImageUrl;
public HelpItemViewModel(Step step) {
mText = step.getText();
mHelpId = step.getHelpId();
mImageUrl = step.getImage();
}
}
Related
Recently I have created RecyclerView with Multiple ViewTypes followed this video. In the video the lecturer followed the traditional method of sending data using ArrayList In MainAvtivity. But when I used ViewModel and Retrofit it is not passing any data and nothing show in the screen.
And here an expiation of what I have done.
First:
I have 3 diffrents types of views so I created a 3 model classes for each view called (FirstImageModel,LiveModel,DailyImageModel).
FirstImageModel class -- All other 2 classes have same stretcher.
public class FirstImageModel {
#SerializedName("firstImageUrl")
private String firstImageUrl;
public FirstImageModel(String firstImageUrl) {
this.firstImageUrl = firstImageUrl;
}
public String getFirstImageUrl() {
return firstImageUrl;
}
public void setFirstImageUrl(String firstImageUrl) {
this.firstImageUrl = firstImageUrl;
}
and I have created a fourth class called ItemModel that have type int and Object object.
public class ItemModel {
private int type;
private Object object;
public ItemModel(int type) {
this.type = type;
this.object = object;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public Object getObject() {
return object;
}
public void setObject(Object object) {
this.object = object;
}
}
Second:
I have created Adapter class called HomeAdapter that extends from RecyclerView and I made 3 classes for eatch view inside the same class HomeAdapter.
public class HomeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<ItemModel> items;
public HomeAdapter(List<ItemModel> items) {
this.items = items;
}
public void setHomeList(List<ItemModel> items) {
this.items = items;
notifyDataSetChanged();
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
// Here is types are: 0-FirstImage, 1-Live, 2-DailyImage
if (viewType == 0) {
return new FirstImageViewHolder(
LayoutInflater.from(parent.getContext()).inflate(
R.layout.item_home_container_firstimage,
parent,
false
)
);
} else if (viewType == 1) {
return new LiveViewHolder(
LayoutInflater.from(parent.getContext()).inflate(
R.layout.item_home_container_live,
parent,
false
)
);
} else {
return new DailyImageViewHolder(
LayoutInflater.from(parent.getContext()).inflate(
R.layout.item_home_container_dailyimage,
parent,
false
)
);
}
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
if (getItemViewType(position) == 0) {
FirstImageModel firstImageModel = (FirstImageModel) items.get(position).getObject();
((FirstImageViewHolder) holder).setFirstImageData(firstImageModel);
} else if (getItemViewType(position) == 1) {
LiveModel liveModel = (LiveModel) items.get(position).getObject();
((LiveViewHolder) holder).setLiveImageData(liveModel);
} else {
DailyImageModel dailyImageModel = (DailyImageModel) items.get(position).getObject();
((DailyImageViewHolder) holder).setDailyImageData(dailyImageModel);
}
}
#Override
public int getItemCount() {
if(this.items != null) {
return this.items.size();
}
return 0;
}
#Override
public int getItemViewType(int position) {
return items.get(position).getType();
}
/* firstImage Adapter */
static class FirstImageViewHolder extends RecyclerView.ViewHolder {
private ImageView firstImage;
FirstImageViewHolder(#NonNull View itemView) {
super(itemView);
firstImage = itemView.findViewById(R.id.image_home_firstImage);
}
void setFirstImageData(FirstImageModel firstImageModel) {
Glide.with(itemView.getContext())
.load(firstImageModel.getFirstImageUrl())
.into(firstImage);
}
}
/* Live Adapter */
static class LiveViewHolder extends RecyclerView.ViewHolder {
private ImageView liveImage;
LiveViewHolder(#NonNull View itemView) {
super(itemView);
liveImage = itemView.findViewById(R.id.image_home_liveImage);
}
void setLiveImageData(LiveModel liveModel) {
Glide.with(itemView.getContext())
.load(liveModel.getImageLiveInfoUrl())
.into(liveImage);
}
}
/* DailyImage Adapter */
static class DailyImageViewHolder extends RecyclerView.ViewHolder {
private ImageView dailyImage;
DailyImageViewHolder(#NonNull View itemView) {
super(itemView);
dailyImage = itemView.findViewById(R.id.image_home_dailyImage);
}
void setDailyImageData(DailyImageModel dailyImageModel) {
Glide.with(itemView.getContext())
.load(dailyImageModel.getDailyImageUrl())
.into(dailyImage);
}
}
My Problem:
When I use Retrofit to load the data, I don't Know how to pass the 3 views types data to the RecyclerView using ViewModel. My ViewModel class.
public class HomeViewModel extends ViewModel {
private MutableLiveData<List<ItemModel>> homeObjectsList;
private Call<List<ItemModel>> call;
public HomeViewModel(){
homeObjectsList = new MutableLiveData<>();
}
public MutableLiveData<List<ItemModel>> getHomeItemsListObserver() {
return homeObjectsList;
}
public void makeApiCallHome() {
APIServiceHome apiServiceHome = RetroInstanceHome.getRetroClientHome().create(APIServiceHome.class);
call = apiServiceHome.getHomeObjectsList();
call.enqueue(new Callback<List<ItemModel>>() {
#Override
public void onResponse(Call<List<ItemModel>> call, Response<List<ItemModel>> response) {
homeObjectsList.postValue(response.body());
}
#Override
public void onFailure(Call<List<ItemModel>> call, Throwable t) {
homeObjectsList.postValue(null);
}
});
}
Also here's my fragment that should dislay the data in RecyclerView.
public class HomeFragment extends Fragment {
View rootView;
RecyclerView recyclerView;
private List<ItemModel> itemModelList;
private HomeViewModel viewModel;
private HomeAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_home, container, false);
initializeContent();
initializeViewModel();
return rootView;
}
private void initializeContent() {
recyclerView = rootView.findViewById(R.id.recyclerView_home);
recyclerView.setAdapter(new HomeAdapter(itemModelList));
}
private void initializeViewModel() {
ProgressBar progressBar = rootView.findViewById(R.id.progress_bar_home);
viewModel = ViewModelProviders.of(this).get(HomeViewModel.class);
viewModel.getHomeItemsListObserver().observe(getActivity(), new Observer<List<ItemModel>>() {
#Override
public void onChanged(List<ItemModel> itemModels) {
if(itemModels != null) {
progressBar.setVisibility(View.GONE);
itemModelList = itemModels;
adapter.setHomeList(itemModels);
}
}
});
viewModel.makeApiCallHome();
}
I hope this explanation was clear to show the problem. Waiting for your answer
As I fetched and show the dates (see image) as the title of the main recyclerview. I want to show the available slots data instead of the 0 1 2 etc elements. The code is attached below
Url for json data
https://run.mocky.io/v3/c9bd7858-0e41-422f-b1d2-cd490c08583b
AppointmentTimeActivity.java
public class AppointmentTimeActivity extends AppCompatActivity {
SharedPrefManager sharedPrefManager;
Button appointmentTimeButton;
private TextView doctorFullName;
ConstraintLayout constraintLayout;
public static List<List<String>> availableSlots;
RecyclerView rvGroup;
public static ArrayList<String> arrayListGroup;
LinearLayoutManager layoutManagerGroup;
GroupAdapter groupAdapter;
private DoctorScheduleResponse timings;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.select_appointment_time);
getSupportActionBar().setTitle("Appointment time");
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
sharedPrefManager = new SharedPrefManager(this);
constraintLayout = findViewById(R.id.constraintLayout);
appointmentTimeButton = findViewById(R.id.book_video_call_appointment_btn);
doctorFullName = findViewById(R.id.doctor_full_name);
rvGroup = findViewById(R.id.rv_group);
String docName = getIntent().getStringExtra("doctorFullName");
doctorFullName.setText(docName);
arrayListGroup = new ArrayList<>();
fetchAndShowAppointmentsTime();
}
private void fetchAndShowAppointmentsTime() {
String id = String.valueOf(SpecialityActivity.doctorID);
Call<DoctorScheduleResponse> call = RetrofitClient.getInstance().getMyInterface().getAppointmentTime("Bearer " + sharedPrefManager.getAccessToken(), id);
call.enqueue(new Callback<DoctorScheduleResponse>() {
#Override
public void onResponse(#NotNull Call<DoctorScheduleResponse> call, #NotNull Response<DoctorScheduleResponse> response) {
arrayListGroup = new ArrayList<>();
if (response.isSuccessful()) {
assert response.body() != null;
for (List<Slot> slots : response.body().getSlot()) {
for (Slot slot : slots) {
arrayListGroup.add(slot.getScheduleDate());
}
}
groupAdapter = new GroupAdapter(AppointmentTimeActivity.this, response.body().getSlot());
layoutManagerGroup = new LinearLayoutManager(getApplicationContext());
rvGroup.setLayoutManager(layoutManagerGroup);
rvGroup.setAdapter(groupAdapter);
}
}
#Override
public void onFailure(#NotNull Call<DoctorScheduleResponse> call, #NotNull Throwable t) {
Toast.makeText(getBaseContext(), t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
DoctorScheduleResponse.java
public class DoctorScheduleResponse {
#SerializedName("slot")
#Expose
private List<List<Slot>> slot = null;
public List<List<Slot>> getSlot() {
return slot;
}
public void setSlot(List<List<Slot>> slot) {
this.slot = slot;
}
}
GroupAdater.java
public class GroupAdapter extends RecyclerView.Adapter<GroupAdapter.ViewHolder> {
private Activity activity;
ArrayList<String> arrayListGroup, arrayListMember;
LinearLayoutManager linearLayoutManager;
SharedPrefManager sharedPrefManager;
List<List<Slot>> slotsList;
public GroupAdapter(Activity activity, ArrayList<String> arrayListGroup) {
this.activity = activity;
this.arrayListGroup = arrayListGroup;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.custom_slot_layout, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.dummyTV.setText(arrayListGroup.get(position));
arrayListMember = new ArrayList<>();
sharedPrefManager = new SharedPrefManager(activity);
for (int i = 0; i < 5; i++) {
arrayListMember.add(String.valueOf(i));
}
CustomAdapter customAdapter = new CustomAdapter(arrayListMember);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(activity);
holder.rvMember.setLayoutManager(linearLayoutManager);
holder.rvMember.setAdapter(customAdapter);
}
#Override
public int getItemCount() {
return arrayListGroup.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView dummyTV;
RecyclerView rvMember;
public ViewHolder(#NonNull View itemView) {
super(itemView);
dummyTV = itemView.findViewById(R.id.dummyTextView);
rvMember = itemView.findViewById(R.id.rv_member);
}
}
}
CustomAdapter.java
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.SlotsViewHolder> {
ArrayList<String> slots;
public CustomAdapter(ArrayList<String> slots) {
this.slots = slots;
}
#NonNull
#Override
public SlotsViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.available_slots_list, parent, false);
return new CustomAdapter.SlotsViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull SlotsViewHolder holder, int position) {
holder.tvSlots.setText(slots.get(position));
}
#Override
public int getItemCount() {
return slots.size();
}
public class SlotsViewHolder extends RecyclerView.ViewHolder {
TextView tvSlots;
public SlotsViewHolder(#NonNull View itemView) {
super(itemView);
tvSlots = itemView.findViewById(R.id.tv_slots);
}
}
}
Nested recycler view will be more complex in terms of memory. So you can achieve same UI with different approach.
You should try with single recycler view with dynamic layout binding.
Example: For single item of recycler view, there will be a header(for date) and a viewgroup(may be linear layout) then bind any no. of child views inside that linear layout.
The problem is in GroupAdater.java. Inside onBindViewHolder method you are adding the value of loop variable to your list that you pass to your nested recycler view adaptor.
for (int i = 0; i < 5; i++) {
arrayListMember.add(String.valueOf(i));
}
You have to add the correct date from arrayListGroup object.
I have 3 RecyclerView to display most visited market, close by markets and favorite markets.
I have created 3 difference instance of MarketAdapter class for the three RecyclerView
Everything works fine, but my Activity implements one OnClickListener and I cant figure out which adapter was clicked. Is it possible to programmatically determine the Adapter that was clicked from the OnClickListener?
Here is my MarketAdapter Class
public class MarketAdapter extends RecyclerView.Adapter<MarketAdapter.ViewHolder> {
ArrayList<Markets> mMarket = new ArrayList<>();
Context mContext;
private final MarketsItemsClickListener mItemsClickListener;
private final MarketLongClickListener mLongClickListener;
private final MarketClickListener mClickListener;
public MarketAdapter(Context context, MarketsItemsClickListener itemsClickListener, MarketClickListener clickListener, MarketLongClickListener longClickListener){
mContext = context;
mItemsClickListener = itemsClickListener;
mLongClickListener = longClickListener;
mClickListener = clickListener;
}
public interface MarketLongClickListener{
void onLongClick(int position);
}
public interface MarketClickListener{
void onClick(int position);
}
public interface MarketsItemsClickListener{
void imageViewOnClickListener(View view, int position);
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
Context context = viewGroup.getContext();
int layoutForListItem = R.layout.list_market;
LayoutInflater inflater = LayoutInflater.from(context);
boolean shouldAttachToParentImmediately = false;
View view = inflater.inflate(layoutForListItem, viewGroup, shouldAttachToParentImmediately);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder viewHolder, int i) {
viewHolder.bindView(i);
}
#Override
public int getItemCount() {
if(mMarket != null) return mMarket.size();
return 0;
}
public void setData(ArrayList<Markets> markets){
mMarket = markets;
notifyDataSetChanged();
}
public void addData(Markets market, int position){
mMarket.add(0, market);
notifyDataSetChanged();
}
public Markets getItem(int position){return mMarket.get(position);}
class ViewHolder extends RecyclerView.ViewHolder implements View.OnLongClickListener, View.OnClickListener{
ImageView mImageView;
TextView mNameTextView, mCityTextView;
public ViewHolder(#NonNull View itemView) {
super(itemView);
mImageView = itemView.findViewById(R.id.image_view);
mNameTextView = itemView.findViewById(R.id.name_text_view);
mCityTextView = itemView.findViewById(R.id.city_text_view);
itemView.setOnLongClickListener(this);
itemView.setOnClickListener(this);
}
void bindView(int position){
Markets market = getItem(position);
mCityTextView.setText(market.getCity());
mNameTextView.setText(market.getName());
}
#Override
public void onClick(View v) {
//Get position of Adapter
int position = getAdapterPosition();
//Handle the click
mClickListener.onClick(position);
}
#Override
public boolean onLongClick(View v) {
return false;
}
}
}
and OnClickListener from Activity
#Override
public void onClick(int position) {}
You can pass a tag in the constructor and get that tag back via a click listener to identify the click as
private final MarketsItemsClickListener mItemsClickListener;
private final MarketLongClickListener mLongClickListener;
private final MarketClickListener mClickListener;
private final String mTag;
public MarketAdapter(Context context, MarketsItemsClickListener itemsClickListener, MarketClickListener clickListener, MarketLongClickListener longClickListener, String tag){
mTag = tag
mContext = context;
mItemsClickListener = itemsClickListener;
mLongClickListener = longClickListener;
mClickListener = clickListener;
}
Modify the listener as
public interface MarketClickListener{
void onClick(int position, String tag);
}
and the listener code in activity as
#Override
public void onClick(int position, String tag) {
switch(tag){
case "adapter1":
break;
case "adapter2":
break;
case "adapter3":
break;
}
}
and create adapter object as
MarketAdapter adapter = new MarketAdapter("adapter1"....);
MarketAdapter adapter1 = new MarketAdapter("adapter2"....);
MarketAdapter adapter2 = new MarketAdapter("adapter3"....);
and use
mClickListener.onClick(position, mTag);
Note: You can use enums as well
You can add a attribute inside MarketAdapter so that you can tell what instance is that adapter.
Change your custom click listener to receive the adapter type:
public interface MarketClickListener {
//You can change this to receive any data you want from the adapter
void onClick(int position, int adapterType);
}
Add the constants, the identifier attribute and change the listener in your adatper:
public class MarketAdapter extends RecyclerView.Adapter<MarketAdapter.ViewHolder> {
//The constants types
public static int MOST_VISITED_MARKETS = 1;
public static int CLOSE_BY_MARKETS = 2;
public static int FAVORITE_MARKETS = 3;
//New attribute
private int adapterType;
...
//Keep the listener
private final MarketClickListener mClickListener;
public MarketAdapter(Context context, MarketsItemsClickListener itemsClickListener, MarketClickListener clickListener, MarketLongClickListener longClickListener, int adapterType){
...
//Set the type
adapterType = adapterType;
}
...
}
In your activity:
mostVisitedRecyclerView.setAdapter(new MarketAdapter(this,itemsClickListener,clickListener,longClickListener,MarketAdapter.MOST_VISITED_MARKETS ));
closeByRecyclerView.setAdapter(new MarketAdapter(this,itemsClickListener,clickListener,longClickListener,MarketAdapter.CLOSE_BY_MARKETS));
favoritesRecyclerView.setAdapter(new MarketAdapter(this,itemsClickListener,clickListener,longClickListener,MarketAdapter.FAVORITE_MARKETS));
In your view holder, change the onClick:
#Override
public void onClick(View v) {
//Get position of Adapter
int position = getAdapterPosition();
//Handle the click
mClickListener.onClick(position,adapterType);
}
I didn't test this but I think it will do the trick. Try it out.
If you want to do it this way, I would add a new variable to the adapters constructor, and then use a case/if statement to determine what you want to do in your onbindviewholder.
Guys please dont make this question as a duplicate as I have not found any simple or easy implementation of realm in my app. I am in the process of creating a chat app and what I want to do is make it possible for the user to be able to access and read earlier messages that he received even without internet connection.
In short I want my app to be still accessible without an internet connection but am finding it difficult doing that as am new to local data storage.
Below are my codes for your perusal:
Fragment
public class ChatFragment extends Fragment {
public RecyclerView mChatsList;
public View mView;
public List<ChatsModel> mChatsModel;
public ChatsAdapter mChatsAdapter;
private Realm realm;
public ChatFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
mView = inflater.inflate(R.layout.fragment_chat, container, false);
((AppCompatActivity) getActivity()).getSupportActionBar().setShowHideAnimationEnabled(true);
initUI();
realm = Realm.getDefaultInstance();
return mView;
}
//Method and views initializer
public void initUI() {
mChatsList = (RecyclerView) mView.findViewById(R.id.chatsList);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
mChatsModel = new ArrayList<ChatsModel>();
mChatsAdapter = new ChatsAdapter(getActivity(), mChatsModel);
mChatsList.setLayoutManager(layoutManager);
mChatsList.setHasFixedSize(true);
mChatsAdapter.notifyDataSetChanged();
mChatsList.setAdapter(mChatsAdapter);
RecyclerView.ItemAnimator itemAnimator = new DefaultItemAnimator();
itemAnimator.setAddDuration(1000);
itemAnimator.setRemoveDuration(1000);
mChatsList.setItemAnimator(itemAnimator);
prepareItems();
Realm realm = Realm.getInstance(getActivity());
realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
ChatsModel chat = realm.createObject(ChatsModel.class);
chat.setUsername("username");
chat.setDate("date");
chat.setPicture("Picture");
}
}, new Realm.Transaction.Callback() {
#Override
public void onSuccess() {
Main.Mess(getString(R.string.real_sucess));
}
#Override
public void onError(Exception e) {
Main.Mess(getString(R.string.real_error));
}
});
}
// This is a simple method to add items to our recyclerview
private void prepareItems() {
Rests mRests = RestService.createService(Rests.class, Session.getToken(getActivity()));
mRests.suggest(new Callback<List<ChatsModel>>() {
#Override
public void success(List<ChatsModel> mChatsModel, Response response) {
RealmList<ChatsModel> mChatsModel2 = new RealmList<ChatsModel>();
mChatsAdapter.setUsers(mChatsModel);
}
#Override
public void failure(RetrofitError error) {
Main.Mess(getString(R.string.server_error));
}
});
}
}
My Adapter
public class ChatsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int TYPE_HEADER = 0;
private static final int TYPE_ITEM = 1;
private RealmList<ChatsModel> mChatsModel;
private Realm realm;
public Activity mActivity;
public ChatsAdapter(#NonNull Activity mActivity) {
super();
this.mChatsModel = new RealmList<>();
this.realm = Realm.getDefaultInstance();
this.mActivity = mActivity;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder (ViewGroup parent, int viewType) {
if(viewType == TYPE_HEADER) {
View v = LayoutInflater.from (parent.getContext ()).inflate (R.layout.ad_view, parent, false);
return new HeaderViewHolder (v);
} else if(viewType == TYPE_ITEM) {
View v = LayoutInflater.from (parent.getContext ()).inflate (R.layout.chats_item, parent, false);
return new ContentViewHolder (v);
}
return null;
}
private ChatsModel getItem (int position) {
return mChatsModel.get (position);
}
#Override
public void onBindViewHolder (RecyclerView.ViewHolder holder, final int position) {
if (holder instanceof HeaderViewHolder) {
HeaderViewHolder headerHolder = (HeaderViewHolder) holder;
if (Constant.SHOW_ADS) {
headerHolder.mAdView.setVisibility(View.VISIBLE);
AdRequest adRequest = new AdRequest.Builder().build();
headerHolder.mAdView.loadAd(adRequest);
} else {
headerHolder.mAdView.setVisibility(View.GONE);
}
}else if (holder instanceof ContentViewHolder) {
ContentViewHolder contentHolder = (ContentViewHolder) holder;
ChatsModel item = getItem (position - 1);
contentHolder.username.setText(item.getUsername());
contentHolder.date.setText(item.getDate());
contentHolder.message.setText(item.getMessage());
Picasso.with(mActivity.getApplicationContext())
.load(Constant.IMAGE_SMALL + item.getPicture())
.error(R.drawable.user)
.into(contentHolder.picture);
}
}
#Override
public int getItemViewType (int position) {
if(isPositionHeader (position)) {
return TYPE_HEADER;
}
return TYPE_ITEM;
}
public void setUsers(RealmList<ChatsModel> friendsItems) {
this.mChatsModel = friendsItems;
notifyDataSetChanged();
}
public List<ChatsModel> getSuggestionsModel() {
return this.mChatsModel;
}
private boolean isPositionHeader (int position) {
return position == 0;
}
#Override
public int getItemCount () {
return mChatsModel.size ();
}
public class HeaderViewHolder extends RecyclerView.ViewHolder {
public AdView mAdView;
public HeaderViewHolder(View itemView) {
super(itemView);
mAdView = (AdView) itemView.findViewById(R.id.ad_view);
}
}
public class ContentViewHolder extends RecyclerView.ViewHolder {
public ImageView picture;
public TextView username, date, message;
public LinearLayout chat;
public ContentViewHolder(View v) {
super(v);
picture = (ImageView) v.findViewById(R.id.picture);
username = (TextView) v.findViewById(R.id.username);
date = (TextView) v.findViewById(R.id.date);
message = (TextView) v.findViewById(R.id.message);
}
}
}
Okay so thats my code.
You can use a SQLite database for storing the chats offline, watch this YouTube tutorial, it is extensive but you can skip through some parts.
When downloading/sending chat messages, mirror them into your database and use the database and ONLY THE DATABASE as the data source for your RecyclerView (never let any online data directly go into the list, always store it in the database first and read it from the database when putting it into your layout).
To improve performance, you can store relevant chat messages in memory (in a separate ArrayList for example) instead of always reading data from the DB that you just wrote into it.
As #geisshirt says in comment, use RealmRecyclerViewAdapter instead of RecyclerView.Adapter. Couple words about android realm adapters you can found in official doc.
Also, you can look at RealmRecyclerViewAdapter example
How can I implement an Activity with page_ two? What can I do?
Here's an example:
So far, my activity code looks like this:
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
viewPager.setAdapter(new CustomPagerAdapter(this));
CustomPagerAdapter.java
public class CustomPagerAdapter extends PagerAdapter {
private Context mContext;
public CustomPagerAdapter(Context context) {
mContext = context;
}
#Override
public Object instantiateItem(ViewGroup collection, int position) {
ModelObject modelObject = ModelObject.values()[position];
LayoutInflater inflater = LayoutInflater.from(mContext);
ViewGroup layout = (ViewGroup) inflater.inflate(modelObject.getLayoutResId(), collection, false);
collection.addView(layout);
return layout;
}
#Override
public void destroyItem(ViewGroup collection, int position, Object view) {
collection.removeView((View) view);
}
#Override
public int getCount() {
return ModelObject.values().length;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
#Override
public CharSequence getPageTitle(int position) {
ModelObject customPagerEnum = ModelObject.values()[position];
return mContext.getString(customPagerEnum.getTitleResId());
}
}
And ModelObject.java
public enum ModelObject {
BLUE(R.string.blue, R.layout.page_one),
GREEN(R.string.green, R.layout.page_two),
RED(R.string.blue, R.layout.page_tree);
private int mTitleResId;
private int mLayoutResId;
ModelObject(int titleResId, int layoutResId) {
mTitleResId = titleResId;
mLayoutResId = layoutResId;
}
public int getTitleResId() {
return mTitleResId;
}
public int getLayoutResId() {
return mLayoutResId;
}
}
How can I solve this ?
I changed list but I didn't;
So how ?