ArrayAdapter not displaying data in Fragment - java

I have seen a lot of similar questions about this issue but I couldn't find any solution to this:
I have three fragments in a TabLayout handled by a ViewPager and I have a ListView in the third Fragment which is not displaying any items after I change the orientation of the screen. I have tried to set a background color to the convertView in the ArrayAdapter to see if it was displayed and indeed it is not being displayed after I change the orientation. But it's weird because in my First Fragment where I use the same ArrayAdapter for another ListView everything's working and I can't understand why it's not on the third Fragment.
One thing is sure: I have checked with logs almost everywhere that the ArrayList.size() is never zero.
Here's the Third Fragment's relevant code:
public class SavedScanFragment extends Fragment{
private ListView lv;
private Database db;
private ArrayList<Scan> scans;
private ScanAdapter adapter;
public static SavedScanFragment newInstance() {
return new SavedScanFragment();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
db = new Database(getContext());
getScans();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View result = inflater.inflate(R.layout.fragment_saved_scan, container, false);
lv = (ListView) result.findViewById(R.id.saved_scan_list);
return result;
}
#Override
public void onResume() {
super.onResume();
db = new Database(getContext());
getScans();
}
public void getScans() {
AsyncTask<Void, Void, Boolean> task = new AsyncTask<Void, Void, Boolean>() {
#Override
protected Boolean doInBackground(Void... params) {
scans = db.getScans();
if(scans!=null)
return true;
else {
scans = new ArrayList<>();
return false;
}
}
#Override
protected void onPostExecute(Boolean result) {
if(result)
populateList();
}
};
task.execute();
}
public void populateList() {
if(getContext()!=null) {
if (lv.getAdapter() == null) {
adapter = new ScanAdapter(getContext(), R.layout.scan_list_item, scans);
lv.setAdapter(adapter);
} else {
((ScanAdapter) lv.getAdapter()).update(scans);
}
}
}
And the ArrayAdapter's code:
public class ScanAdapter extends ArrayAdapter<Scan> implements ListAdapter {
private Context context;
private int layoutResourceID;
private ArrayList<Scan> results;
public ScanAdapter(Context context, int layoutResourceID, ArrayList<Scan> results) {
super(context, layoutResourceID, results);
this.context = context;
this.layoutResourceID = layoutResourceID;
this.results = results;
}
public void update(ArrayList<Scan> scans) {
results.clear();
results.addAll(scans);
notifyDataSetChanged();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView; //view = row
ViewHolder holder = null;
if(view == null) {
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(layoutResourceID, parent, false);
view.setBackgroundColor(Color.GREEN);
holder = new ViewHolder();
holder.name = (TextView)view.findViewById(R.id.scan_name_and_date_text);
holder.ssid = (TextView)view.findViewById(R.id.scan_SSID_text);
holder.frequency = (TextView)view.findViewById(R.id.scan_frequency_text);
holder.level = (TextView)view.findViewById(R.id.scan_level_text);
view.setTag(holder);
} else
holder = (ViewHolder) view.getTag();
Scan sr = results.get(position);
holder.name.setText(sr.getName()+" ( "+sr.getDate()+" )");
holder.ssid.setText(sr.getSsid() + " ( " + sr.getBssid() + " )");
holder.frequency.setText(sr.getFrequency()+" MHz");
holder.level.setText(Integer.toString(sr.getLevel())+ " dBm");
return view;
}
static class ViewHolder {
TextView name,ssid, frequency, level;
}
}
Thanks in advance!

From this post. You can try to use onActivityCreated instead of onCreate. Try this:
public class SavedScanFragment extends Fragment{
//....to restore the saved state
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//Restore the fragment state here
db = new Database(getContext());
getScans();
}
//add this to save instant state
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//save your important variable here to outstate
}
}

Related

Clear bundler data

