guys i need help with this matter i have been going through my code for a couple of days to figure whats going wrong but i couldn't figure it out.
I have a fragment with a RecyclerView i initialize the Adapter data with an image place holder and some default text and the fragment shows them as expected then using a loader i fetch data from the internet and parse and pass the new data to the Adapter (all of this happens as required) until the data reaches the Adapter then Taaadaaaa the initial data disappears and the new data is not showing actually the fragment shows a blank screen definitely i am doing something wrong please advise.
This is the fragment code
public class fragment_MovieStartGridlayout extends android.support.v4.app.Fragment implements MyGridAdapter.MyGridAdapterListener{
private static RecyclerView myRecyclerView;
private static MyGridAdapter myGridAdapter;
private static RecyclerView.LayoutManager rvLayoutManager;
private LoaderManager.LoaderCallbacks<ArrayList<HashMap>> dataLoaderCallbacks;
private OnFragmentInteractionListener mListener;
public fragment_MovieStartGridlayout() {
}
#Override
public void onActivityCreated (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dataLoaderCallbacks = new LoaderManager.LoaderCallbacks<ArrayList<HashMap>>() {
#Override
public Loader<ArrayList<HashMap>> onCreateLoader(int id, Bundle args) {
return new DataLoader(getActivityContext(), MyUriBuilder.DISCOVER, null);
}
#Override
public void onLoadFinished(Loader<ArrayList<HashMap>> loader,ArrayList<HashMap> data) {
myGridAdapter.setMyAdapterData(data);
}
#Override
public void onLoaderReset(Loader<ArrayList<HashMap>> loader) {
loader.reset();
}
};
getLoaderManager().initLoader(0, null, dataLoaderCallbacks);
setRetainInstance(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View fragGridLayout = inflater.inflate(R.layout.fragment_gridlayout_movie_start, container, false);
myRecyclerView = (RecyclerView) fragGridLayout.findViewById(R.id.myViewRecycler);
rvLayoutManager = new GridLayoutManager(getActivityContext(),2);
myRecyclerView.setLayoutManager(rvLayoutManager);
myGridAdapter = new MyGridAdapter(getActivityContext());
myRecyclerView.setAdapter(myGridAdapter);
return fragGridLayout;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnFragmentInteractionListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDataSetChanged(boolean state) {
if (state){
myGridAdapter.notifyDataSetChanged();
}
}
public interface OnFragmentInteractionListener {
public void onFragmentInteraction(Uri uri);
}
public Context getActivityContext(){
return this.getActivity();
}
}
and this is the Adapter for the RecyclerView
public class MyGridAdapter extends RecyclerView.Adapter<MyGridAdapter.MyViewHolder> {
LayoutInflater layoutInflater;
private static ArrayList<HashMap> data=null;
private Context mContext;
public static Bitmap placeHolder;
public MyGridAdapter(Context context){
mContext = context;
setInitialData();
placeHolder = BitmapFactory.decodeResource(mContext.getResources(),R.drawable.android_blue);
}
public interface MyGridAdapterListener{
public void onDataSetChanged(boolean state);
}
private MyGridAdapterListener listener = null;
public void registerListener(MyGridAdapterListener newListener){
listener = newListener;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
layoutInflater = LayoutInflater.from(context);
View v = layoutInflater.inflate(R.layout.gridlayout_item_movie_start, parent, false);
MyViewHolder vHolder=new MyViewHolder(v);
return vHolder;
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
HashMap singleData = data.get(position);
String movieRate = String.valueOf(singleData.get(MyJSONDataParser.TAG_VOTE_AVERAGE)) ;
holder.movieTitle.setText((String)singleData.get(MyJSONDataParser.TAG_TITLE));
holder.moviePoster.setImageBitmap(placeHolder);
holder.movieRating.setRating(Float.valueOf(movieRate));
}
#Override
public int getItemCount() {
return data.size();
}
public static class MyViewHolder extends RecyclerView.ViewHolder {
TextView movieTitle;
RoundedImageView moviePoster;
RatingBar movieRating;
public MyViewHolder(View v) {
super(v);
movieTitle = (TextView) v.findViewById(R.id.movieTitleTextView);
moviePoster = (RoundedImageView) v.findViewById(R.id.roundImageView);
movieRating = (RatingBar) v.findViewById(R.id.ratingBar);
}
}
private boolean dataChanged = false;
public void setMyAdapterData(ArrayList<HashMap> data){
this.data = data;
dataChanged = true;
if (listener != null){
listener.onDataSetChanged(dataChanged);
}
}
protected void setInitialData(){
HashMap initialItem = new HashMap();
ArrayList<HashMap> initialData = new ArrayList<>(20);
initialItem.put(MyJSONDataParser.TAG_TITLE, "Loading...");
initialItem.put(MyJSONDataParser.TAG_MOVIE_BITMAP, placeHolder);
initialItem.put(MyJSONDataParser.TAG_VOTE_AVERAGE, 3.3);
for (int i = 0;i<20;i++){
initialData.add(initialItem);
}
this.data = initialData;
}
}
I did call notifyDataSetChanged
but this was not the issue after alooooooooot of testing and Logging the problem was with setAdapterData method where i just passed the data reference from the loader to the adapter but this didn't work and i had to clone the arraylist instead of just passing the reference which sounds strange to me and i still don't understand why I had to do that if you can take a look at the setAdapterData method in MyGridAdapter class and tell me what do you think
Try invoking notifyDataSetChanged() when you modify your adapter data:
public void setMyAdapterData(ArrayList<HashMap> data){
this.data = data;
dataChanged = true;
notifyDataSetChanged();
if (listener != null){
listener.onDataSetChanged(dataChanged);
}
}
I see that you attempt to do this in the callback on your listener, but perhaps it is null and therefore never firing the notification?
[COMMENT]
When I want to replace the entire collection of data in my adapter I often write a method similar to this:
public void setData(List<MyData> newData) {
this.data.clear();
this.data.addAll(newData);
this.notifyDataSetChanged();
}
Related
I am creating an app which can retrieve data from my own database. I'm using Retrofit to connect with my API. I'm creating a Bottom Navigation Activity so i could add some fragments to it. I'm using a Recycler View to show the list but it won't let me attach the adapter when i retrieve the data, it always shows this error in the log :
04-11 14:29:19.461 1912-1912/com.siscaproject.sisca E/RecyclerView: No adapter attached; skipping layout
Usually i use a single activity to create a list activity with a recycler view and it ran perfectly, but now that i use a fragment to do the same, it always gave me the error. Here is the fragment code :
public class SearchAssetFragment extends Fragment {
private static final String TAG = "SearchAssetFragment";
#BindView(R.id.search_view) SearchView searchView;
#BindView(R.id.swprefresh) SwipeRefreshLayout refresh;
#BindView(R.id.rv_list_asset) RecyclerView recyclerView;
#BindView(R.id.progress_bar) ProgressBar progressBar;
private MaterialDialog createDialog;
private AssetsAdapter adapter;
private ArrayList<Asset> listData = new ArrayList<>();
private UserService userService;
private OnFragmentInteractionListener mListener;
private AssetsAdapter.OnButtonClickListener listener = new AssetsAdapter.OnButtonClickListener() {
#Override
public void showDeleteDialog(int id) {
// TODO: Complete showDeleteDialog()
}
#Override
public void showEditDialog(Asset asset) {
// TODO: Complete showEditDialog()
}
};
public SearchAssetFragment() {
// Required empty public constructor
}
public static SearchAssetFragment newInstance() {
SearchAssetFragment fragment = new SearchAssetFragment();
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_search_asset, container, false);
ButterKnife.bind(this, view);
userService = APIProperties.getUserService();
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
// The method to retrieve the data from the DB and set the recycler view adapter
getAsset();
refresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
getAsset();
}
});
return view;
}
private void showCreateDialog(){
// creating a dialog
}
private void showProgressBar(){
// showing a progress bar
}
private void hideProgressBar(){
// hiding a progress bar
}
// The method to retrieve the data from the DB and set the recycler view adapter
private void getAsset(){
showProgressBar();
Call<ResponseIndex<Asset>> call = userService.indexFixed(Header.auth, Header.accept);
call.enqueue(new Callback<ResponseIndex<Asset>>() {
#Override
public void onResponse(Call<ResponseIndex<Asset>> call, Response<ResponseIndex<Asset>> response) {
if(response.isSuccessful()){
int total = response.body().getTotal();
Log.i(TAG, "onResponse: total " + total);
// Initializing the adapter and set it to the recycler view
ArrayList<Asset> rows = response.body().getRows();
adapter = new AssetsAdapter(rows, getActivity(), userService, listener);
recyclerView.setAdapter(adapter);
}
else{
Log.i(TAG, "onResponse: else");
}
hideProgressBar();
refresh.setRefreshing(false);
}
#Override
public void onFailure(Call<ResponseIndex<Asset>> call, Throwable t) {
Log.e(TAG, "onFailure: " + t.getMessage() );
}
});
}
}
I'm not sure what i did wrong nor how to fix it, any answer would be appreciated. Thank you.
--Edit-- AssetsAdapter class :
public class AssetsAdapter extends RecyclerView.Adapter<AssetsAdapter.ItemHolder> implements Filterable{
private static final String TAG = "AssetsAdapter";
private OnButtonClickListener listener;
private ArrayList<Asset> listData;
private ArrayList<Asset> listDataFull;
private Context activityContext;
private UserService userService;
private MaterialDialog dialog;
public AssetsAdapter(ArrayList<Asset> listData, Context activityContext, UserService userService, OnButtonClickListener listener) {
this.listData = listData;
listDataFull = new ArrayList<>(listData);
this.activityContext = activityContext;
this.userService = userService;
this.listener = listener;
}
public AssetsAdapter(Context activityContext) {
this.activityContext = activityContext;
}
public void setListData(ArrayList<Asset> listData) {
this.listData = listData;
notifyDataSetChanged();
}
#NonNull
#Override
public ItemHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.layout_item_assets, parent, false);
return new ItemHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ItemHolder holder, final int position) {
// holder.iv_asset.setImageDrawable(); On progress
holder.tv_name.setText(listData.get(position).getName());
holder.tv_manufacturer.setText(listData.get(position).getAsset_id());
holder.tv_quantity.setText(listData.get(position).getPurchase_cost());
//holder.tv_status.setText(listData.get(position).getModel_no()); // Still on Progress
holder.btn_delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
listener.showDeleteDialog(listData.get(position).getId());
}
});
holder.btn_edit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//Toast.makeText(activityContext, "Edit", Toast.LENGTH_SHORT).show();
listener.showEditDialog(listData.get(position));
}
});
}
#Override
public int getItemCount() {
if(listData.isEmpty()) return 0;
else return listData.size();
}
#Override
public Filter getFilter() {
return dataFilter;
}
private Filter dataFilter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
ArrayList<Asset> filteredList = new ArrayList<>();
if(charSequence == null || charSequence.length() == 0){
filteredList.addAll(listDataFull);
}
else{
String filterPattern = charSequence.toString().toLowerCase().trim();
for(Asset item : listDataFull){
if(item.getName().toLowerCase().contains(filterPattern)){
filteredList.add(item);
}
}
}
FilterResults results = new FilterResults();
results.values = filteredList;
return results;
}
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
listData.clear();
listData.addAll((List) filterResults.values);
notifyDataSetChanged();
}
};
public class ItemHolder extends RecyclerView.ViewHolder{
private ImageView iv_asset;
private TextView tv_name;
private TextView tv_manufacturer;
private TextView tv_quantity;
private TextView tv_status;
private ImageButton btn_edit;
private ImageButton btn_delete;
public ItemHolder(View itemView) {
super(itemView);
iv_asset = itemView.findViewById(R.id.iv_asset);
tv_name = itemView.findViewById(R.id.tv_name);
tv_manufacturer = itemView.findViewById(R.id.tv_manufacturer);
tv_quantity = itemView.findViewById(R.id.tv_quantity);
tv_status = itemView.findViewById(R.id.tv_status);
btn_edit = itemView.findViewById(R.id.btn_edit);
btn_delete = itemView.findViewById(R.id.btn_delete);
}
}
public interface OnButtonClickListener {
void showDeleteDialog(final int id);
void showEditDialog(Asset asset);
}
}
First, initialize the model class and the adapter and attach to recyclerview and than get the data after retrieving data put notifydatasetchanged() or notifydatainserted() method, I think it should work,
please initialize adapter in fragment oncreateview method and set adapter to recycleview
adapter = new AssetsAdapter(rows, getActivity(), userService, listener);
recyclerView.setAdapter(adapter);
recyclerView.setAdapter(adapter);
after get response from api you can update adapter. please refer
this question
I have implemented a basic ListAdapter in RecyclerView as I am using View Model. The data I am getting is from networkManager to Viewmodel by calling API. Even when I did got the data the submitList is not Working and thus no data is getting inflated.
UpcomingGroupFragment
public class UpcomingGroupFragment extends Fragment {
private UpcomingViewModel mViewModel;
private RecyclerView recyclerView;
private GroupAdapter_new adapter;
public static UpcomingGroupFragment newInstance() {
return new UpcomingGroupFragment();
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_chatgroups, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
recyclerView = view.findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
adapter = new GroupAdapter_new();
recyclerView.setAdapter(adapter);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mViewModel = ViewModelProviders.of(this).get(UpcomingViewModel.class);
mViewModel.getMutableLiveData().observe(this, new Observer<List<ChatGroups_New>>() {
#Override
public void onChanged(#Nullable List<ChatGroups_New> chatGroups_news) {
adapter.submitList(chatGroups_news);
Log.e("Upcoming", String.valueOf(chatGroups_news.size()));
}
});
}
}
The Adapter Class extends the ListAdapter.
Link for overriding submitlist: https://stackoverflow.com/a/50062174
The Code is as follows:
GroupAdapter_new
public class GroupAdapter_new extends ListAdapter<ChatGroups_New,GroupAdapter_new.ViewHolder> {
public GroupAdapter_new() {
super(DIFF_CALLBACK);
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
Context context = parent.getContext();
int layoutID = R.layout.ongoing_group;
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(layoutID,parent,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
ChatGroups_New currentGroup = getItem(position);
holder.text_flightarrival.setText(currentGroup.getFlightNameArrival());
}
class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
//... Finding ID's for various Views
}
}
/****ADDED THIS FROM CODE*****/
#Override
public void submitList(List<ChatGroups_New> list) {
super.submitList(list != null ? new ArrayList<ChatGroups_New>() : null);
}
/***********/
private static final DiffUtil.ItemCallback<ChatGroups_New> DIFF_CALLBACK =
new DiffUtil.ItemCallback<ChatGroups_New>() {
#Override
public boolean areItemsTheSame(ChatGroups_New oldItem, ChatGroups_New newItem) {
Log.e("areItemsTheSame", String.valueOf(oldItem.getMergedLogId() == newItem.getMergedLogId()));
return oldItem.getMergedLogId() == newItem.getMergedLogId();
}
#Override
public boolean areContentsTheSame(ChatGroups_New oldItem, ChatGroups_New newItem) {
if(oldItem.getFlightIcon().equals(newItem.getFlightIcon()) && oldItem.getFlightNameArrival().equals(newItem.getFlightNameArrival())){
if(oldItem.getGateValue().equals(newItem.getGateValue()) && oldItem.getEtaValue().equals(newItem.getEtaValue())){
if(oldItem.getAlertValue().equals(newItem.getAlertValue()) && oldItem.getTaskcompletedValue().equals(newItem.getTaskcompletedValue())){
Log.e("areContentsTheSame", "true");
return true;
}
}
}
return false;
}
};
}
If you want to see my ViewModel Class then:
UpcomingViewModel
public class UpcomingViewModel extends AndroidViewModel
implements I_NetworkResponse {
private NetworkManager networkManager;
private SharedPrefService prefService;
private HashMap<String, String> header;
private final String TAG = "UpcomingViewModel";
private List<ChatGroups_New> upcomingList;
private MutableLiveData<List<ChatGroups_New>> mutableLiveData;
public UpcomingViewModel(#NonNull Application application) {
super(application);
prefService = SharedPrefService.getInstance(application);
networkManager = new NetworkManager(application,this);
upcomingList = new ArrayList<>();
mutableLiveData = new MutableLiveData<>();
mutableLiveData.setValue(upcomingList);
header = new HashMap<>();
header.put("authorizationcode",prefService.getStringValue(Keys.getPreferenceAuthKey()));
if(upcomingList.isEmpty()){
networkManager.Volley_JsonObjectRequest(Keys.getBaseUrl()+"AviLeap/flights/upcoming",
header,null,TAG,"AviLeap/flights/upcoming");
}
}
public MutableLiveData<List<ChatGroups_New>> getMutableLiveData() { return mutableLiveData; }
#Override
public void getNetworkSuccessResponse(String TAG, String successResponse, String TAGforApi) {
Log.e(TAGforApi,successResponse);
parseUpcomingFlight(successResponse, upcomingList);
mutableLiveData.setValue(upcomingList);
}
#Override
public void getNetworkFailResponse(String TAG, VolleyError failResponse, String TAGforApi) { }
#Override
protected void onCleared() {
super.onCleared();
networkManager.stopNetworkCallsWithTag(TAG);
}
private void parseUpcomingFlight(String successResponse, List<ChatGroups_New> upcomingList) {
try {
JSONObject rootObject = new JSONObject(successResponse);
if(rootObject.has("upcomingflights") && rootObject.opt("upcomingflights") instanceof JSONArray){
JSONArray flightsArray = rootObject.optJSONArray("upcomingflights");
for(int flightIndex = 0; flightIndex < flightsArray.length(); flightIndex++){
JSONObject flightObject = flightsArray.optJSONObject(flightIndex);
int mergedLogId = flightObject.optInt("logid");
upcomingList.add(new ChatGroups_New(mergedLogId));
Log.e("parseUpcomingFlight", String.valueOf(upcomingList.size()));//..... Log Point
}
}
}
catch (JSONException e) { e.printStackTrace(); }
}
}
Initially the Size of the List is zero, so the Error is coming for as
AviLeap/flights/upcoming: //.... API CALL
2019-03-02 13:25:53.652 8477-8477/com.avileapconnect.com E/parseUpcomingFlight: 1 2019-03-02 13:25:53.652 8477-8477/com.avileapconnect.com E/parseUpcomingFlight: 2
2019-03-02 13:25:53.653 8477-8477/com.avileapconnect.com E/Upcoming: 2
The above logs show that the data is being added to the arraylist, but it is not updating. Also after all these logs when I go back to my Fragment I get the following error.
no adapter Attached, Skipping Layout
One more thing to add is that the adapter's getItemCount is getting updated properly. But even after that I am getting error:
no adapter Attached, Skipping Layout
EDIT: I fixed the error by commenting out the code for overriding the SubmitList method. I am also setting the adapter in the observer method in the fragment Class
Is it all possible to access an adapter's data via another adapter?
I want to start an activity and pass data from an adapter to a fragment which is used in TabLayout as one of three fragments, I have two adapters and a button which is clicked to start an activity, its Java code is in my first adapter and I need to pass second adapter's data via second adapter itself
here is my codes:
my first adapter:
public class RecyclerViewDataAdapter extends RecyclerView.Adapter<RecyclerViewDataAdapter.ItemRowHolder>{
private ArrayList<SectionDataModel> dataList;
private Context mContext;
private RecyclerView.RecycledViewPool recycledViewPool;
private SnapHelper snapHelper;
public RecyclerViewDataAdapter(ArrayList<SectionDataModel> dataList, Context mContext) {
this.dataList = dataList;
this.mContext = mContext;
recycledViewPool = new RecyclerView.RecycledViewPool();
}
#Override
public ItemRowHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, null);
ItemRowHolder rowHolder = new ItemRowHolder(v);
snapHelper = new GravitySnapHelper(Gravity.START);
return rowHolder;
}
#Override
public void onBindViewHolder(ItemRowHolder holder, int position) {
ArrayList singleSectionItems = dataList.get(position).getAllItemInSection();
final String sectionName = dataList.get(position).getHeaderTitle();
holder.itemTitle.setText(sectionName);
SectionDataAdapter adapter = new SectionDataAdapter(singleSectionItems, mContext);
holder.recyclerView.setHasFixedSize(true);
holder.recyclerView.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.HORIZONTAL, false));
holder.recyclerView.setAdapter(adapter);
holder.recyclerView.setRecycledViewPool(recycledViewPool);
snapHelper.attachToRecyclerView(holder.recyclerView);
holder.btnMore.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//here i can start the activity but..(second adapter)
Toast.makeText(view.getContext(), sectionName, Toast.LENGTH_SHORT).show();
}
});
}
#Override
public int getItemCount() {
return (null != dataList ? dataList.size() : 0);
}
public class ItemRowHolder extends RecyclerView.ViewHolder {
protected ImageView mitemImage;
protected TextView mitemtext;
protected TextView itemTitle;
protected RecyclerView recyclerView;
protected Button btnMore;
public ItemRowHolder(View itemView) {
super(itemView);
this.mitemImage = itemView.findViewById(R.id.itemImage);
this.mitemtext = itemView.findViewById(R.id.tvTitle);
this.itemTitle = itemView.findViewById(R.id.itemTitle);
this.recyclerView = itemView.findViewById(R.id.recycler_view_list);
this.btnMore = itemView.findViewById(R.id.btnMore);
}
}
} '
and my second adapter:
import java.net.PortUnreachableException;
import java.util.ArrayList;
public class SectionDataAdapter extends RecyclerView.Adapter<SectionDataAdapter.SssingleItemRowHolder>{
private ArrayList<SingleItemModel> itemModels;
private Context mContext;
public SectionDataAdapter(ArrayList<SingleItemModel> itemModels, Context mContext) {
this.itemModels = itemModels;
this.mContext = mContext;
}
#Override
public SingleItemRowHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_single_card, null);
SingleItemRowHolder singleItemRowHolder = new SingleItemRowHolder(v);
return singleItemRowHolder;
}
#Override
public void onBindViewHolder(SingleItemRowHolder holder, int position) {
SingleItemModel itemModel = itemModels.get(position);
holder.tvTitle.setText(itemModel.getName());
holder.mitemImage.setImageResource(itemModel.getImage());
}
#Override
public int getItemCount() {
return (null != itemModels ? itemModels.size() : 0);
}
public class SingleItemRowHolder extends RecyclerView.ViewHolder {
protected TextView tvTitle;
protected ImageView mitemImage;
public SingleItemRowHolder(View itemView) {
super(itemView);
final Intent intent = new Intent(mContext,MainActivity.class);
this.mitemImage = itemView.findViewById(R.id.itemImage);
this.tvTitle = itemView.findViewById(R.id.tvTitle);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//... need to start the activity from here
Toast.makeText(view.getContext(), tvTitle.getText(), Toast.LENGTH_SHORT).show();
}
});
}
}
Like #MilaDroid said you simply need a getter that returns the another Adapter's ArrayList<SingleItemModel> but the problem you will face is that you need to have the same instance of the Adapter from the Activity in order to get the populated ArrayList<SingleItemModel>.
A good workaround is to used Bill Pugh's Singleton in the Adapter
public class Adapter {
private ArrayList<SingleItemModel> list;
private Adapter() {}
public static Adapter getInstance() {
return InstInit.INSTANCE;
}
// Don't forget to set the list (or NPE)
// because we can't argue with a Singleton
public void setList(ArrayList<SingleItemModel> list) {
this.list = list;
}
// You can now get the ArrayList
public ArrayList<SingleItemModel> getList() {
return list;
}
private static class InstInit {
private static final Adapter INSTANCE = new Adapter();
}
// Overrided RecyclerView.Adapter Methods
.................
}
Retrieving the ArrayList assuming that the following Adapters are Singleton
AdapterOne a1 = AdapterOne.getInstance();
AdapterTwo a2 = AdapterTwo.getInstance();
ArrayList<SingleItemModel> a1RetrievedList = a1.getList();
// You don't need to create a new instance
// creating a new instance doesn't make sense
// because you need to repopulate the list
// for the new instance.
ArrayList<SingleItemModel> a2RetrievedList = a2.getList();
// You can also retrieve from AdapterTwo
I am trying to create an interface between my Recyclerview Adapter and an Activity, so that when an item in the adapter is clicked, the Activity will react accordingly but the listener is always null.
Interface
public interface UrlTagCatClickedListener {
public void onUrlTagCatClicked (String chemicalURL);
}
Adapter
public class TagCatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context mContext;
private List<TagCatItem> mTagCatItems;
private int lastPosition = -1;
private UrlTagCatClickedListener mTagCatClickedListener;
public TagCatAdapter(List<TagCatItem> tagCatItems, Context context) {
super();
this.mTagCatItems = tagCatItems;
this.mContext = context;
this.mTagCatClickedListener = null;
}
public void setTagCatClickedListener (UrlTagCatClickedListener tagCatClickedListener) {
this.mTagCatClickedListener = tagCatClickedListener;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.tag_cat_item, parent, false);
return new ItemViewHolder(v);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final TagCatItem tagCatItem = mTagCatItems.get(position);
((ItemViewHolder) holder).chemicalTitle.setText(Html.fromHtml(tagCatItem.getChemicalTitle()));
((ItemViewHolder) holder).chemicalDate.setText(tagCatItem.getChemicalDate());
((ItemViewHolder) holder).chemicalTitle.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mTagCatClickedListener != null) { // mTagCatClickedListener is always null
mTagCatClickedListener.onUrlTagCatClicked(tagCatItem.getChemicalURL());
}
}
});
}
public class ItemViewHolder extends RecyclerView.ViewHolder{
public TextView chemicalTitle, chemicalDate;
public ItemViewHolder(final View mView) {
super(mView);
chemicalTitle = (TextView) mView.findViewById(R.id.tagcat_title);
chemicalDate = (TextView) mView.findViewById(R.id.tagcat_date);
}
}
#Override
public int getItemCount() {
return mTagCatItems.size();
}
}
Activity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate called")
//Skipped a lot of codes that doesn't relate to the queation
List<TagCatItem> mTagCatItems = new ArrayList<>();
TagCatAdapter tagCatAdapter = new TagCatAdapter(mTagCatItems, this);
tagCatAdapter.setTagCatClickedListener(new UrlTagCatClickedListener() {
#Override
public void onUrlTagCatClicked(String chemicalURL) {
Log.d(TAG, "I go the url!!!!!!!!!! and it is + " + chemicalURL);
}
});
}
Please, do you have an idea why it's null and how I can fix it?
You have two different instances of TagCatAdapter in your given setup; one in the Activity, and one in the Fragment. You're setting the UrlTagCatClickedListener you've posted on the one created in the Activity, but it's the Fragment's TagCatAdapter instance that you're setting on the RecyclerView. That one doesn't have the listener set, so its mTagCatClickedListener is always null.
You just need to move the given UrlTagCatClickedListener to the TagCatAdapter in the Fragment, and remove the TagCatAdapter from the Activity, as you're not using that one anyway.
I'm in a fragment trying to updated my recycler view, after querying Parse for some data. In the done method of the query I call notifyDataSetChagned, but the list is never displayed
package com.garciaericn.t2d.fragments;
public class DevicesCardViewFragment extends Fragment implements View.OnClickListener {
private OnFragmentInteractionListener mListener;
private BatteryHelper mBatteryHelper;
Intent mBatteryStatus;
private RecyclerView mRecyclerView;
private DeviceAdapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
private List<Device> mDevices;
public DevicesCardViewFragment() {
// Required empty public constructor
mDevices = new ArrayList<Device>();
}
public static DevicesCardViewFragment newInstance() {
// Bundle parameters is necessary
return new DevicesCardViewFragment();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get arguments
getDevices();
mBatteryHelper = new BatteryHelper(getActivity());
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
mBatteryStatus = getActivity().registerReceiver(null, intentFilter);
// Update stats of current device.
Toast.makeText(getActivity(), "Battery level: " + mBatteryHelper.getCurrentBatteryLevel() + "%", Toast.LENGTH_LONG).show();
// Update device stats
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_devices_list, container, false);
mListener.showAd();
// Obtain recycler view
mRecyclerView = (RecyclerView) view.findViewById(R.id.devices_recycler_view);
mRecyclerView.setHasFixedSize(true);
mAdapter = new DeviceAdapter(getActivity(), mDevices);
// Set adapter
mRecyclerView.setAdapter(mAdapter);
// Set layout manager
mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
return view;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnFragmentInteractionListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public List<Device> getDevices() {
ParseQuery<Device> query = ParseQuery.getQuery(Device.DEVICES);
// new ParseQuery<Device>(Device.DEVICES);
query.whereEqualTo("deviceUser", ParseUser.getCurrentUser());
query.findInBackground(new FindCallback<Device>() {
#Override
public void done(List<Device> devices, ParseException e) {
if (e == null) {
// Loop through return devices
for (Device device : devices) {
Device currentDevice = new Device();
currentDevice.setDeviceName(device.getDeviceName());
currentDevice.setBatteryLevel(device.getBatteryLevel());
currentDevice.setIsCharging(device.isCharging());
mDevices.add(currentDevice);
}
mAdapter.notifyDataSetChanged();
} else {
// Something went wrong
Toast.makeText(getActivity(), "Error: " + e.toString(), Toast.LENGTH_LONG).show();
}
}
});
return mDevices;
}
#Override
public void onClick(View v) {
// Click events go here
}
public static DevicesCardViewFragment newInstance(List<Device> mDevices) {
DevicesCardViewFragment fragment = new DevicesCardViewFragment();
Bundle args = new Bundle();
return fragment;
}
public interface OnFragmentInteractionListener {
public void showAd();
}
}
My recyclerViewAdapter looks like this:
package com.garciaericn.t2d.data;
public class DeviceAdapter extends RecyclerView.Adapter<DeviceAdapter.MyViewHolder> {
private final LayoutInflater inflater;
List<Device> data = Collections.emptyList();
public DeviceAdapter(Context context, List<Device> data) {
inflater = LayoutInflater.from(context);
this.data = data;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.card_layout, parent, false);
MyViewHolder holder = new MyViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Device device = data.get(position);
holder.deviceNameTV.setText(device.getDeviceName());
holder.batteryLevelTV.setText(device.getBatteryLevel());
}
#Override
public int getItemCount() {
return 0;
}
public static class MyViewHolder extends RecyclerView.ViewHolder {
// Temp data set
private String[] mDataset;
TextView deviceNameTV;
TextView batteryLevelTV;
public MyViewHolder(View itemView) {
super(itemView);
deviceNameTV = (TextView) itemView.findViewById(R.id.device_name_tv);
batteryLevelTV = (TextView) itemView.findViewById(R.id.battery_level_tv);
}
}
}
Change getItemCount() to actually return the correct value:
#Override
public int getItemCount() {
return data.size()
}