I load a recyclerview based on Firebase data via the following method:
#Override
public void onStart() {
super.onStart();
mChildEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
String newPollEpoch = dataSnapshot.getKey();
if (mNewPollsAray.contains(newPollEpoch)) {
Log.v("POLL_ADDED", "POLL ADDED: " + newPollEpoch);
} else {
Log.v("Child_Added", "The new child is " + newPollEpoch);
String newPollImageURL = dataSnapshot.child(IMAGE_URL).getValue(String.class);
//TODO: On additional devices, numbesr are not appearing as the question
String newPollQuestion = dataSnapshot.child(QUESTION_STRING).getValue(String.class);
String convertedQuestion = newPollQuestion.toString();
mNewPollsAray.add(0, new Poll(convertedQuestion, newPollImageURL, newPollEpoch));
mNewPollsAdapter.notifyDataSetChanged();
Log.v("OnChildChanged", "OnCHILDCHANGEDCALLED " + dataSnapshot.getKey());
}
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
mPollsRef.addChildEventListener(mChildEventListener);
}
#Override
public void onStop() {
super.onStop();
mPollsRef.removeEventListener(mChildEventListener);
}
Here is the method I call when an item in the recyclerview is clicked:
#Override
public void onClick(View view) {
view.getId();
int itemPosition = getAdapterPosition();
String passEpoch = mNewPollsAray.get(itemPosition).getPollID();
Log.v("PASSED_ID", "The passed ID is " + passEpoch);
Intent toPoll = new Intent(getActivity(), PollHostActivity.class);
toPoll.putExtra("POLL_ID", passEpoch);
startActivity(toPoll);
}
The fragment I am loading it from is part of a TabLayout. When I navigate between the tabs the recyclerview loads correctly.
However, when I click an item in the recyclerview (which takes me to a new activity) and then navigate back to the fragment containing the recyclerview, items get duplicated and the recyclerview items are all out of order. I think it has to do with onStart() being called multiple times and essentially "stacking" new items onto the recyclerview instead of replacing them, but I was hoping to confirm.
This happens because you add a listener, but never remove it. So the next time when you enter the view, you add a second listener and thus get two calls to onChildAdded() for each item in the database.
The solution is to remove the listener when you exit the view. Since you attach the listener in onStart(), you should remove it again in onStop():
#Override
public void onStop() {
mPollsRef.removeEventListener(mChildEventListener);
}
You can try with code, I was facing similar issue got resolved with bellow changes.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if(mMainLayout == null)
{
mMainLayout = inflater.inflate(R.layout.fragment_main, container,false);
...
}
return mMainLayout;
}
When mMainlayout is not null, it mean that your fragment instance has already one instance of the mMainLayout and already added to ViewGroup container no need to add it again. You may be facing issue as you are adding same view again to same container.
By Clear the data set you can avoid loading of similar items again in Recycler View. It worked for me.
listOftrailers.clear();
try {
JSONObject jsonObject = new JSONObject(data);
JSONArray jsonArray = jsonObject.getJSONArray("results");
for (int i = 0; i < jsonArray.length(); i++) {
MovieTrailer item = new MovieTrailer();
JSONObject js = jsonArray.getJSONObject(i);
item.setVideoID(js.getString("id"));
item.setVideoName(js.getString("name"));
item.setVideoKey(js.getString("key"));
item.setVideoSite(js.getString("site"));
item.setVideoType(js.getString("type"));
String name = item.getVideoName();
if (name.contains("Official Trailer") ||
name.startsWith("Official"))
listOftrailers.add(item);
}
} catch (JSONException e) {
e.printStackTrace();
}
videosadapter = new TrailerListAdapter(listOftrailers.size(),
listOftrailers, MoviePage.this);
recyclerView.setAdapter(videosadapter);
Related
I've tried a few different ways of fixing this, but it just doesn't seem to want to work. I have attached the fragment involved. The recyclerview works when I use the search function; However, when I first load the page, I get the error that
E/RecyclerView: No adapter attached; skipping layout
I think it might be an issue with the onCreate vs onCreateView, but I'm not exactly sure what to put where.
NewsFragment.java
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
v = inflater.inflate(R.layout.fragment_news, container, false);
swipeRefreshLayout = v.findViewById(R.id.swipeRefresh);
recyclerView = v.findViewById(R.id.news_recyclerView);
etQuery = v.findViewById(R.id.etQuery);
btnSearch = v.findViewById(R.id.btnSearch);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
final String country = getCountry();
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
retrieveJson("", country, API_KEY);
}
});
retrieveJson("", country, API_KEY);
btnSearch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!etQuery.getText().toString().equals("")) {
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
retrieveJson(etQuery.getText().toString(), country, API_KEY);
}
});
retrieveJson(etQuery.getText().toString(), country, API_KEY);
} else {
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
retrieveJson("", country, API_KEY);
}
});
retrieveJson("", country, API_KEY);
}
}
});
return v;
}
public void retrieveJson(String query ,String country, String apiKey){
swipeRefreshLayout.setRefreshing(true);
Call<Headlines> call;
if (!etQuery.getText().toString().equals("")){
call=NewsApiClient.getInstance().getApi().getSpecificData(query,apiKey);
}else{
call=NewsApiClient.getInstance().getApi().getHeadlines(country,apiKey);
}
call.enqueue(new Callback<Headlines>() {
#Override
public void onResponse(Call<Headlines> call, Response<Headlines> response) {
if (response.isSuccessful() && response.body().getArticles() != null ){
swipeRefreshLayout.setRefreshing(false);
articles.clear();
articles = response.body().getArticles();
newsAdapter = new NewsAdapter(getContext(), articles);
recyclerView.setAdapter(newsAdapter);
}
}
#Override
public void onFailure(Call<Headlines> call, Throwable t) {
swipeRefreshLayout.setRefreshing(false);
Toast.makeText(getContext(), t.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
}
});
}
public String getCountry(){
Locale locale = Locale.getDefault();
String country = locale.getCountry();
return country.toLowerCase();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
On the onCreateView you are in fact not setting any adapter. You instead set it when retrieving the json data inside the call.enqueue callbacks, this callbacks are called asynchronously and thus the first time the onCreateView is called no adapter is set to the RecyclerView. To avoid that, set an adapter with empty data empty adapter right at the start of the onCreateView function like this (make newsAdapter a variable of the current fragment)
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
newsAdapter = new NewsAdapter(getContext(), articles);
recyclerView.setAdapter(newsAdapter);
make articles be a variable of the current fragment
and insted of setting and adapter on the callbacks of you retriveJson function simply update the articles array with the data and call the notifydatasetchanged function of the RecycleView like this
public void onResponse(Call<Headlines> call, Response<Headlines> response) {
if (response.isSuccessful() && response.body().getArticles() != null ){
swipeRefreshLayout.setRefreshing(false);
articles.clear();
articles = response.body().getArticles();
newsAdapter.setData(articles);
newsAdapter.notifyDataSetChanged()
}
}
setData is a function that you have to create in your NewsAdapter class.
Hope it helped!
And take a look a this brief guide on how to use RecycleViews
just a quick explanation of my project before I get to my question so you can get the gist of everything.
I'm currently working on this real-estate application with android and Firebase. I have been using Firebase to store my data of my app and to authenticate users.
I can add real estate objects to the database and retrieve the all the added real estates in a list view. When I click on one list item I'm getting a more detailed version of the real estate. The details of the real estates are shown in four different tabs. In one of the tabs I give the user the oppertunity to add attachments like pictures to the real estate.
I added the functionality to add the pictures just fine. They are stored in the database as shown in the following screenshot.
The eBncv5ke05ZxR32AiRoP9gSyPkO2 is the user_id and the
"-L38Qe8GEo33i5roKOCi" the Realestate id. the keys are the name of the image and the values the urls.
Here is the code that shows how I add the pictures to the database:
private void saveImage() {
// get the expose id
bundle = getArguments();
immoID = bundle.getString("exposeID");
Toast.makeText(getContext(), immoID, Toast.LENGTH_SHORT).show();
// get an reference to the current user and his id
user = FirebaseAuth.getInstance().getCurrentUser();
user_id = user.getUid();
imageName = imageNameInput.getText().toString();
if (!TextUtils.isEmpty(imageName)) {
//displaying progress dialog while image is uploading
final ProgressDialog progressDialog = new ProgressDialog(getContext());
progressDialog.setTitle("Bild wird hochgeladen");
progressDialog.show();
// uploading the Picture
pictureStorageRef = FirebaseStorage.getInstance().getReference(user_id).child(Constants.STORAGE_PATH_UPLOADS).child(immoID);
pictureDataRef = FirebaseDatabase.getInstance().getReference(Constants.DATABASE_PATH_UPLOADS).child(user.getUid()).child(immoID);
//checking if file is available
if (filePath != null) {
//getting the storage reference
StorageReference sRef = pictureStorageRef.child(Constants.STORAGE_PATH_UPLOADS + System.currentTimeMillis() + "." + getFileExtension(filePath));
//adding the file to reference
sRef.putFile(filePath)
.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
String imageName = imageNameInput.getText().toString().trim();
String imageDownloadURL = taskSnapshot.getDownloadUrl().toString();
//creating the upload object to store uploaded image details
PictureUpload upload = new PictureUpload(imageName, imageDownloadURL);
//adding an upload to firebase database
pictureDataRef.child(imageName).setValue(imageDownloadURL);
string_immo_image_url = imageDownloadURL;
//dismissing the progress dialog
progressDialog.dismiss();
changeFragment();
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
progressDialog.dismiss();
Toast.makeText(getContext(), exception.getMessage(), Toast.LENGTH_LONG).show();
}
})
.addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
#Override
public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
//displaying the upload progress
double progress = (100.0 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount();
progressDialog.setMessage(((int) progress) + "% wurden hochegeladen");
}
});
}
}else{
imageNameInput.setError("Geben Sie einen Namen ein");
imageNameInput.requestFocus();
}
}
Now I'm trying to show the pictures using Glide inside my Fragment in a ListView. Therefore I added an adapter for my ListView AttachmentList
public class AttachmentList extends ArrayAdapter <PictureUpload> {
List <PictureUpload> pictureUploads;
DatabaseReference pictureDatabase;
FirebaseUser user;
String userid;
private Activity context;
// Constructor
public AttachmentList (Activity context, List<PictureUpload> pictureUploads){
super (context, R.layout.layout_expose_list, pictureUploads);
this.context = context;
this.pictureUploads = pictureUploads;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
// inflate the custom layout for the listitems
LayoutInflater inflater= context.getLayoutInflater();
final View listViewItem = inflater.inflate(R.layout.layout_expose_list, null, true);
// get the data item for this position
PictureUpload pictureUpload = pictureUploads.get(position);
user = FirebaseAuth.getInstance().getCurrentUser();
userid = user.getUid();
// get references to the view elements in the layout for populating the data
TextView textViewTitle = listViewItem.findViewById(R.id.imageNameDisplay);
ImageView attachmentImage = listViewItem.findViewById(R.id.attachmentImage);
// set the most relevant information of the immo object to the textviews
textViewTitle.setText(pictureUpload.getName());
Glide.with(getContext()).load(pictureUpload.getUrl()).into(attachmentImage);
// return the listview item to render
return listViewItem;
}
}
The PictureUpload class looks like the following:
public class PictureUpload {
public String name;
public String url;
// Default constructor required for calls to
// DataSnapshot.getValue(User.class)
public PictureUpload() {
}
public PictureUpload(String name, String url) {
this.name = name;
this.url = url;
}
public String getName() {
return name;
}
public String getUrl() {
return url;
}
}
And here is the code to the Fragment where I'm trying to display the list:
package com.webgalaxie.blischke.bachelortakesix.fragments.tabfragments;
public class AttachmentTabFragment extends Fragment {
private static final String TAG = "ATTACHMENT_TAB";
FirebaseUser user;
String user_id;
Bundle bundle, newBundle;
String immoID;
// Button to add Attachments to the Expose
Button addAtachments;
private DatabaseReference immoDataRef, pictureDataRef, contactDataRef;
private StorageReference pictureStorageRef;
ListView show_all_attachments_list;
List<PictureUpload> pictureUploads;
public AttachmentTabFragment() {
// Required empty public constructor
}
// Inflate the view for the fragment based on layout XML
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_attachment_tab, container, false);
// get reference to the view elements
addAtachments = view.findViewById(R.id.addAtachments);
show_all_attachments_list = view.findViewById(R.id.show_all_attachments_list);
// get the current user
user = FirebaseAuth.getInstance().getCurrentUser();
user_id = user.getUid();
// get the expose id
bundle = getArguments();
immoID = bundle.getString("exposeID");
// set the on ClickListener to the addAttachments Button
addAtachments.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// change the fragment
Fragment addAttachmentFragment = new AddAttachmentFragment();
FragmentManager manager = getFragmentManager();
newBundle = new Bundle();
newBundle.putString("exposeID", immoID);
addAttachmentFragment.setArguments(newBundle);
manager.beginTransaction().replace(R.id.content_frame, addAttachmentFragment).addToBackStack(null).commit();
}
});
// get reference to the database and storage
immoDataRef = FirebaseDatabase.getInstance().getReference(Constants.DATABASE_PATH_IMMOBILIEN).child(user_id).child(immoID);
pictureDataRef = FirebaseDatabase.getInstance().getReference(Constants.DATABASE_PATH_UPLOADS).child(user_id).child(immoID);
contactDataRef = FirebaseDatabase.getInstance().getReference(Constants.DATABASE_PATH_CONTACTS).child(user_id).child(immoID);
pictureStorageRef = FirebaseStorage.getInstance().getReference(user_id).child(Constants.STORAGE_PATH_UPLOADS);
//return the view
return view;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.showexposemenu, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
final FragmentManager manager = getFragmentManager();
// get the expose id
bundle = getArguments();
immoID = bundle.getString("exposeID");
switch (item.getItemId()) {
case R.id.edit_expose:
Toast.makeText(getContext(), "Expose bearbeiten geklickt.", Toast.LENGTH_SHORT).show();
// put the immoID into new Bundle
newBundle = new Bundle();
newBundle.putString("exposeID", immoID);
// get a new instance of editExposeFragment
Fragment editExpose = new EditExposeFragment();
// set the newBundle as Arguments to the fragement
editExpose.setArguments(newBundle);
// switch the fragment
manager.beginTransaction().replace(R.id.content_frame, editExpose).commit();
break;
case R.id.delete_expose:
Toast.makeText(getContext(), "Expose wurde gelöscht.", Toast.LENGTH_SHORT).show();
immoDataRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
immoDataRef.removeValue();
pictureDataRef.removeValue();
contactDataRef.removeValue();
Fragment showAllExpose = new ShowAllExposeFragment();
manager.beginTransaction().replace(R.id.content_frame, showAllExpose).commit();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
break;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onStart() {
super.onStart();
// attaching the ValueEventListener
pictureDataRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// check if there are values in the database
if (dataSnapshot.getValue() != null) {
// clear the list of immos
pictureUploads.clear();
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
// getting the immo
PictureUpload pictureUpload = postSnapshot.getValue(PictureUpload.class);
// adding the immo to the list
pictureUploads.add(pictureUpload);
}
// creating the List Adapter and add him to the Listview
final AttachmentList attachmentAdapter = new AttachmentList((Activity) getContext(), pictureUploads);
show_all_attachments_list.setAdapter(attachmentAdapter);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
when I try to run my app on my device I'm always getting the following error:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.webgalaxie.blischke.bachelortakesix, PID: 14901
java.lang.NullPointerException: Attempt to invoke interface method 'void java.util.List.clear()' on a null object reference
at com.webgalaxie.blischke.bachelortakesix.fragments.tabfragments.AttachmentTabFragment$3.onDataChange(AttachmentTabFragment.java:191)
at com.google.android.gms.internal.zzegf.zza(Unknown Source)
at com.google.android.gms.internal.zzeia.zzbyc(Unknown Source)
at com.google.android.gms.internal.zzeig.run(Unknown Source)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6682)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)
Does anyone have an idea why this happens. I'm a bit stuck on this issue.
Thank you very much for your help. If you need more information on the project do not hesitate to ask.
I also have the code to the project on GitHub if you need more information.
Link to GitHub: https://github.com/BexxBl/BachelorTakeSix
That's because in your onStart() method you're calling clear() on a list that hasn't been initialized yet. You should initialize it instead of clearing it:
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// check if there are values in the database
if (dataSnapshot.getValue() != null) {
// clear the list of immos
pictureUploads = new ArrayList();
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
// getting the immo
PictureUpload pictureUpload = postSnapshot.getValue(PictureUpload.class);
// adding the immo to the list
pictureUploads.add(pictureUpload);
}
// creating the List Adapter and add him to the Listview
final AttachmentList attachmentAdapter = new AttachmentList((Activity) getContext(), pictureUploads);
show_all_attachments_list.setAdapter(attachmentAdapter);
}
}
EDIT: The value of your snapshot is a String. You need to get the key as well and pass it to your PictureUpload class.
String val = postSnapshot.getValue(String.class);
PictureUpload pictureUpload = new PictureUpload(postSnapshot.getKey(), val);
pictureUploads.add(pictureUpload);
i am trying to read a specific child in Firebase which i named Tags. the problem is, i just can't put the object from tags (dados.getValue) into a ArrayList to later populate in my ListView.
I know is simple, sorry about that, ut i am new here in android
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_taglist);
tags = new ArrayList<>();
tagList = (ListView) findViewById(R.id.tagsList);
tagsRefs = FirebaseConfig.getFireBase();
tagsRefs.child("tags").child("categorias");
tagsRefs.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot dados : dataSnapshot.child("tags").getChildren()) {
System.out.println("tag EXTRAIDA NO taglist " + dados.getValue());
dados.getValue(); //HOW CAN I PUT THIS INTO AN ARRAY TO LATER ADD IN MY ArrayList tags??
String tagS = dados.getValue(String.class);
tags.addAll(tagS);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
tagAdapter = new ArrayAdapter(getBaseContext(), android.R.layout.simple_list_item_2,
android.R.id.text1,
tags);
tagList.setAdapter(tagAdapter);
tagList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
selectedTag = (String) tagList.getItemAtPosition(position);
setSelectedTag(selectedTag);
}
});
}
here is my database:
h
This is happening because onDataChange() method is called asynchronously. This means that the statement that adds tags to your list is executed before onDataChange() method has been called. That's why your list is empty outside that method. So in order to use that lists, you need to use it inside the onDataChange().
For other approach, please visit this post and this post.
Hope it helps.
I am using Firebase for my apps back end and I am retrieving my data as excepted. After I retrieve my data, I am posting it by using otto bus and the code can be seen below.
#Subscribe
public void loadBrothers(ServiceCalls.SearchBrothersRequest request) {
final ServiceCalls.SearchBrothersResponse response = new ServiceCalls.SearchBrothersResponse();
response.Brothers = new ArrayList<>();
Firebase reference = new Firebase("my data's url here");
reference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
int index = 0;
for (DataSnapshot brotherSnapchat : dataSnapshot.getChildren()) {
BrotherFireBase bro = brotherSnapchat.getValue(BrotherFireBase.class);
Log.i(LOG_TAG, bro.getName());
Log.i(LOG_TAG, bro.getWhy());
Log.i(LOG_TAG, bro.getPicture());
Log.i(LOG_TAG, bro.getMajor());
Log.i(LOG_TAG, bro.getCross());
Log.i(LOG_TAG, bro.getFact());
Brother brother = new Brother(
index,
bro.getName(),
bro.getWhy(),
bro.getPicture(),
bro.getMajor(),
bro.getCross(),
bro.getFact());
response.Brothers.add(brother);
index++;
}
bus.post(response);
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
Once the data is in my RecyclerView, I am to click an item and it's respective activity is to pop up in a custom activity dialog. However, since the activity is a dialog, you can see the RecyclerView reloading in the background. This does not happen when I do not retrieve the data from the internet. After a few clicks around, the app crashes due to an out of memory exception. Is there something I am missing?
Here is the activity where the recyclerView is found:
#Override
public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_meet_a_brother, container, false);
adapter = new BrotherRecycleAdapter((BaseActivity) getActivity(),this);
brothers = adapter.getBrothers();
recyclerView =(RecyclerView) view.findViewById(R.id.fragment_meet_a_brother_recycleView);
recyclerView.setLayoutManager(new GridLayoutManager(getActivity(),3));
setUpAdapter();
bus.post(new ServiceCalls.SearchBrothersRequest("Hello"));
return view;
}
private void setUpAdapter(){
if(isAdded()){
recyclerView.setAdapter(adapter);
}
}
#Subscribe
public void onBrosLoaded(final ServiceCalls.SearchBrothersResponse response){
int oldBrotherLength = brothers.size();
brothers.clear();
adapter.notifyItemRangeRemoved(0, oldBrotherLength);
brothers.addAll(response.Brothers);
//Delete for Debug method...
adapter.notifyItemRangeChanged(0,brothers.size());
Log.i(LOG_TAG, Integer.toString(brothers.size()));
}
#Override
public void onBrotherClicked(Brother brother) {
Intent intent = BrotherPagerActivity.newIntent(getActivity(),brother);
Log.i(LOG_TAG,brother.getBrotherName() + " was Clicked");
startActivity(intent);
}
Just in case, here is also the activity that is started when a list item is clicked, it is a viewPager activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_brother_pager);
brothers = new ArrayList<>();
bus.post(new ServiceCalls.SearchBrothersRequest("Hello"));
FragmentManager fragmentManager = getSupportFragmentManager();
viewPager = (ViewPager) findViewById(R.id.activity_brother_viewPager);
viewPager.setAdapter(new FragmentStatePagerAdapter(fragmentManager) {
#Override
public Fragment getItem(int position) {
Brother brother = brothers.get(position);
return BrotherDetailsFragment.newInstance(brother);
}
#Override
public int getCount() {
return brothers.size();
}
});
}
#Subscribe
public void onBrosLoad(final ServiceCalls.SearchBrothersResponse response){
brothers.clear();
brothers.addAll(response.Brothers);
viewPager.getAdapter().notifyDataSetChanged();
Brother brother = getIntent().getParcelableExtra(BROTHER_EXTRA_INFO);
int brotherId = brother.getBrotherId();
for(int i=0;i<brothers.size();i++){
if(brothers.get(i).getBrotherId() == brotherId){
viewPager.setCurrentItem(i);
break;
}
}
Log.i(LOG_TAG, Integer.toString(brothers.size()));
}
public static Intent newIntent(Context context, Brother brother){
Intent intent = new Intent(context,BrotherPagerActivity.class);
intent.putExtra(BROTHER_EXTRA_INFO,brother);
return intent;
}
Any help is greatly appreciated thank you!
in public void onBrotherClicked(Brother brother) where RecyclerView resides, you call:
Intent intent = BrotherPagerActivity.newIntent(getActivity(),brother);
which will call
Intent intent = new Intent(context,BrotherPagerActivity.class);`
in newIntent of your viewPager activity.
This could be a recursive call.
try adding:
public static Intent newIntent(Context context, Brother brother){
Intent intent = new Intent(context,BrotherPagerActivity.class);
intent.putExtra(BROTHER_EXTRA_INFO,brother);
return intent;
}
in Activity where your RecyclerView resides. And call your ViewPage activity there.
-- UPDATE --
Call your viewpager activity (which is used to show Brother data) with the following code:
private void showBrotherData(Brother brother){
Intent intent = new Intent(this, BrotherPagerActivity.class);
intent.putExtra(BROTHER_EXTRA_INFO, brother);
this.startActivity(intent);
}
I found the answer! I changed my recyclerView to only updated if the size of the array was zero.
#Subscribe
public void onBrosLoaded(final ServiceCalls.SearchBrothersResponse response){
int oldBrotherLength = brothers.size();
Log.i(LOG_TAG, "Brother lists old size" + Integer.toString(oldBrotherLength));
if(oldBrotherLength ==0){
brothers.clear();
adapter.notifyItemRangeRemoved(0, oldBrotherLength);
brothers.addAll(response.Brothers);
//Delete for Debug method...
adapter.notifyItemRangeChanged(0,brothers.size());
} else{
return;
}
Log.i(LOG_TAG, Integer.toString(brothers.size()));
}
I don't know how good this solution is in terms of cleaness but it works for me. I hope this helps someone.
My app tries to get various information from an api call using Retrofit and Gson. This information needs to be displayed as a gridview and the gridview needs to repopulate on scrolling. As of now, I can get the first 10 items, and thats it. How to add the endless scrolling feature to this.
public class ProductListing extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.product_listing_act);
init();
}
public void productListingApiCall() {
RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint(base_url).setLogLevel(RestAdapter.LogLevel.FULL).build();
final ProductListingApi productListingApi =
restAdapter.create(ProductListingApi.class);
productListingApi.getFeed(file, operation_condition, search_string_condition, minprice_condition, maxprice_condition, mincusratings_condition,
maxcusratings_condition, discount_condition, catids_condition, brands_condition, affids_condition, start_row_condition, limit_condition,
orderby_condition, sortby_condition, new Callback<ProductListingPojo>() {
#Override
public void success(ProductListingPojo productListingPojo, Response response) {
final ProductListingPojo product = productListingPojo;
new Thread(new Runnable() {
#Override
public void run() {
product_key = Arrays.copyOf(product.getProductkey(),
product.getProductkey().length);
cs_category_id = Arrays.copyOf(product.getCsCategoryid(),
product.getCsCategoryid().length);
title = Arrays.copyOf(product.getTitle(),
product.getTitle().length);
price = Arrays.copyOf(product.getSellingprice(),
product.getSellingprice().length);
mrp = Arrays.copyOf(product.getMrp(),
product.getMrp().length);
discount = Arrays.copyOf(product.getDiscountpercent(),
product.getDiscountpercent().length);
image = Arrays.copyOf(product.getProductimageSmall1(),
product.getProductimageSmall1().length);
cus_agg_num = Arrays.copyOf(product.getCustratingAggNum(),
product.getCustratingAggNum().length);
}
}).run();
setAdapter();
}
#Override
public void failure(RetrofitError error) {
tv_title_header.setText(error.getMessage());
Log.e("error", error.getMessage());
}
});
}
void setAdapter() {
adapter = new ProductListingGridAdapter(this, title, image, price, mrp, discount);
gv_product_listing_act.setAdapter(adapter);
}
}
The init() in OnCreate() will initialise all the view and call the productListingApiCall() for the first time. The way the api works is that, i will request for the first 10 items (start_row_condition: 0 and limit: 10), then on reaching the bottom after scrolling it should add the next 10, hence i need to call the api with (start_row_condition: 10 and limit:10). How can i implement this.