In my fragment I have an EditText which basically allows, when submitted, to query the values from Firebase Realtime Database and show them in a Recycler View.
Everything is fine when I search the first time but, when I search more than once, the previous results stay in the Recycler View.
I've tried to clear my lists but I got no success. I think I found the problem but I just can't solve it. I need to clear my bundle everytime I pass the retrieved values from the DB from one fragment to another. This is my fragment code (where I call the adaptor, not where I retrieve the DB values):
public class FilteredResultsFragment extends android.support.v4.app.Fragment {
ImageAdapter imageAdapter;
List<String> listOfImages = new ArrayList<>();
List<String> listOfNames = new ArrayList<>();
private RecyclerView recyclerView;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View viewFilteredResults = inflater.inflate(R.layout.fragment_filtered_results, container, false);
recyclerView = viewFilteredResults.findViewById(R.id.recyclerViewFiltered);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
imageAdapter = new ImageAdapter(listOfImages, listOfNames, getContext());
recyclerView.setAdapter(imageAdapter);
return viewFilteredResults;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (getArguments() != null) {
removeAll();
listOfImages.addAll(getArguments().getStringArrayList("listOfImages"));
listOfNames.addAll(getArguments().getStringArrayList("listOfNames"));
Log.d("IMAGENS", "img "+listOfImages);
Log.d("Nomes","nome "+listOfNames);
imageAdapter.notifyDataSetChanged();
}
}
public void removeAll(){
listOfImages.clear();
listOfNames.clear();
imageAdapter.notifyDataSetChanged();
}
}
As you can see, I've created a function that should allow me to clear the data... And this is my Adaptor:
public class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ImageViewHolder> {
List<String> listaPaisesFiltrados;
List<String> listaNomesFiltrados;
android.content.Context context;
ImageAdapter(List<String> listaPaisesFiltrados, List<String> listaNomesFiltrados, android.content.Context c) {
this.listaPaisesFiltrados = listaPaisesFiltrados;
this.listaNomesFiltrados = listaNomesFiltrados;
this.context = c;
}
#NonNull
#Override
public ImageViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item_view, parent, false);
return new ImageViewHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull ImageViewHolder holder, int position) {
String imageUrl = listaPaisesFiltrados.get(holder.getAdapterPosition());
String nomePais = listaNomesFiltrados.get(holder.getAdapterPosition());
android.content.Context context1 = context.getApplicationContext();
Log.d("ADAPTER", "imageUrl : " + imageUrl + " position : " + holder.getAdapterPosition());
Typeface tpPaisNome = Typeface.createFromAsset(holder.itemView.getContext().getAssets(),"fonts/RobotoSlab-Bold.ttf"); // Define a Typeface
holder.textView.setTypeface(tpPaisNome);
holder.textView.setText(nomePais);
Glide.with(holder.imageView.getContext()).load(imageUrl).centerCrop().into(holder.imageView);
}
#Override
public int getItemCount() {
Log.d("ADAPTER", "SIZE : " + listaPaisesFiltrados.size());
return listaPaisesFiltrados.size();
}
public class ImageViewHolder extends RecyclerView.ViewHolder {
ImageView imageView;
TextView textView;
public ImageViewHolder(View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.imgPaisFiltrado);
textView = itemView.findViewById(R.id.txtNomePaisFiltrado);
}
}
}
EDIT
In my ExploreFragment (where I have the query and the EditText) I send two ArrayLists via Bundle to the fragment that opens the adaptor. I need to clear my Bundler but, when I use blunder.clear() than no value is passed to the other fragment and no image is displayed. This is my code
srcView.setOnEditorActionListener(new EditText.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
boolean handled = false;
if (actionId == EditorInfo.IME_ACTION_DONE) {
txtRecomendado.setVisibility(View.INVISIBLE);
scrollView.setVisibility(View.INVISIBLE);
final Bundle bundler = new Bundle();
bundler.clear();
FirebaseDatabase mDatabase = FirebaseDatabase.getInstance();
DatabaseReference paisNomeContinentes = mDatabase.getReference().child("paises");
Query queries = paisNomeContinentes.orderByChild("Nome").startAt(String.valueOf(srcView.getText())).endAt(String.valueOf(srcView.getText())+"\uf8ff");
Log.d("AQUIPUTO","teste "+String.valueOf(srcView.getText()));
queries.addListenerForSingleValueEvent(new com.google.firebase.database.ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
List<String> imagemPaisList = new ArrayList<>();
List<String> nomePaisList = new ArrayList<>();
for (DataSnapshot ds : dataSnapshot.getChildren()) {
String imagemPais = ds.child("Imagem").getValue(String.class);
String nomePais = ds.child("Nome").getValue(String.class);
imagemPaisList.add(imagemPais);
nomePaisList.add(nomePais);
}
int urlCount = imagemPaisList.size();
// int randomImage = new Random().nextInt(urlCount);
for (int i = 0; i < nomePaisList.size(); i++) {
//Integer randomVariavel = new Random().nextInt(urlCount);
randomImagemPaisList.add(imagemPaisList.get(i));
randomNomePaisList.add(nomePaisList.get(i));
}
getFragmentManager().popBackStack();
FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
transaction.setCustomAnimations(R.anim.slide_up_info,R.anim.slide_down_info);
FilteredResultsFragment fragment = new FilteredResultsFragment();
bundler.putStringArrayList("listOfImages", (ArrayList<String>) randomImagemPaisList);
bundler.putStringArrayList("listOfNames", (ArrayList<String>) randomNomePaisList);
fragment.setArguments(bundler);
transaction.replace(R.id.fragContainerExploreFilteredResults, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
How can I clear my bundle? I've tried to clear it after I use:
bundler.putStringArrayList("listOfImages", (ArrayList<String>) randomImagemPaisList);
bundler.putStringArrayList("listOfNames", (ArrayList<String>) randomNomePaisList);
fragment.setArguments(bundler);
And if I do this no value is passed from one fragment to another. I've tried to clear it when the fragment.trasaction is complete but I still get the same 'error'...
might be possible that updated data is not notify with recyclerview, you can create doRefresh method in adapter class and then update the list and notify it, please see the below code
Fragment Code
public class FilteredResultsFragment extends android.support.v4.app.Fragment {
ImageAdapter imageAdapter;
List<String> listOfImages = new ArrayList<>();
List<String> listOfNames = new ArrayList<>();
private RecyclerView recyclerView;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View viewFilteredResults = inflater.inflate(R.layout.fragment_filtered_results, container, false);
setAdapter();
return viewFilteredResults;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (getArguments() != null) {
listOfImages.clear();
listOfNames.clear();
listOfImages.addAll(getArguments().getStringArrayList("listOfImages"));
listOfNames.addAll(getArguments().getStringArrayList("listOfNames"));
Log.d("IMAGENS", "img "+listOfImages);
Log.d("Nomes","nome "+listOfNames);
setAdapter();
}
}
private void setAdapter() {
if (listOfImages != null && listOfNames != null) {
if (imageAdapter == null) {
imageAdapter = new ImageAdapter(getContext());
}
imageAdapter.doRefresh(listOfImages, listOfNames);
if (recyclerView.getAdapter() == null) {
recyclerView = viewFilteredResults.findViewById(R.id.recyclerViewFiltered);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setAdapter(imageAdapter);
}
}
}
}
and Adapter class as below
public class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ImageViewHolder> {
List<String> listaPaisesFiltrados;
List<String> listaNomesFiltrados;
android.content.Context context;
ImageAdapter(android.content.Context c) {
this.context = c;
}
public void doRefresh(List<String> listaPaisesFiltrados, List<String> listaNomesFiltrados) {
this.listaPaisesFiltrados = listaPaisesFiltrados;
this.listaNomesFiltrados = listaNomesFiltrados;
notifyDataSetChanged();
}
#NonNull
#Override
public ImageViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item_view, parent, false);
return new ImageViewHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull ImageViewHolder holder, int position) {
String imageUrl = listaPaisesFiltrados.get(holder.getAdapterPosition());
String nomePais = listaNomesFiltrados.get(holder.getAdapterPosition());
android.content.Context context1 = context.getApplicationContext();
Log.d("ADAPTER", "imageUrl : " + imageUrl + " position : " + holder.getAdapterPosition());
Typeface tpPaisNome = Typeface.createFromAsset(holder.itemView.getContext().getAssets(),"fonts/RobotoSlab-Bold.ttf"); // Define a Typeface
holder.textView.setTypeface(tpPaisNome);
holder.textView.setText(nomePais);
Glide.with(holder.imageView.getContext()).load(imageUrl).centerCrop().into(holder.imageView);
}
#Override
public int getItemCount() {
Log.d("ADAPTER", "SIZE : " + listaPaisesFiltrados.size());
return listaPaisesFiltrados.size();
}
public class ImageViewHolder extends RecyclerView.ViewHolder {
ImageView imageView;
TextView textView;
public ImageViewHolder(View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.imgPaisFiltrado);
textView = itemView.findViewById(R.id.txtNomePaisFiltrado);
}
}
}
you can try to create new adapter and set to your recycler.
listOfImages.clear();
listOfNames.clear();
/*
Adding your new searching data here
*/
recyclerView.setAdapter(new ImageAdapter(listOfImages, listOfNames, getContext());
recyclerView.invalidate();
When you try to clear by calling removeAll, you only clear the list objects from the Fragment class. What you need is to clear the list objects in your RecyclerView.Adapter class.
Try this:
Move your removeAll to your adapter. That way, you clear the list objects in that adapter.
In your Fragment, just call your removeAll from your Adapter.
Sample Code:
Fragment.java
//No more removeAll() here
public void callAdapterToRemove() {
imageAdapter.removeAll();
}
ImageAdapter.java
//Now it's here
public void removeAll() {
listaPaisesFiltrados.clear();
listaNomesFiltrados.clear();
notifyDataSetChanged();
}

query() method of Content provider returns data twice in recycler View adapter

I am working on a android project, here i have a class CategoryProvider which extends ContentProvider class and i also implements LoaderManager.LoaderCallbacks<Cursor> in my main Activity and I also have CategoryAdapter class which extends RecyclerView.Adapter<CategoryAdapter.ViewHolder>. I have 3 records in my Sqlite database, now after initialization of Loader in main Activity when data is loading in the adapter it loads each record twice so how to fix that.
CategotyAdapter.java
public class CategoryAdapter extends RecyclerView.Adapter<CategoryAdapter.ViewHolder> {
Cursor dataCursor;
Context context;
String global_lang = "English";
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView name;
ImageView imageView;
public ViewHolder(View itemView) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.titleText);
imageView = (ImageView) itemView.findViewById(R.id.icons);
}
}
public CategoryAdapter(Activity mContext, Cursor cursor) {
dataCursor = cursor;
context = mContext;
}
#Override
public CategoryAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View cardview = LayoutInflater.from(parent.getContext())
.inflate(R.layout.option_layout, parent, false);
return new ViewHolder(cardview);
}
#Override
public void onBindViewHolder(CategoryAdapter.ViewHolder holder, int position) {
dataCursor.moveToPosition(position);
String imagePath = dataCursor.getString(dataCursor.getColumnIndex(CategoryContract.CategoryEntry.COLUMN_IMAGE_PATH));
String cEn_name = dataCursor.getString(dataCursor.getColumnIndex(CategoryContract.CategoryEntry.COLUMN_CONTENT_EN));
String cHi_name = dataCursor.getString(dataCursor.getColumnIndex(CategoryContract.CategoryEntry.COLUMN_CONTENT_HI));
if(global_lang.equals("English"))
holder.name.setText(cEn_name);
else
holder.name.setText(cHi_name);
Glide.with(context)
.load(imagePath)
.apply(new RequestOptions()
.placeholder(R.drawable.loading))
.into(holder.imageView);
}
public Cursor swapCursor(Cursor cursor) {
if(dataCursor == cursor) {
return null;
}
Cursor oldCursor = dataCursor;
this.dataCursor = cursor;
if(cursor != null) {
this.notifyDataSetChanged();
}
return oldCursor;
}
#Override
public int getItemCount() {
if(dataCursor != null)
Log.d("datacursor count", " " +dataCursor.getCount());
else
Log.d("datacursor count", "datacursor is null");
return (dataCursor == null) ? 0 : dataCursor.getCount();
}
public void changeLang(String lang) {
this.global_lang = lang;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return position;
}
}
MainActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
firstTimeUser();
ActivityToolbar = (Toolbar) findViewById(R.id.toolbar);
ActivitySpinner = (Spinner) findViewById(R.id.spinner);
ActivityToolbar.setTitle(R.string.app_name);
ActivityAdapter = ArrayAdapter.createFromResource(this, R.array.languages, R.layout.drop_menu);
ActivityAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
ActivitySpinner.getBackground().setColorFilter(getResources().getColor(R.color.white), PorterDuff.Mode.SRC_ATOP);
ActivitySpinner.setAdapter(ActivityAdapter);
listeners();
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
if(this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
recyclerView.setLayoutManager(new GridLayoutManager(this, 2));
} else {
recyclerView.setLayoutManager(new GridLayoutManager(this, 4));
}
categoryAdapter = new CategoryAdapter(this, null);
recyclerView.setAdapter(categoryAdapter);
getLoaderManager().initLoader(CATEGORY_LOADER, null, this);
}
public void listeners() {
ActivitySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
categoryAdapter.changeLang(ActivitySpinner.getSelectedItem().toString());
getLoaderManager().restartLoader(CATEGORY_LOADER, null, MainActivity.this);
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] data = {
CategoryContract.CategoryEntry._ID,
CategoryContract.CategoryEntry.COLUMN_IMAGE_PATH,
CategoryContract.CategoryEntry.COLUMN_CONTENT_EN,
CategoryContract.CategoryEntry.COLUMN_CONTENT_HI
};
return new CursorLoader(
this,
CategoryContract.CategoryEntry.CONTENT_URI,
data,
null,
null,
null
);
}
#Override
protected void onResume() {
super.onResume();
loader_flag = 0;
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
categoryAdapter.swapCursor(data);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
categoryAdapter.swapCursor(null);
}
Thanks!!
Ok, I got it after a lot of debugging. Here I am using Sync Adapter framework in my App which syncs the data at the background, when it trying to reload data the duplicate data is synced rapidly with new ID and it was rendered by recyclerView. so now I am using some constraints and changing my Database structure.

Problems calling notifyDataSetChange in RecyclerViewHolder

I am having problems updating my RecyclerView with new data. If I press a confirmation button on a CardView in the first tab, the card should get added to the second tab but it won't update it there until I rotate the screen. I get the data for the card from reading a text file. Please advise me how to call the notifyDataSetChange method after I have added the new data to my text file. I have tried everything and all I get is NullPointerExceptions. The RecyclerViews are in fragments and I use FragementStatePagerAdapter.
I'll put some of my classes here. Ask if you need more information.
RecyclerViewAdapter.java
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewHolder> {
private List<String> mListTitle;
private List<String> mListDesc;
private List<String> mListPoints;
private List<String> mListDates;
private String fragment_tag;
public RecyclerViewAdapter() {
}
public RecyclerViewAdapter(List<List<String>> super_list, String tag) {
this.mListTitle = super_list.get(0);
this.mListDesc = super_list.get(1);
this.mListPoints = super_list.get(2);
this.mListDates = super_list.get(3);
fragment_tag = tag;
}
#Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
return new RecyclerViewHolder(inflater, parent, fragment_tag);
}
#Override
public void onBindViewHolder(RecyclerViewHolder holder, int position) {
holder.mTitleText.setText(mListTitle.get(position));
holder.mDescText.setText(mListDesc.get(position));
holder.mPointsText.setText(mListPoints.get(position));
if (fragment_tag.equals("completed")) {
holder.mDateText.setText(mListDates.get(position));
}
}
#Override
public int getItemCount() {
return mListTitle.size();
}
}
class RecyclerViewHolder extends RecyclerView.ViewHolder {
RecyclerView recyclerView;
RecyclerViewAdapter mAdapter;
public TextView mTitleText, mDescText, mDateText, mPointsText, popupTitle;
public Button mConfButton, popCancelBtn, popAcceptBtn;
public RecyclerViewHolder(View itemView) {
super(itemView);
}
public RecyclerViewHolder(final LayoutInflater inflater, final ViewGroup container, String tag) {
// Inflating the card layout depending on the tag parameter.
super(inflater.inflate
((tag.equals("challenges")) ? R.layout.card_view_chall : R.layout.card_view_comp, container,
false));
mTitleText = itemView.findViewById(R.id.title_holder);
mDescText = itemView.findViewById(R.id.desc_holder);
mPointsText = itemView.findViewById(R.id.points_holder);
mDateText = itemView.findViewById(R.id.date_holder);
if (tag.equals("challenges")) {
mConfButton = itemView.findViewById(R.id.card_conf_button);
mConfButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Setting the layout inflater for popup window.
LayoutInflater pInflater = (LayoutInflater) itemView.getContext().getSystemService(LAYOUT_INFLATER_SERVICE);
ViewGroup container1 = (ViewGroup) pInflater.inflate(R.layout.confirmation_popup, null);
final PopupWindow popupWindow = new PopupWindow(container1, 700, 600, true);
popupTitle = container1.findViewById(R.id.popuptext);
popAcceptBtn = container1.findViewById(R.id.accept_button);
popCancelBtn = container1.findViewById(R.id.cancel_button);
popupTitle.setText(mTitleText.getText().toString());
// Dismisses the popup window
popCancelBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
popupWindow.dismiss();
}
});
// Click listener for dialog accept button.
popAcceptBtn.setOnClickListener(new View.OnClickListener() {
String date;
#Override
public void onClick(View view) {
List<String> list = new ArrayList<>();
list.add(mTitleText.getText().toString());
list.add(mDescText.getText().toString());
list.add(mPointsText.getText().toString());
list.add(date = new SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(new Date()));
// Saving data from current card into the completed challenges list.
TempDataReader reader = new TempDataReader(itemView.getContext());
new TempDataReader(itemView.getContext()).saveFile(list);
// I want to notify the dataset change here if possible!
popupWindow.dismiss();
}
});
popupWindow.showAtLocation(itemView, Gravity.CENTER, 25, 100);
}
});
}
}
}
SectionsPagerAdapter.java
public class SectionsPagerAdapter extends FragmentStatePagerAdapter{
private ViewPager viewPager;
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public void addFragment(Fragment fragment, String title){
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
#Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
}
}
CompletedFragment.java
public class CompletedFragment extends Fragment {
RecyclerView recyclerView;
RecyclerViewAdapter adapter;
public Fragment newInstance() {
return new CompletedFragment();
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.completed_fragment, container, false);
recyclerView = view.findViewById(R.id.completed_frag);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
TempDataReader reader = new TempDataReader(getActivity());
List<List<String>> super_list = reader.readCompFile();
if(super_list == null || super_list.size() < 1){
return null;
} else{
adapter = new RecyclerViewAdapter(super_list,"completed");
recyclerView.setAdapter(adapter);
return view;
}
}
}
EDIT:
Added the code for the second fragment, which is the one that should be updated after the onClick at RecyclerViewHolder-class.
You have to add a function in your adapter for adding data:
public void addData(String title, String desc, String point, String date) {
this.mListTitle.add(title);
this.mListDesc.add(desc);
this.mListPoints.add(point);
this.mListDates.add(date);
notifyDataSetChanged();
}
If you want to enable animations call notifyItemInserted() instead of notifyDataSetChanged();
It is important that you add a String to every list because in your onBindViewHolder() you get the item to display from every list with list.get(position). Otherwise you'll get a IndexOutOfBoundsException.
You can create an interface and use as a callback. Send it as a parameter of the RecyclerViewAdapter and then to your RecyclerViewHolder. When the item should be added you call the callback that will get you back to your fragment. There you can read the file again and call notifyDataSetChanged.
I know i explain pretty bad so i will try to change your code so that it does what i said:
this will be your RecyclerViewAdapter:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewHolder> {
private List<String> mListTitle;
private List<String> mListDesc;
private List<String> mListPoints;
private List<String> mListDates;
private String fragment_tag;
private Runnable callback;
public RecyclerViewAdapter() {
}
public RecyclerViewAdapter(List<List<String>> super_list, String tag, Runnable callBack) {
//add the callback here(Runnable) and save it into a local variable
this.callback=callback;
this.mListTitle = super_list.get(0);
this.mListDesc = super_list.get(1);
this.mListPoints = super_list.get(2);
this.mListDates = super_list.get(3);
fragment_tag = tag;
}
#Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
return new RecyclerViewHolder(inflater, parent, fragment_tag, callback);
//send the callback to your viewHolder
}
#Override
public void onBindViewHolder(RecyclerViewHolder holder, int position) {
holder.mTitleText.setText(mListTitle.get(position));
holder.mDescText.setText(mListDesc.get(position));
holder.mPointsText.setText(mListPoints.get(position));
if (fragment_tag.equals("completed")) {
holder.mDateText.setText(mListDates.get(position));
}
}
#Override
public int getItemCount() {
return mListTitle.size();
}
}
class RecyclerViewHolder extends RecyclerView.ViewHolder {
RecyclerView recyclerView;
RecyclerViewAdapter mAdapter;
public TextView mTitleText, mDescText, mDateText, mPointsText, popupTitle;
public Button mConfButton, popCancelBtn, popAcceptBtn;
public RecyclerViewHolder(View itemView) {
super(itemView);
}
public RecyclerViewHolder(final LayoutInflater inflater, final ViewGroup container, String tag, Runnable callback) {
//ADD the callback to the parameters list here
// Inflating the card layout depending on the tag parameter.
super(inflater.inflate
((tag.equals("challenges")) ? R.layout.card_view_chall : R.layout.card_view_comp, container,
false));
mTitleText = itemView.findViewById(R.id.title_holder);
mDescText = itemView.findViewById(R.id.desc_holder);
mPointsText = itemView.findViewById(R.id.points_holder);
mDateText = itemView.findViewById(R.id.date_holder);
if (tag.equals("challenges")) {
mConfButton = itemView.findViewById(R.id.card_conf_button);
mConfButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Setting the layout inflater for popup window.
LayoutInflater pInflater = (LayoutInflater) itemView.getContext().getSystemService(LAYOUT_INFLATER_SERVICE);
ViewGroup container1 = (ViewGroup) pInflater.inflate(R.layout.confirmation_popup, null);
final PopupWindow popupWindow = new PopupWindow(container1, 700, 600, true);
popupTitle = container1.findViewById(R.id.popuptext);
popAcceptBtn = container1.findViewById(R.id.accept_button);
popCancelBtn = container1.findViewById(R.id.cancel_button);
popupTitle.setText(mTitleText.getText().toString());
// Dismisses the popup window
popCancelBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
popupWindow.dismiss();
}
});
// Click listener for dialog accept button.
popAcceptBtn.setOnClickListener(new View.OnClickListener() {
String date;
#Override
public void onClick(View view) {
List<String> list = new ArrayList<>();
list.add(mTitleText.getText().toString());
list.add(mDescText.getText().toString());
list.add(mPointsText.getText().toString());
list.add(date = new SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(new Date()));
// Saving data from current card into the completed challenges list.
TempDataReader reader = new TempDataReader(itemView.getContext());
new TempDataReader(itemView.getContext()).saveFile(list);
// I want to notify the dataset change here if possible!
//call the callback
callback.run();
popupWindow.dismiss();
}
});
popupWindow.showAtLocation(itemView, Gravity.CENTER, 25, 100);
}
});
}
}
}
And this will be your fragment:
public class CompletedFragment extends Fragment {
RecyclerView recyclerView;
RecyclerViewAdapter adapter;
public Fragment newInstance() {
return new CompletedFragment();
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.completed_fragment, container, false);
recyclerView = view.findViewById(R.id.completed_frag);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
TempDataReader reader = new TempDataReader(getActivity());
List<List<String>> super_list = reader.readCompFile();
if(super_list == null || super_list.size() < 1){
return null;
} else{
adapter = new RecyclerViewAdapter(super_list,"completed", new Runnable() {
#Override
public void run() {
//here read the list again and call notifyDataSetChanged on your recycler
}
});
);
recyclerView.setAdapter(adapter);
return view;
}
}
}
Hope it helps and it works for you. If i did anything wrong, let me know, i can't run the code right now so...
edited, i forgot to add code in the callback

Other ways to search a ListView

I am trying to use TextChangedListener to implement search functionality on my ListView. But after adding some character in EditText; the ListView goes blank. I have implemented filter method in my ArrayAdapter class.
I am getting my data from JSON.
My Logcat shows: getSlotFromBufferLocked: unknown buffer
Is there any other way to search ListView?
Here's my code:
UserList.java
public class UserList extends AppCompatActivity {
private ListView listView;
private ArrayList<MyDataModel> list;
private MyArrayAdapter adapter;
private EditText search;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.user_list);
search = (EditText) findViewById(R.id.search);
//Array List for Binding Data from JSON to this List
list = new ArrayList<>();
//Binding that List to Adapter
adapter = new MyArrayAdapter(this, list);
//Getting List and Setting List Adapter
listView = (ListView) findViewById(R.id.listView);
listView.setAdapter(adapter);
listView.setTextFilterEnabled(true);
search.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
String text = search.getText().toString().toLowerCase(Locale.getDefault());
adapter.filter(text);
}
#Override
public void afterTextChanged(Editable s) {
}
});
//Checking Internet Connection
if (InternetConnection.checkConnection(getApplicationContext())) {
new GetDataTask().execute();
} else {
Snackbar.make(findViewById(R.id.parentLayout),"Internet Connection Not Available", Snackbar.LENGTH_LONG).show();
}
}
//Creating Get Data Task for Getting Data From Web
class GetDataTask extends AsyncTask<Void, Void, Void> {
ProgressDialog dialog;
int jIndex;
int x;
#Override
protected void onPreExecute() {
super.onPreExecute();
//Progress Dialog for User Interaction
x=list.size();
if(x==0)
jIndex=0;
else
jIndex=x;
dialog = new ProgressDialog(UserList.this);
dialog.setTitle("Please Wait..."+x);
dialog.setMessage("Retrieving Data");
dialog.show();
}
#Nullable
#Override
protected Void doInBackground(Void... params) {
//Getting JSON Object from Web Using okHttp
JSONObject jsonObject = JSONParser.getDataFromWeb();
try {
if (jsonObject != null) {
if(jsonObject.length() > 0) {
JSONArray array = jsonObject.getJSONArray(Keys.KEY_CONTACTS);
//Check Length of Array...
int lenArray = array.length();
if(lenArray > 0) {
for( ; jIndex < lenArray; jIndex++) {
//Creating Every time New Object and adding to List
MyDataModel model = new MyDataModel();
JSONObject innerObject = array.getJSONObject(jIndex);
String name = innerObject.getString(Keys.KEY_NAME);
model.setName(name);
list.add(model);
}
}
}
} else {
}
} catch (JSONException je) {
Log.i(JSONParser.TAG, "" + je.getLocalizedMessage());
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
dialog.dismiss();
//Checking if List size if more than zero then update ListView
if(list.size() > 0) {
adapter.notifyDataSetChanged();
} else {
Snackbar.make(findViewById(R.id.parentLayout), "No Data Found", Snackbar.LENGTH_LONG).show();
}
}
}
}
I have implemented the filter method in my ArrayAdapter class.
Here's my ArrayAdapter class:
MyArrayAdapter.java
public class MyArrayAdapter extends ArrayAdapter<MyDataModel> implements Filterable{
List<MyDataModel> modelList;
Context context;
private LayoutInflater mInflater;
private ArrayList<MyDataModel> arrayList;
public MyArrayAdapter(Context context, List<MyDataModel> objects) {
super(context, 0, objects);
this.context = context;
this.mInflater = LayoutInflater.from(context);
modelList = objects;
this.arrayList = new ArrayList<MyDataModel>();
this.arrayList.addAll(modelList);
}
#Override
public MyDataModel getItem(int position) {
return modelList.get(position);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder vh;
if (convertView == null) {
View view = mInflater.inflate(R.layout.layout_row_view, parent, false);
vh = ViewHolder.create((RelativeLayout) view);
view.setTag(vh);
} else {
vh = (ViewHolder) convertView.getTag();
}
MyDataModel item = getItem(position);
vh.textViewName.setText(item.getName());
return vh.rootView;
}
private static class ViewHolder {
public final RelativeLayout rootView;
public final TextView textViewName;
private ViewHolder(RelativeLayout rootView, TextView textViewName) {
this.rootView = rootView;
this.textViewName = textViewName;
}
public static ViewHolder create(RelativeLayout rootView) {
TextView textViewName = (TextView) rootView.findViewById(R.id.textViewName);
return new ViewHolder(rootView, textViewName);
}
}
// Filter Class
public void filter(String charText) {
charText = charText.toLowerCase(Locale.getDefault());
modelList.clear();
if (charText.length() == 0) {
modelList.addAll(arrayList);
} else {
for (MyDataModel wp : arrayList) {
if (wp.getName().toLowerCase(Locale.getDefault()).contains(charText)) {
modelList.add(wp);
}
}
}
notifyDataSetChanged();
}
Try,
modelList = new ArrayList<MyDataModel>;
Write this line after modelList.clear(); and check.
Go with this link, and follow steps for implementing the same:
and the problem with buffer is called every textchanged listener will call everytime if you add or delete any character or space in it. So avoid using that. It will cause memory leak problems.

Attempt to invoke Adapter.notifyDataSetChanged()' on a null object refernce

I have tried adding the adapter in the onCreate() as well and it throws a null pointer exception with an error 'Attempt to invoke listVIew.setAdapter on a null object reference.
Here is the code where I use notifyDataSetChange() inside my Main Activity;
import static com.name.sample.Tab1.adapter;
public class Requests extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
Cursor c = myDB.rawQuery("SELECT * FROM requests", null);
int aIndex = c.getColumnIndex("name");
int bIndex = c.getColumnIndex("nick");
int cIndex = c.getColumnIndex("num");
name.clear();
nick.clear();
number.clear();
if (c.moveToFirst()){
do {
name.add(c.getString(aIndex));
nick.add(c.getString(bIndex));
number.add(c.getInt(cIndex));
} while (c.moveToNext());
}
return null;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
adapter.notifyDataSetChanged();
}
}
Here is my Tab1 code
Here is the code for the Adapter
public class Tab1 extends Fragment {
static ListView listNotifications;
final static ArrayList<String> name = new ArrayList<>();
static ArrayList<Integer> number = new ArrayList<>();
static ArrayList<String> nick = new ArrayList<>();
static ImageAdapter adapter;
public static class ImageAdapter extends ArrayAdapter<String> {
private final Context context;
private final String[] values;
public ImageAdapter (Context context, String[] values) {
super(context, R.layout.list_with_icons, values);
this.context = context;
this.values = values;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.list_with_icons, parent, false);
TextView textView = (TextView) rowView.findViewById(R.id.textViewName);
ImageView imageView = (ImageView) rowView.findViewById(R.id.imagePicture);
textView.setText(values[position]);
// Change the icon for Windows and iPhone
return rowView;
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.tab1layout, container, false);
String[] nameString = new String[name.size()];
nameString = name.toArray(nameString);
adapter = new ImageAdapter (getActivity(), nameString);
listNotifications =(ListView)rootView.findViewById(R.id.listNotifications);
listNotifications.setAdapter(adapter);
return rootView;
}}
Try using: adapterClass.this.notifyDataSetChanged() in onPostExcecute()
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
InvitedAdapter.this.notifyDataSetChanged();
}
you have added a wrong adapter in the listview. it should be like this in onCreateView():
listNotifications.setAdapter(adapter);
Try this :)

Categories

Resources