maybe I'm tired but I miss something in what's happening in my code. I have an activity with fragments.
My activity HomeActivity calls a webservice to fill a List (my business object), it does this onResume().
My fragment WalletFragment has a mehtod refreshCardListView() that uses an adapter to display the list. It does this onResume().
What I was doing and that was working until now was:
HomeActivity.onCreate() displays WalletFragment,
WalletFragment.onResume() calls this.refreshCardList() but at this
instant cardList is null so the adapter displays nothing
HomeActivity.onResume() calls webservice, which on success calls
walletFragment.refreshCardList(), this time cardList has been filled
by the webservice so tid displays the list correctly.
Now I thout it was stupid to call refreshList twice so I tried to move the displayWalletFragment from HomeActivity.onCreate() to the success callback of the webservice and remove the call to refreshCardList from HomeActivity and leaving it only in WalletFragment.onResume(), so it'd go like this:
HomeActivity.onResume() calls webservice, which on success displays WalletFragment, WalletFragment.onResume() calls this.refreshCardList(), cardList having been filled by the webservice.
However at this point my adapter crashes, because parent.getWidth() == 0 (and I needed parent width to display card images).
I don't understad why, by moving this bit of code, the parent view would now not be initialized at this point, do you have an idea?
So this is the original code I used that is working, the only things I changed are removing displayWalletFragment(false) from onCreate and moving it in the success return of refreshCardList and removing walletFragment.refreshCardListView() from there.
HomeActivity.java
public class HomeActivity extends Activity {
CardService cardService = new CardService(this);
UserService userService = new UserService(this);
User user = null;
Set<WegaCard> userCards = null;
ProfileFragment profileFragment;
WalletFragment walletFragment;
/*
* Saving card images for performance concerns.
*/
Map<String, Bitmap> cardsImageBitmaps = new HashMap<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
initializeComponents();
styleCompnents();
displayWalletFragment(false);
}
#Override
protected void onResume() {
Log.d(this, "fired HomeActivity.onResume()");
super.onResume();
user = null;
userCards = null;
refreshUser(
new SingleResultCallback<User>() {
#Override
public void onResponse(User cards) {
Log.d(this, "user: " + user.toString());
HomeActivity.this.user = user;
profileFragment.refreshUser();
}
},
new ErrorCallback() {
#Override
public void onResponse(Throwable error) {
Log.e(this, "error: " + error.toString());
}
});
refreshCardList(
new SingleResultCallback<Set<WegaCard>>() {
#Override
public void onResponse(Set<WegaCard> cards) {
Log.d(this, "cards: " + cards.toString());
userCards = cards;
walletFragment.refreshCardListView();
}
},
new ErrorCallback() {
#Override
public void onResponse(Throwable error) {
Log.e(this, "error: " + error.toString());
}
});
}
private void refreshCardList(SingleResultCallback<Set<WegaCard>> successCallback, ErrorCallback errorCallback) {
Log.d(this, "fired HomeActivity.refreshCardList()");
// First empty list...
userCards = new LinkedHashSet<>();
// ...then fill it back
cardService.getCards(false, true, successCallback, errorCallback);
}
private void refreshUser(SingleResultCallback<User> successCallback, ErrorCallback errorCallback) {
Log.d(this, "fired HomeActivity.refreshUser()");
// First empty user...
userCards = new LinkedHashSet<>();
// ...then recreate it
userService.getUser(successCallback, errorCallback);
}
public void displayWalletFragment(boolean addToBackStack) {
displayFragment(WalletFragment.newInstance(), addToBackStack);
}
public void displayCardFragment(String cardNumber, boolean addToBackStack) {
displayFragment(CardFragment.newInstance(cardNumber), addToBackStack);
}
public void displayProfileFragment(boolean addToBackStack) {
displayFragment(ProfileFragment.newInstance(), addToBackStack);
}
private void displayFragment(HomeFragment fragment, boolean addToBackStack) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.home_fragment, fragment);
if (addToBackStack) {
fragmentTransaction.addToBackStack(null);
}
fragmentTransaction.commit();
}
public void profileEdit(View view) {
ActivityLauncher.getInstance().startProfileActivityForResult(this, ProfileActivity.ProfileEditMode.EDIT_PROFILE, user);
}
public Map<String, Bitmap> getCardsImageBitmaps() {
return cardsImageBitmaps;
}
}
WalletFragment.java
public class WalletFragment extends HomeFragment {
List<WegaCard> cardList;
ListView cardListView;
WegaCardAdapter adapter;
public static WalletFragment newInstance() {
WalletFragment fragment = new WalletFragment();
// Bundle args = new Bundle();
// fragment.setArguments(args);
return fragment;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
activity.walletFragment = this;
cardListView = (ListView) getView().findViewById(R.id.fragment_home_wallet_list);
cardListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
activity.displayCardFragment(cardList.get(position).getCardNumber(), true);
}
});
}
#Override
public void onResume() {
Log.d(this, "fired WalletFragment.onResume()");
super.onResume();
refreshCardListView();
}
void refreshCardListView() {
Log.d(this, "fired WalletFragment.refreshCardListView()");
// First empty list...
cardList = new ArrayList<>();
cardList.addAll(activity.userCards);
adapter = new WegaCardAdapter(activity, R.layout.adapter_card_item, cardList);
cardListView.setAdapter(adapter);
getView().findViewById(R.id.fragment_home_wallet_empty).setVisibility(cardList.isEmpty() ? View.VISIBLE : View.GONE);
}
}
WegaCardAdapter.java
public class WegaCardAdapter extends ArrayAdapter<WegaCard> {
public WegaCardAdapter(#NonNull Context context, #LayoutRes int resource, #NonNull List<WegaCard> objects) {
super(context, resource, objects);
}
/**
* Data that should appear in the view should be added here
*/
private class ViewHolder {
ImageView imageView;
}
/*
* Note: using layout_height="match_parent" on the ListView helps Android calculate faster
* the elements that are displayed on screen, and prevent the array adapter for calling
* getView() too many times, thus improving the display speed
*/
public View getView(int position, View convertView, ViewGroup parent) {
Log.d(this, "fired WegaCardAdapter.getView(" + position + ")");
ViewHolder holder = null;
WegaCard card = getItem(position);
LayoutInflater mInflater = (LayoutInflater) getContext().getSystemService(android.app.Activity.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = mInflater.inflate(R.layout.adapter_card_item, null);
holder = new ViewHolder();
holder.imageView = (ImageView) convertView.findViewById(R.id.adapter_card_image);
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
Bitmap cardImage = null;
if (getContext() instanceof HomeActivity) {
Log.d(this, "In home activity \\o/");
Map<String, Bitmap> savedBitmaps = ((HomeActivity) getContext()).getCardsImageBitmaps();
if (savedBitmaps.containsKey(card.getCardNumber())) {
Log.d(this, "Found saved image, using it ^^");
cardImage = savedBitmaps.get(card.getCardNumber());
}
else {
Log.d(this, "Didn't found saved image éè building and saving it for later!");
cardImage = card.getRoundedScaledBitmap(getContext(), parent.getWidth());
savedBitmaps.put(card.getCardNumber(), cardImage);
}
}
else {
Log.d(this, "Not in home activity?");
cardImage = card.getRoundedScaledBitmap(getContext(), parent.getWidth());
}
holder.imageView.setImageBitmap(cardImage);
return convertView;
}
}
activity_home.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:auto="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<!-- Fragment will be displayed here -->
<LinearLayout
android:id="#+id/home_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
</LinearLayout>
</ScrollView>
</RelativeLayout>
fragment_home_wallet.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/fragment_home_wallet_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<LinearLayout
android:id="#+id/fragment_home_wallet_empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:visibility="gone">
<ImageView
android:src="#drawable/icon_card_white"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.gaetanl.aspa.ui.component.StaticTextView
android:id="#+id/fragment_home_wallet_empty_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/defaultSpacing"
android:text="#string/dashboard_text_nocard" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/defaultSpacing"
android:gravity="center_vertical"
android:orientation="horizontal">
<com.gaetanl.aspa.ui.component.StaticTextView
android:id="#+id/fragment_home_wallet_empty_text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/dashboard_text_tap1" />
<ImageView
android:src="#drawable/icon_plus_white"
android:layout_width="#dimen/inlineIcon"
android:layout_height="#dimen/inlineIcon"
android:layout_marginLeft="#dimen/wordSpacing"
android:layout_marginRight="#dimen/wordSpacing" />
<com.gaetanl.aspa.ui.component.StaticTextView
android:id="#+id/fragment_home_wallet_empty_text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/dashboard_text_tap2" />
</LinearLayout>
</LinearLayout>
<!-- Note: using layout_height="match_parent" on the ListView helps Android calculate faster
the elements that are displayed on screen, and prevent the array adapter for calling
getView() too many times, thus improving the display speed -->
<ListView
android:id="#+id/fragment_home_wallet_list"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</LinearLayout>
</LinearLayout>
I found the solution here: When should I get Width View in Fragment.
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.post(new Runnable() {
#Override
public void run() {
// do operations or methods involved
// View.getWidth(); or View.getHeight();
// here
}
});
}
You can try calling just displayWalletFragment(false); on your success callback and move walletFragment.refreshCardListView(); to the onViewCreated() of your WallentFragment.
This will ensure the right sequence of your Fragment being created and the list being populated.
Related
I am using for loop, and I have around 20 items displaying in recycler view! Now how do I hide/show image view as for loop runs... Here tts is working fine, but when i try to show/hide using this its not happening..
Presently with below code, once for loops ends the entire imageview is affecting, i want it a row wis(show current(image1) & hide previous imageview(image) )
I am calling this method from main Activity class, but the imageview show or hide not happening
activity
......
......
private void ConvertTextToSpeech() {
// TODO Auto-generated method stub
//items.forEach( Multiples obj -> System.out.println());
int z=0;
View holder=null; ImageView imageView=null;ImageView imageView1=null;
for (Multiples p : items) {
if(z>0){
holder = recyclerView.findViewHolderForAdapterPosition(z).itemView;
holder.findViewById(R.id.image).setVisibility(View.VISIBLE);
holder.findViewById(R.id.image1).setVisibility(View.INVISIBLE);
}
if(z < items.size()) {
holder = recyclerView.findViewHolderForAdapterPosition(z).itemView;
holder.findViewById(R.id.image).setVisibility(View.INVISIBLE);
holder.findViewById(R.id.image1).setVisibility(View.VISIBLE);
}
text = p.first + " " + p.getSecond() + " Za "+p.getResult()+".";
tts.speak(text, TextToSpeech.QUEUE_ADD, null);
z++;
}
}
xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.balysv.materialripple.MaterialRippleLayout
android:id="#+id/lyt_parent"
style="#style/RippleStyleBlack"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:focusable="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#color/grey_10" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="horizontal"
android:textAlignment="gravity" >
<View
android:layout_width="#dimen/spacing_large"
android:layout_height="wrap_content" />
<ImageView
android:id="#+id/image"
android:layout_width="35dp"
android:layout_height="35dp"
android:background="#android:color/transparent"
android:src="#drawable/ic_arrow_right" />
<ImageView
android:id="#+id/image1"
android:layout_width="51dp"
android:layout_height="35dp"
android:background="#android:color/transparent"
android:src="#drawable/ic_arrow_right"
android:visibility="invisible" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="#dimen/spacing_middle"
android:paddingTop="#dimen/spacing_middle">
<TextView
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="#dimen/spacing_middle"
android:layout_marginRight="#dimen/spacing_middle"
android:fontFamily="sans-serif-condensed"
android:gravity="center|left"
android:text="36"
android:textAppearance="#style/TextAppearance.AppCompat.Medium"
android:textColor="#color/grey_80"
android:textSize="30sp"
/>
</LinearLayout>
<View
android:layout_width="#dimen/spacing_large"
android:layout_height="match_parent" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#color/grey_10" />
</LinearLayout>
</com.balysv.materialripple.MaterialRippleLayout>
</RelativeLayout>
adapter
public class AdapterListAnimation extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Multiples> items = new ArrayList<>();
private Context ctx;
private OnItemClickListener mOnItemClickListener;
private int animation_type = 0;
.........
.........
You need just add field in your adapter where you will save currently active item. Then call notifyDataSetChanged.
Also you should update your onBindViewHolder like this:
private int currentPosition = -1;
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
holder.textView.setText(items.get(position));
if (currentPosition == position) {
holder.img1.setVisibility(View.INVISIBLE);
holder.img2.setVisibility(View.VISIBLE);
} else {
holder.img1.setVisibility(View.VISIBLE);
holder.img2.setVisibility(View.INVISIBLE);
}
}
public void setCurrentPosition(int currentPosition) {
this.currentPosition = currentPosition;
}
I've created a test project to show how it can be implemented. Here you can see how it works. Here is my github repository.
You should not directly change the item view state inside the adapter with the following:
holder = recyclerView.findViewHolderForAdapterPosition(z).itemView;
holder.findViewById(R.id.image).setVisibility(View.VISIBLE);
holder.findViewById(R.id.image1).setVisibility(View.INVISIBLE);
instead, you need to use a specific method to tell the RecyclerView adapter that you need to change a state of an item view.
Be noted, that RecylerView naturally (in programmatically way) will recyler it's previous item whenever it needs to draw another item. So, you need to keep the state of each item whether using a specific variable inside your model or using a variable to hold each item state.
In case that you don't want to change your model, you can use SparseBooleanArray to hold the state. You can do something like this in your Adapter:
public class YourAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Multiples> mItems;
// We use this to hold the image state.
private SparseBooleanArray mImageStates;
public YourAdapter(List<Multiples> items) {
this.mItems = items;
mImageStates = new SparseBooleanArray();
...
}
#Override
public YourAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
...
return viewHolder;
}
#Override
public void onBindViewHolder(ContactsAdapter.ViewHolder viewHolder, int position) {
int itemPosition = viewHolder.getAdapterPosition();
Multiples item = mItems.get(itemPosition);
// Load the state by the previous saved state
// default value is false.
if(mImageStates.get(itemPosition)) {
// show the images or something.
} else {
// hide the images or something.
}
}
public void setState(int position, boolean isVisible) {
mImageStates.put(position, isVisible);
}
}
now you can change the state item visibility with:
yourAdapter.setState(yourItemPosition, true);
then notify the adapter about the change with:
yourAdapter.notifyItemChanged(yourItemPosition);
or reset all if you have change many items with:
yourAdapter.notifyDataSetChanged();
you have to write a logic on onbindholder then.
onBindHolder(ViewHolder holder, int position){
if(position %2==0)
imageview.setVisibility(View.Visible);
else
imageview.setVisibility(View.InVisible);
}
Finally Got the Solution
I have added two parameters in your Multiples. In your loop when a condition is true, I am setting variable according to you have done with Image view. after I am notifying RecyclerView. so, a callback will come on onBindViewHolder. there I have added conditions for show/hide Image view.
suppose left Arrow is image & right Arrow is image1
NOTE: Android Default TextToSpeech does not provide any event listener for complete. So, I have tried a new library that is well maintained and provide Speech recognition and Text to speech functionality.
Gradle:
implementation 'net.gotev:speech:1.4.0'
Initialization:
To start using the library, you have to initialize it in your Activity.
public class YourActivity extends Activity {
private count = 0;
private maxCount = 0;
Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout);
Speech.init(this, getPackageName());
maxCount = items.size();
}
#Override
protected void onDestroy() {
// prevent memory leaks when activity is destroyed
Speech.getInstance().shutdown();
}
}
public class Multiples implements Serializable {
private Boolean isShowimage = false;
private Boolean isShowimage1 = false;
public Boolean getShowimage() {
return isShowimage;
}
public void setShowimage(Boolean showimage) {
isShowimage = showimage;
}
public Boolean getShowimage1() {
return isShowimage1;
}
public void setShowimage1(Boolean showimage1) {
isShowimage1 = showimage1;
}
}
private void ConvertTextToSpeech() {
if (count < maxCount) {
reset();
String text = items.get(count).first + " " + items.get(count).getSecond() + " Za " + items.get(count).getResult() + ".";
Speech.getInstance().say(text, new TextToSpeechCallback() {
#Override
public void onStart() {
Log.i("speech", "speech started");
items.get(count).setShowimage(false);
items.get(count).setShowimage1(true);
adapter.notifyDataSetChanged();
}
#Override
public void onCompleted() {
Log.i("speech", "speech completed");
ConvertTextToSpeech();
count++;
}
#Override
public void onError() {
Log.i("speech", "speech error");
}
});
}
}
private void reset() {
for (Multiples p : items) {
p.setShowimage(true);
p.setShowimage1(false);
}
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
final Multiples item = items.get(position);
if (item.getShowimage()) {
holder.image.setVisibility(View.VISIBLE);
} else {
holder.image.setVisibility(View.INVISIBLE);
}
if (item.getShowimage1()) {
holder.image1.setVisibility(View.VISIBLE);
} else {
holder.image1.setVisibility(View.INVISIBLE);
}
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private ImageView imageView,imageView1;
public ViewHolder(View view) {
super(view);
this.imageView = (ImageView) view.findViewById(R.id.imageView);
this.imageView1 = (ImageView) view.findViewById(R.id.imageView1);
}
}
I am trying to use a swipeCallback on a list with modeladapter. In order to make it work, I stripped down all my customization and modeled it close to the sample app, but the combination produces the error of not allowing undo. When I swipe, this happens:
The swipe works, but the undo icon does not show up. Any ideas what I am doing wrong? The underlying fragment is this:
public class EditFragment extends Fragment implements ItemTouchCallback, SimpleSwipeCallback.ItemSwipeCallback {
private FragmentEditBinding oBinding;
private SongViewModel oViewModel;
//save our FastAdapter
private FastAdapter fastAdapter;
private ModelAdapter<ModelSongCounter, ModelItemView> itemAdapter;
//drag & drop
private SimpleDragCallback touchCallback;
private ItemTouchHelper touchHelper;
public EditFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//init Databinding
oBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_edit, container, false);//.setContentView(getActivity(), R.layout.fragment_main);
//LayoutInflaterCompat.setFactory(getLayoutInflater(), new IconicsLayoutInflater(getActivity()));
//style our ui
new MaterializeBuilder().withActivity(getActivity()).build();
//adapters
//FastScrollIndicatorAdapter fastScrollIndicatorAdapter = new FastScrollIndicatorAdapter();
itemAdapter = new ModelAdapter<>(new IInterceptor<ModelSongCounter, ModelItemView>() {
#Override
public ModelItemView intercept(ModelSongCounter iconModel) {
return new ModelItemView(iconModel);
}
});
//create our FastAdapter which will manage everything
fastAdapter = FastAdapter.with(Arrays.asList(itemAdapter));
fastAdapter.withSelectable(true);
//get our recyclerView and do basic setup
//RecyclerView rv = oBinding.SongRecyclerView;
oBinding.SongRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
//oBinding.SongRecyclerView.setItemAnimator(new SlideDownAlphaAnimator());
oBinding.SongRecyclerView.setAdapter(fastAdapter);
//get ViewModels from Provider
oViewModel = ViewModelProviders.of(getActivity()).get(SongViewModel.class);
//get rid of the annoying blink
oBinding.SongRecyclerView.setItemAnimator(null);
//add Observer to ViewModel
// The onChanged() method fires when the observed data changes and the activity is
// in the foreground.
oViewModel.getAllCatsLive().observe(this, new Observer<List<ModelSongCounter>>() {
#Override
public void onChanged(#Nullable List<ModelSongCounter> modelSongCounters) {
itemAdapter.set(modelSongCounters);
}
});
fastAdapter.withEventHook(new ClickEventHook<ModelItemView>() {
#Nullable
#Override
public View onBind(#NonNull RecyclerView.ViewHolder viewHolder) {
if (viewHolder instanceof ModelItemView.ViewHolder) {
return ((ModelItemView.ViewHolder) viewHolder).Minus;
}
return null;
}
#Override
public void onClick(View v, int position, FastAdapter<ModelItemView> fastAdapter, ModelItemView item) {
//react on the click event
oViewModel.decrement(item.getModel().uid);
}
});
fastAdapter.withEventHook(new ClickEventHook<ModelItemView>() {
#Nullable
#Override
public View onBind(#NonNull RecyclerView.ViewHolder viewHolder) {
if (viewHolder instanceof ModelItemView.ViewHolder) {
return ((ModelItemView.ViewHolder) viewHolder).Plus;
}
return null;
}
#Override
public void onClick(View v, int position, FastAdapter<ModelItemView> fastAdapter, ModelItemView item) {
//react on the click event
oViewModel.increment(item.getModel().uid);
}
});
//restore selections (this has to be done after the items were added
fastAdapter.withSavedInstanceState(savedInstanceState);
//Swipable stuff within OnCreateView
Drawable leaveBehindDrawableLeft = new IconicsDrawable(getContext())
.icon(MaterialDesignIconic.Icon.gmi_delete)
.color(Color.WHITE)
.sizeDp(24);
Drawable leaveBehindDrawableRight = new IconicsDrawable(getContext())
.icon(MaterialDesignIconic.Icon.gmi_archive)
.color(Color.WHITE)
.sizeDp(24);
touchCallback = new SimpleSwipeDragCallback(
this,
this,
leaveBehindDrawableLeft,
ItemTouchHelper.LEFT,
ContextCompat.getColor(getContext(), R.color.md_red_900)
)
.withBackgroundSwipeRight(ContextCompat.getColor(getContext(), R.color.md_blue_900))
.withLeaveBehindSwipeRight(leaveBehindDrawableRight);
touchHelper = new ItemTouchHelper(touchCallback); // Create ItemTouchHelper and pass with parameter the SimpleDragCallback
touchHelper.attachToRecyclerView(oBinding.SongRecyclerView); // Attach ItemTouchHelper to RecyclerView
//restore selections (this has to be done after the items were added
fastAdapter.withSavedInstanceState(savedInstanceState);
return oBinding.getRoot();
}
#Override
public void onSaveInstanceState(Bundle outState) {
//add the values which need to be saved from the adapter to the bundle
outState = fastAdapter.saveInstanceState(outState);
super.onSaveInstanceState(outState);
}
//Swipable...and probably relevant for expandables, since there is TouchOnMove
#Override
public boolean itemTouchOnMove(int oldPosition, int newPosition) {
//DragDropUtil.onMove((ItemAdapter)itemAdapter, oldPosition, newPosition); // change position
return true;
}
#Override
public void itemTouchDropped(int oldPosition, int newPosition) {
//f.e. save new order in database
}
#Override
public void itemSwiped(int position, int direction) {
// -- Option 1: Direct action --
//do something when swiped such as: select, remove, update, ...:
//A) fastItemAdapter.select(position);
//B) fastItemAdapter.remove(position);
//C) update item, set "read" if an email etc
// -- Option 2: Delayed action --
final ModelItemView item = itemAdapter.getAdapterItem(position);
item.setSwipedDirection(direction);
// This can vary depending on direction but remove & archive simulated here both results in
// removal from list
final Runnable removeRunnable = new Runnable() {
#Override
public void run() {
item.setSwipedAction(null);
int position = itemAdapter.getAdapterPosition(item);
if (position != RecyclerView.NO_POSITION) {
//this sample uses a filter. If a filter is used we should use the methods provided by the filter (to make sure filter and normal state is updated)
//fastItemAdapter.getItemFilter().remove(position);
itemAdapter.remove(position);
}
}
};
final View rv = oBinding.SongRecyclerView;
rv.postDelayed(removeRunnable, 3000);
item.setSwipedAction(new Runnable() {
#Override
public void run() {
rv.removeCallbacks(removeRunnable);
item.setSwipedDirection(0);
int position = itemAdapter.getAdapterPosition(item);
if (position != RecyclerView.NO_POSITION) {
fastAdapter.notifyItemChanged(position);
}
}
});
fastAdapter.notifyItemChanged(position);
//TODO can this above be made more generic, along with the support in the item?
}
}
This is the swipable ModelItem (the model "ModelSongCounter" is just a POJO):
public class ModelItemView
extends ModelAbstractItem<ModelSongCounter, ModelItemView, ModelItemView.ViewHolder>
implements ISwipeable<ModelItemView, IItem>, IDraggable<ModelItemView, IItem> {
public StringHolder undoTextSwipeFromLeft;
public int iSwipedDirection;
private Runnable rSwipedAction;
public boolean bSwipable = true;
public boolean draggable = true;
public ModelItemView(ModelSongCounter icon) {
super(icon);
}
/**
* defines the type defining this item. must be unique. preferably an id
*
* #return the type
*/
#Override
public int getType() {
return R.id.iconics_tag_id;
}
/**
* defines the layout which will be used for this item in the list
*
* #return the layout for this item
*/
#Override
public int getLayoutRes() {
return R.layout.item_view;
}
/**
* binds the data of this item onto the viewHolder
*
* #param viewHolder the viewHolder of this item
*/
#Override
public void bindView(ViewHolder viewHolder, List<Object> payloads) {
super.bindView(viewHolder, payloads);
//define our data for the view
viewHolder.name.setText(getModel().getName());
viewHolder.counter.setText(Integer.toString(getModel().getCounter()));
viewHolder.swipeResultContent.setVisibility(iSwipedDirection != 0 ? View.VISIBLE : View.GONE);
viewHolder.itemContent.setVisibility(iSwipedDirection != 0 ? View.GONE : View.VISIBLE);
CharSequence swipedAction = null;
CharSequence swipedText = null;
if(iSwipedDirection != 0){
swipedAction = viewHolder.itemView.getContext().getString(R.string.action_undo);
swipedText = iSwipedDirection == ItemTouchHelper.LEFT ? "Removed" : "Archived - Should not be implemented!";
viewHolder.swipeResultContent.setBackgroundColor(
ContextCompat.getColor(viewHolder.itemView.getContext(),
iSwipedDirection == ItemTouchHelper.LEFT ? R.color.md_red_900 : R.color.md_blue_900));
}
viewHolder.swipedAction.setText(swipedAction == null ? "" : swipedAction);
viewHolder.swipedText.setText(swipedText == null ? "" : swipedText);
viewHolder.rSwipedActionRunnable = this.rSwipedAction;
}
#Override
public void unbindView(ViewHolder holder) {
super.unbindView(holder);
holder.name.setText(null);
holder.counter.setText(null);
holder.swipedAction.setText(null);
holder.swipedText.setText(null);
holder.rSwipedActionRunnable = this.rSwipedAction;
}
#Override
public ViewHolder getViewHolder(View v) {
return new ViewHolder(v);
}
//SWipable
#Override
public boolean isSwipeable() {
return this.bSwipable;
}
#Override
public ModelItemView withIsSwipeable(boolean swipeableP) {
this.bSwipable = swipeableP;
return this;
}
public void setSwipedDirection(int iSwipedDirectionP){
this.iSwipedDirection = iSwipedDirectionP;
}
public void setSwipedAction(Runnable actionP){
this.rSwipedAction = actionP;
}
#Override
public boolean isDraggable() {
return draggable;
}
#Override
public ModelItemView withIsDraggable(boolean draggableP) {
this.draggable = draggableP;
return this;
}
/**
* our ViewHolder
*/
protected static class ViewHolder extends RecyclerView.ViewHolder {
protected View view;
#BindView(R.id.material_drawer_song)
public TextView name;
#BindView(R.id.material_drawer_counter)
public TextView counter;
#BindView(R.id.material_drawer_minus)
public ImageView Minus;
#BindView(R.id.material_drawer_plus)
public ImageView Plus;
#BindView(R.id.swipe_result_content)
public View swipeResultContent;
#BindView(R.id.item_content)
public View itemContent;
#BindView(R.id.swiped_text)
public TextView swipedText;
#BindView(R.id.swiped_action)
public TextView swipedAction;
public Runnable rSwipedActionRunnable;
public ViewHolder(View view) {
super(view);
ButterKnife.bind(this, view);
//this.view = view;// ?
swipedAction.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (rSwipedActionRunnable != null){
rSwipedActionRunnable.run();
}
}
});
}
}
}
And this is the XML-view of the List-Item:
<?xml version="1.0" encoding="utf-8"?>
<layout>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="#dimen/material_drawer_item_primary">
<LinearLayout
android:id="#+id/swipe_result_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:visibility="visible"
android:paddingEnd="#dimen/material_drawer_vertical_padding"
android:paddingLeft="#dimen/material_drawer_vertical_padding"
android:paddingRight="#dimen/material_drawer_vertical_padding"
android:paddingStart="#dimen/material_drawer_vertical_padding">
<TextView
android:id="#+id/swiped_text"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:gravity="center_vertical|start"
android:lines="1"
android:singleLine="true"
android:textDirection="anyRtl"
android:textColor="#android:color/primary_text_dark"
android:textSize="#dimen/material_drawer_item_primary_text"
tools:text="Removed"/>
<TextView
android:id="#+id/swiped_action"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:fontFamily="sans-serif"
android:gravity="center_vertical|start"
android:lines="1"
android:singleLine="true"
android:textDirection="anyRtl"
android:textAllCaps="true"
android:textColor="#android:color/primary_text_dark"
android:textStyle="bold"
android:textSize="#dimen/material_drawer_item_primary_description"
android:text="#string/action_undo"/>
</LinearLayout>
<LinearLayout
android:id="#+id/item_content"
android:layout_width="match_parent"
android:layout_height="#dimen/material_drawer_item_primary"
android:orientation="horizontal"
android:paddingEnd="#dimen/material_drawer_vertical_padding"
android:paddingLeft="#dimen/material_drawer_vertical_padding"
android:paddingRight="#dimen/material_drawer_vertical_padding"
android:paddingStart="#dimen/material_drawer_vertical_padding">
<TextView
android:id="#+id/material_drawer_song"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginTop="12dp"
android:layout_marginLeft="12dp"
android:lines="1"
android:singleLine="true"
android:textSize="#dimen/material_drawer_item_primary_text"
tools:text="Some drawer text" />
<TextView
android:id="#+id/material_drawer_counter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginLeft="12dp"
android:fontFamily="sans-serif"
android:lines="1"
android:singleLine="true"
android:textSize="#dimen/material_drawer_item_primary_description"
tools:text="Some counter text"
android:layout_weight="1"
android:gravity="center_vertical|start" />
<ImageView
android:id="#+id/material_drawer_minus"
android:layout_width="50dp"
android:layout_height="match_parent"
app:ico_color="#color/md_black_1000"
app:ico_icon="#string/gmd_remove_circle"
app:ico_size="50dp" />
<ImageView
android:id="#+id/material_drawer_plus"
android:layout_width="50dp"
android:layout_height="match_parent"
app:ico_color="#color/md_black_1000"
app:ico_icon="gmd-add_circle"
app:ico_size="50dp" />
</LinearLayout>
</FrameLayout>
</layout>
The part of the code managing the display of the undo button is inside the bindView() method of the ModelItemView.
Please ensure that after swiping the correct item is retrieved via the getItem(position) in the itemSwiped and ensure that the correct item gets notified via notifyItemChanged().
After that ensure that the bindView() is triggered again on that element, and that it has the proper swipeDirection as set via setSwipedDirection(direction).
This is important as:
viewHolder.swipeResultContent.setVisibility(iSwipedDirection != 0 ? View.VISIBLE : View.GONE);
viewHolder.itemContent.setVisibility(iSwipedDirection != 0 ? View.GONE : View.VISIBLE);
Is used to properly adjust the visibility of the views, including showing the undo button.
After several weeks, the answer is simple:
The undo-Button depends on the itemanimator which I always nullified to avoid the blinking. Here is a nice custom animator class that supresses whatever animation you dont want. Now all I had to do was
RecyclerView.setItemAnimator(new CustomItemAnimator());
I'm currently making a playlist of videos. The flow of this is that from a ListView, it shows the list of the videos in the playlist. Upon clicking on the video, it will open the PlaylistActivity with this layout:
Playlist layout:
Problem:
The videos are working fine because I can hear them being played. However, probably because I used fragments, every time I click the prev or next button the video is being played on the last opened page from the ViewPager.
On the custom PagerAdapter, I inflated the layout with a custom player and an empty LinearLayout container where I will add the fragment.
PlaylistPagerAdapter.java
public class PlaylistPagerAdapter extends PagerAdapter {
List<Playlist> videos;
#Override
public int getCount() {
return videos != null ? videos.size() : 0;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
LayoutInflater inflater = LayoutInflater.from(container.getContext());
View pagerView = inflater.inflate(R.layout.view_video_player, container, false);
pagerView.setTag(videos.get(position).getId());
container.addView(pagerView);
return pagerView;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view.equals(object);
}
public void setVideos(List<Playlist> videos) {
this.videos = videos;
notifyDataSetChanged();
}
public Playlist getItemAt(int position) {
if (position > -1 && position < getCount()) {
return videos.get(position);
} else {
return null;
}
}
public void cleanup() {
if (videos != null && !videos.isEmpty()) {
videos.clear();
videos = null;
}
}
}
view_video_player.xml
<com.example.abd.ui.playlist.PlaylistVideoPlayerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:background="#color/white">
<com.example.abd.ui.misc.CustomVideoView
android:id="#+id/video_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_gravity="top"
android:background="#color/gray_holo_light" />
<ProgressBar
android:id="#+id/progress_bar"
style="#android:style/Widget.ProgressBar.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<LinearLayout
android:id="#+id/video_exit_btn_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|right"
android:background="#drawable/semi_transparent_button_bg"
android:visibility="gone">
<com.gc.materialdesign.views.ButtonFlat
android:id="#+id/btn_video_exit"
android:layout_width="wrap_content"
android:layout_height="38dp"
android:background="#color/white"
android:text="#string/action_done" />
</LinearLayout>
<LinearLayout
android:id="#+id/yt_video_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_gravity="top"
android:background="#color/gray_holo_light"
android:orientation="vertical" />
</com.example.abd.ui.playlist.PlaylistVideoPlayerView>
If the url of the video is from YouTube, then I will set the visibility of the CustomVideoView into GONE and set the LinearLayout ytVideoContainer into VISIBLE so it can show the fragment.
PlaylistVideoPlayerView.java
public void bindYouTubeVideo(FragmentTransaction fragmentTransaction, YouTubeVideo youTubeVideo) {
if (videoView != null && ytVideoContainer != null) {
ytVideoContainer.setVisibility(VISIBLE);
videoView.setVisibility(GONE);
progressBar.setVisibility(GONE);
}
Bundle bundle = new Bundle();
bundle.putSerializable(YOUTUBE_VIDEO_OBJ, youTubeVideo);
YouTubePlayerFragment yt_fragment = new YouTubePlayerFragment();
yt_fragment.setArguments(bundle);
fragmentTransaction
.replace(ytVideoContainer.getId(), yt_fragment)
.commit();
}
A snippet of onPageChanged() listener of the ViewPager:
PlaylistActivity.java
if (url.contains("youtube.com") || url.contains("youtu.be")) {
GetVideosDetailsByIDs getVideosDetailsByIDs = new GetVideosDetailsByIDs();
final String youtubeId = extractYTId(url);
try {
getVideosDetailsByIDs.init(youtubeId);
GetYouTubeVideosTask task = new GetYouTubeVideosTask(getVideosDetailsByIDs,
new GetYouTubeVideosTask.VideoResultListener() {
#Override
public void onResults(List<YouTubeVideo> videosList) {
if (videosList != null && !videosList.isEmpty()) {
YouTubeVideo youTubeVideo = videosList.get(0);
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
if (!isFinishing()) {
videoView.bindYouTubeVideo(fragmentTransaction,
youTubeVideo);
}
} else {
handleGetVideoStreamFailure();
}
}
});
task.execute();
} catch (IOException e) {
Timber.e(e, "Failed to play the youtube video.");
handleGetVideoStreamFailure();
}
}
It seems like the fragment was not added to the current page, does this have something to do with the AsyncTask? or with the way I added the fragment?
If you want to replace a fragment in your viewpager, you have to notify your adapter of the change. Your list of fragments needs to be updated to remove the 3rd fragment and add a new one in its place. After you've done that, you call notifyDataSetChanged in your adapter.
You could have an method like this in your adapter:
public void replaceFragment(Fragment fragment, String title, int index) {
mFragmentList.remove(index);
mFragmentList.add(index, fragment);
// do the same for the title
notifyDataSetChanged();
}
I have implemented the SwipeRefreshLayout in many of the pages,and it working fine. but here i got stuck with one specific implementation , where i have a SwipeRefreshLayout for the ViewPager and ViewPager holding the FragmentPagerAdapter.
In my case , I have a ViewPager with two tabs and each holding the fragment with RecyclerView. On main page I have a SwipeRefreshLayout and on the onRefresh i need to load the API and update the fragments in ViewPager. Updating is working fine but unfortunately RecyclerView inside the Fragment ( ViewPager tab Item ) not scrolling top and it always calling the SwipeToRefresh.
I am familiar with using the SwipeRefreshLayout with RecyclerView, but here the problem is the main child of the SwipeRefreshLayout is ViewPager and it having the Fragment inside it and that fragment is holding the RecyclerView.
I have a thought of moving the SwipeRefreshLayout inside the fragments for the RecyclerView , but again here i have challenges like both the Fragments is having the same API. So that i am using the SwipeRefreshLayout directly on ViewPager to refresh my data.
Here is some of my codes.
MainContacts.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/ll_no_records"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone">
<ImageView
android:id="#+id/iv_retry"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_gravity="center"
android:contentDescription="#string/todo"
android:src="#drawable/ic_reload" />
<TextView
android:id="#+id/textError"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:gravity="center"
android:text="#string/no_contact_found"
android:textAppearance="#style/Base.TextAppearance.AppCompat.Medium"
android:textColor="#color/colorDarkGray" />
</LinearLayout>
<LinearLayout
android:id="#+id/ll_process"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:alpha="1"
android:gravity="center"
android:orientation="vertical"
android:visibility="visible">
<ProgressBar
android:id="#+id/progress"
android:layout_width="50dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:indeterminate="true" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="#string/fetching"
android:textAppearance="#style/Base.TextAppearance.AppCompat.Medium"
android:textColor="#color/colorDarkGray" />
</LinearLayout>
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/contacts_screen"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<android.support.design.widget.TabLayout
android:id="#+id/my_contacts_tabs"
style="#style/MyCustomTabLayout"
android:layout_width="match_parent"
app:tabBackground="#color/colorWhite"
android:layout_height="wrap_content" />
<android.support.v4.view.ViewPager
android:id="#+id/my_contacts_view_pager"
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1"
android:background="#android:color/transparent" >
</android.support.v4.view.ViewPager>
</LinearLayout>
</android.support.v4.widget.SwipeRefreshLayout>
</RelativeLayout>
contacts.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:hc="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/ll_no_records"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone">
<ImageView
android:id="#+id/iv_retry"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_gravity="center"
android:contentDescription="#string/todo"
android:src="#drawable/ic_reload" />
<TextView
android:id="#+id/textError"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:gravity="center"
android:text="#string/no_contact_found"
android:textAppearance="#style/Base.TextAppearance.AppCompat.Medium"
android:textColor="#color/colorDarkGray" />
</LinearLayout>
<com.diegocarloslima.fgelv.lib.FloatingGroupExpandableListView
android:id="#+id/contactList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/searchContainer"
android:animateLayoutChanges="true"
android:childDivider="#android:color/transparent" />
</RelativeLayout>
MainFragment ( Which i am using to load the child fragments , SwipeTORefreshLayout + ViewPager here)
public class MainFragment extends BaseFragment {
private TextView mTextError;
private LinearLayout llNoRecords, ll_process;
private ImageView iv_retry;
private MaterialSearchView materialSearchView;
PHCJsonResponseContactDetailModel mContactResponseModel;
int expandableListSelectionType = ExpandableListView.PACKED_POSITION_TYPE_NULL;
boolean actionModeEnabled;
private Activity mActivity;
SwipeRefreshLayout mSwipeRefreshLayout;
private ViewPager viewPager;
TabLayout tabLayout;
ContactsTabPagerAdapter mAdapter;
ArrayList<PHCContactDetailModel> mContactList =new ArrayList<>();
ArrayList<PHCContactDetailModel> mFavoriteList;
boolean isSwipeToRefresh;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mActivity = getActivity();
View view = inflater.inflate(R.layout.phc_contact_fragment, container, false);
getViewId(view);
setListener();
if (isNetworkAvailable()) {
if(((MainDrawerActivity)mActivity).getPHCContactFragmentData()==null)
getAllContactData();
else
updateWidgets();
} else {
showNoNetworkToast();
llNoRecords.setVisibility(View.VISIBLE);
mTextError.setText(getResources().getText(R.string.no_internet_retry));
}
return view;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public void onResume() {
super.onResume();
}
/*#Override
public void onPrepareOptionsMenu(final Menu menu) {
getActivity().getMenuInflater().inflate(R.menu.menu_fragment_group, menu);
}*/
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_fragment_contacts, menu);
MenuItem item = menu.findItem(R.id.action_search);
materialSearchView.setMenuItem(item);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_create_group) {
Intent createGroupIntent = new Intent(getActivity(), PHCCreateGroupActivity.class);
createGroupIntent.putExtra("comeFrom", PHCAppConstant.GROUP_ADD);
getActivity().startActivity(createGroupIntent);
}
return super.onOptionsItemSelected(item);
}
private void setListener() {
iv_retry.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (isNetworkAvailable()) {
getAllContactData();
} else {
showNoNetworkToast();
}
}
});
}
private void getViewId(View view) {
mTextError = (TextView) view.findViewById(R.id.textError);
ll_process = (LinearLayout) view.findViewById(R.id.ll_process);
llNoRecords = (LinearLayout) view.findViewById(R.id.ll_no_records);
iv_retry = (ImageView) view.findViewById(R.id.iv_retry);
viewPager = (ViewPager) view.findViewById(R.id.my_contacts_view_pager);
tabLayout = (TabLayout) view.findViewById(R.id.my_contacts_tabs);
mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipeRefreshLayout);
mSwipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary,
android.R.color.holo_green_dark,
android.R.color.holo_orange_dark,
android.R.color.holo_blue_dark);
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
if(mContactResponseModel!=null && mContactResponseModel.getData().size() >0)
{
isSwipeToRefresh = true;
getAllContactData();
}
}
});
materialSearchView = (MaterialSearchView) getActivity().findViewById(R.id.search_view);
}
private void getAllContactData() {
if (isNetworkAvailable()) {
// showProgress();
PHCApiInterface apiService = PHCApiClient.getClient(getActivity()).create(PHCApiInterface.class);
Call<PHCJsonResponseContactDetailModel> call = apiService.contactData(getApplicationData(getActivity()).getAuthToken(), getApplicationData(getActivity()).getUserID());
call.enqueue(new Callback<PHCJsonResponseContactDetailModel>() {
#Override
public void onResponse(Call<PHCJsonResponseContactDetailModel> call, Response<PHCJsonResponseContactDetailModel> response) {
Log.d(TAG, "getContacts URL " + response.raw().request().url());
Log.d(TAG, "getContacts Resp " + new Gson().toJson(response.body()));
mContactResponseModel = response.body();
((MainDrawerActivity)mActivity).setPHCContactFragmentData(mContactResponseModel);
if(mSwipeRefreshLayout.isRefreshing())
{
// cancel the Visual indication of a refresh
mSwipeRefreshLayout.setRefreshing(false);
}
if(isSwipeToRefresh)
{
isSwipeToRefresh=false;
updateWidgets();
}
else
updateWidgets();
}
#Override
public void onFailure(Call<PHCJsonResponseContactDetailModel> call, Throwable t) {
if(mSwipeRefreshLayout.isRefreshing())
{
// cancel the Visual indication of a refresh
mSwipeRefreshLayout.setRefreshing(false);
}
isSwipeToRefresh=false;
dismissProgress();
mTextError.setVisibility(View.VISIBLE);
}
});
} else {
isSwipeToRefresh=false;
if(mSwipeRefreshLayout.isRefreshing())
{
// cancel the Visual indication of a refresh
mSwipeRefreshLayout.setRefreshing(false);
}
showNoNetworkAlert();
}
}
private void updateWidgets() {
if (mContactResponseModel.getStatusCode() == 401 || mContactResponseModel.getStatusCode() == 402) {
showSessionExpireAlert(mContactResponseModel.getStatusMessage(), mContactResponseModel.getStatusCode());
return;
}
if (mContactResponseModel != null && mContactResponseModel.getStatusCode() == 1) {
dismissProgress();
mTextError.setVisibility(View.GONE);
mContactList = mContactResponseModel.getData();
mFavoriteList = mContactResponseModel.getData();
if(mContactList!=null && mContactList.size()>0)
{
llNoRecords.setVisibility(View.GONE);
mAdapter = new ContactsTabPagerAdapter(getActivity().getApplicationContext(), getChildFragmentManager(), mContactList , mFavoriteList);
viewPager.setAdapter(mAdapter);
tabLayout.setupWithViewPager(viewPager);
}
else {
llNoRecords.setVisibility(View.VISIBLE);
}
} else {
dismissProgress();
mTextError.setVisibility(View.VISIBLE);
}
}
public void dismissProgress() {
ll_process.setVisibility(View.GONE);
super.dismissProgress();
}
private void initiateContactChat(final PHCFacilityDetailsModel facilityDetailsModel, final int groupPosition, final int childPosition) {
String header = getApplicationData(getActivity()).getAuthToken();
PHCApiInterface apiService = PHCApiClient.getClient(getActivity()).create(PHCApiInterface.class);
Call<PHCContactInitiateChatResponseModel> call = apiService.initiateContactChat(header, facilityDetailsModel.getUserId(), getApplicationData(getActivity()).getUserID(), 0);
call.enqueue(new Callback<PHCContactInitiateChatResponseModel>() {
#Override
public void onResponse(Call<PHCContactInitiateChatResponseModel> call, Response<PHCContactInitiateChatResponseModel> response) {
Log.d(TAG, "initiateContactChat URL " + response.raw().request().url());
Log.d(TAG, "initiateContactChat Resp " + new Gson().toJson(response.body()));
PHCContactInitiateChatResponseModel mContactInitiateChatModel = response.body();
if (mContactInitiateChatModel != null && mContactInitiateChatModel.getStatusCode() == 1) {
Intent chatIntent = new Intent(getActivity(), PHCChatActivity.class);
// chatIntent.putExtra("headerName",mData.get(groupPosition).getFacilityDetails().get(childPosition).getUserName());
chatIntent.putExtra("headerName", facilityDetailsModel.getUserName());
chatIntent.putExtra("groupId", mContactInitiateChatModel.getData().getGroupId());
getActivity().startActivity(chatIntent);
}
}
#Override
public void onFailure(Call<PHCContactInitiateChatResponseModel> call, Throwable t) {
Toast.makeText(getActivity(), "Something went wrong! Please try again", Toast.LENGTH_SHORT).show();
}
});
}
}
ContactsTabPagerAdapter.java
public class ContactsTabPagerAdapter extends FragmentPagerAdapter {
/**
* The Page count.
*/
final int PAGE_COUNT = 2;
private String[] tabTitles = { "Contacts", "Favorites" };
private ArrayList<PHCContactDetailModel> mContactsList;
private ArrayList<PHCContactDetailModel> mFavoritesList;
Context mContext ;
public ContactsTabPagerAdapter(Context context, FragmentManager fm ,ArrayList<PHCContactDetailModel> contacts , ArrayList<PHCContactDetailModel> favs) {
super(fm);
this.mContext = context;
this.mContactsList = contacts;
this.mFavoritesList=favs;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
ContactsFragment mContactsFragment =new ContactsFragment();
Bundle bundle=new Bundle();
bundle.putSerializable("Contacts", (Serializable) mContactsList);
mContactsFragment.setArguments(bundle);
return mContactsFragment;
case 1:
FavoritesFragment mFavoritesFragment=new FavoritesFragment();
Bundle pastBundle=new Bundle();
pastBundle.putSerializable("Favorites", (Serializable) mFavoritesList);
mFavoritesFragment.setArguments(pastBundle);
return mFavoritesFragment;
}
return null;
}
#Override
public int getCount() {
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
// Generate title based on item position
return tabTitles[position];
}
/**
* Update.
*
* #param lContactsList contact list to update
* #param lFavoritesList favorites list to update
*/
//call this method to update fragments in ViewPager dynamically
public void update(ArrayList<PHCContactDetailModel> lContactsList, ArrayList<PHCContactDetailModel> lFavoritesList) {
this.mContactsList = lContactsList;
this.mFavoritesList = lFavoritesList;
notifyDataSetChanged();
}
#Override
public int getItemPosition(Object object) {
if (object instanceof UpdatableFragment) {
((UpdatableFragment) object).update(mContactsList, mFavoritesList);
}
//don't return POSITION_NONE, avoid fragment recreation.
return super.getItemPosition(object);
}
}
ContactsFragment.java
public class ContactsFragment extends BaseFragment implements UpdatableFragment{
private static final String TAG = "ContactFragmentTab";
private FloatingGroupExpandableListView mContactExpandableList;
private PHCContactAdapter mAdapter;
WrapperExpandableListAdapter wrapperAdapter;
boolean actionModeEnabled;
private LinearLayout llNoRecords;
private ArrayList<PHCContactDetailModel> mContactsData;
public ContactsFragment() {
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
}
#SuppressWarnings("unchecked")
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_contacts, container, false);
getViewId(rootView);
Bundle bundle= getArguments();
if(bundle !=null)
{
Log.d(TAG, "bundle is not empty");
mContactsData= (ArrayList<PHCContactDetailModel>) bundle.getSerializable("Contacts");
}
System.out.print("Contacts Size::" + mContactsData.size());
if(mContactsData!=null)
{
updateWidgets();
}
return rootView;
}
private void updateWidgets() {
mAdapter = new PHCContactAdapter(getActivity(), mContactsData, new ListShowingHidingListener() {
#Override
public void listHideAndShow(boolean isData) {
if (isData) {
llNoRecords.setVisibility(View.GONE);
mContactExpandableList.setVisibility(View.VISIBLE);
listUpdate();
} else {
llNoRecords.setVisibility(View.VISIBLE);
mContactExpandableList.setVisibility(View.GONE);
}
}
});
wrapperAdapter = new WrapperExpandableListAdapter(mAdapter);
mContactExpandableList.setAdapter(wrapperAdapter);
try {
for (int i = 0; i < wrapperAdapter.getGroupCount(); i++) {
mContactExpandableList.expandGroup(i);
}
} catch (Exception e) {
Log.e("Exception in Expand", "" + e);
}
}
private void listUpdate() {
try {
for (int i = 0; i < wrapperAdapter.getGroupCount(); i++) {
mContactExpandableList.expandGroup(i);
}
} catch (Exception e) {
Log.e("Exception in Expand", "" + e);
}
}
private void getViewId(View view) {
// mContactExpandableList = (ExpandableListView) view.findViewById(R.id.contactList);
mContactExpandableList = (FloatingGroupExpandableListView) view.findViewById(R.id.contactList);
}
#Override
public void update(ArrayList<PHCContactDetailModel> contactsData, ArrayList<PHCContactDetailModel> favoritesData) {
this.mContactsData = contactsData;
updateWidgets();
}
}
similarly i have Favorites example as well. Mostly both will look like same, that's why not posting it here.
Sorry for posting the long question. Any help regarding this. Apologies for my poor English. Thanks in Advance.
Objective: I have one activity and within two fragments. The ideia is to communicate both fragments, selecting one category and updating its item list.On activity load, a category is settle by default.
Problem: On activity load, ItemsFragment doesn't display/update itemsLisView. Also ItemAdapter's getView Method is being called only twice, even though the list has five items.
Facts:
Items List is being correctly fulfilled before being passed to adapter
Breakpointing the code, not sure why or if it matters, ItemsFragment is being rendered/called before CategoriesFragments. I found this weird since CategoriesFragments is positioned above ItemsFragment. This is the reason why I wrote if (getArguments() != null). Before I was getting Null Pointer Exception.
Research: There is a lot of questions regarding both subjects.
Android ListView not refreshing after notifyDataSetChanged with data as Map
ListFragment Not Rendering and getView() in Adapter Not Being Called
Android getView() not being called properly?
BaseAdapter notifyDatasetChanged() called but getView() is never called
Those are some link examples (of thousands) I went through, trying to find a solution for my case. Unfortunately none of them worked.
I've been with this problem for almost 5 days now and I guess I missing some Android concept here. It's not something related with Java Programming, or at least I hope so.
Questions:
Why ItemsFragment is not displaying Items List on activity load? (This probably answers updating problem)
Why ItemAdapter just calls getView only twice, even that Items List is correctly given to him with more items?
For any further needed information, please don't mind to ask.
Thanks in advance for any help.
EDIT - MCVE:
activity_triple_list:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".controller.activities.Lists">
<include layout="#layout/content_triple_list" />
</android.support.design.widget.CoordinatorLayout>
content_triple_list:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v4.view.ViewPager
android:id="#+id/listsPager"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.PagerTabStrip
android:id="#+id/pager_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:paddingBottom="4dp"
android:paddingTop="4dp" />
</android.support.v4.view.ViewPager>
</LinearLayout>
fragment_categories:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/categoriesFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TableLayout
android:id="#+id/categoriesTable"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:stretchColumns="4">
<TableRow
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:layout_marginTop="5dp"
android:gravity="center_horizontal">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="0"
android:layout_marginLeft="13dp"
android:layout_marginRight="13dp"
android:orientation="vertical">
<TextView
android:id="#+id/category1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="CATEGORY 1"
android:textAlignment="center"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
</TableRow>
</TableLayout>
</LinearLayout>
fragment_items:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#id/itemsFragment"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<ListView
android:id="#+id/itemsListView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:divider="#null" />
</LinearLayout>
content_row_choose_item:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/custom_row"
android:orientation="vertical"
android:paddingBottom="5dp"
android:paddingLeft="15dp"
android:paddingTop="5dp">
<TextView
android:id="#+id/itemName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TEST"
android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>
custom_row:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" android:background="#2fff00">
<item android:drawable="#color/colorPrimary" android:state_pressed="true" /> <!-- pressed -->
</selector>
ApplicationUtils:
public final class ApplicationUtils extends Application {
private static Context context;
public void onCreate() {
super.onCreate();
ApplicationUtils.context = getApplicationContext();
}
public static Context getContext() {
return ApplicationUtils.context;
}
public static String getJavaPackageName() {
return ApplicationUtils.context.getPackageName();
}
public static Resources getAppResources() {
return getContext().getResources();
}
public static String getResouceName(Integer id) {
return getAppResources().getResourceName(id);
}
public static String getResourceString(Integer id) {
return getAppResources().getString(id);
}
public static int getResourceId(String variableName, String resourceName, String packageName) {
try {
return getContext().getResources().getIdentifier(variableName, resourceName, packageName);
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
}
Lists:
public class Lists extends AppCompatActivity implements CategoriesFragment.OnHeadlineSelectedListener {
private String listName;
public void onItemSelected(String currentCategory) {
ItemsFragment itemsCallBackFragment = (ItemsFragment) getSupportFragmentManager().findFragmentById(R.id.itemsFragment);
if (itemsCallBackFragment != null) {
itemsCallBackFragment.updateArticleView(currentCategory);
} else {
ItemsFragment itemFragment = new ItemsFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.itemsFragment, itemFragment);
transaction.addToBackStack(null);
transaction.commit();
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_triple_list);
setListsAdapter();
}
private void setListsAdapter() {
ViewPager tripleListViewPager = (ViewPager) findViewById(R.id.listsPager);
FragmentPagerAdapter tripleListFragmentAdapt = new ListsPagerAdapter(getSupportFragmentManager(), "LIST NAME", ApplicationUtils.getContext());
tripleListViewPager.setAdapter(tripleListFragmentAdapt);
}
}
ListsPagerAdapter:
public class ListsPagerAdapter extends FragmentPagerAdapter {
private static int NUM_TABS = 1;
private String listName;
private Context listsContext;
public ListsPagerAdapter(FragmentManager fm, String newListName, Context listsContext) {
super(fm);
setListName(newListName);
setListsContext(listsContext);
}
// Returns total number of pages
#Override
public int getCount() {
return NUM_TABS;
}
// Returns the fragment to display for that page
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return NewItemPagerFragment.newInstance();
default:
return null;
}
}
// Returns the page title for the top indicator
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return listsContext.getResources().getString(R.string.lists_tab_newItem, getListName());
default:
return "$value";
}
}
public String getListName() {
return listName;
}
public void setListName(String listName) {
this.listName = listName;
}
public Context getListsContext() {
return listsContext;
}
public void setListsContext(Context listsContext) {
this.listsContext = listsContext;
}
}
CategoriesFragment:
public class CategoriesFragment extends Fragment {
private List<Integer> categoryIds = new ArrayList<>();
private String currentCategory;
private View categoriesView;
OnHeadlineSelectedListener itemCallback;
public interface OnHeadlineSelectedListener {
void onItemSelected(String categoryName);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
itemCallback = (OnHeadlineSelectedListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString()
+ " must implement OnHeadlineSelectedListener");
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
categoriesView = inflater.inflate(R.layout.fragment_categories, container, false);
categoriesView.setId(R.id.categoriesFragment);
return categoriesView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setCategoriesListener();
setDefaultSelectedCategory();
}
private void setCategoriesListener() {
categoryIds.add(R.id.category1);
for (Integer id : categoryIds) {
setListener(id);
}
}
private void setListener(final int categoryId) {
final ImageView categoryImg = (ImageView) categoriesView.findViewById(categoryId);
categoryImg.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
removePreviousSelectedCategory(categoryImg);
selectCategory(categoryId, categoryImg);
loadItemList();
}
});
}
private void removePreviousSelectedCategory(ImageView categoryImg) {
for (Integer id : categoryIds) {
final ImageView imgView = (ImageView) categoriesView.findViewById(id);
if (imgView.getTag() != null) {
String previousSelectedCategory = (String) imgView.getTag();
if (StringUtils.contains(previousSelectedCategory, Application.SELECTED)) {
previousSelectedCategory = previousSelectedCategory.replace(Application.SELECTED, "");
categoryImg.setTag(previousSelectedCategory);
Integer previousSelectedCategoryId = ApplicationUtils.getResourceId(previousSelectedCategory, Application.RES_DRAWABLE, ApplicationUtils.getJavaPackageName());
imgView.setImageResource(previousSelectedCategoryId);
}
}
}
}
private void selectCategory(int categoryId, ImageView categoryImg) {
String newSelectedCategory = ApplicationUtils.getResouceName(categoryId) + Application.SELECTED;
setCurrentCategory(newSelectedCategory);
newSelectedCategory = newSelectedCategory.replace(Application.META_INFO_ID, "");
categoryImg.setTag(newSelectedCategory);
Integer currentCategoryId = ApplicationUtils.getResourceId(newSelectedCategory, Application.RES_DRAWABLE, ApplicationUtils.getJavaPackageName());
categoryImg.setImageResource(currentCategoryId);
}
public String getCurrentCategory() {
return currentCategory;
}
public void setCurrentCategory(String currentCategory) {
this.currentCategory = currentCategory;
}
private void loadItemList() {
itemCallback.onItemSelected(getCurrentCategory());
}
private void setDefaultSelectedCategory() {
Integer categoryId = R.id.category1;
final ImageView categoryImg = (ImageView) categoriesView.findViewById(categoryId);
selectCategory(categoryId, categoryImg);
loadItemList();
}
}
ItemsFragment:
public class ItemsFragment extends Fragment {
private View itemsFragmentView;
private ListView itemsListView;
private ItemAdapter itemsListAdapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
itemsFragmentView = inflater.inflate(R.layout.fragment_items, container, false);
itemsListView = (ListView) itemsFragmentView.findViewById(R.id.itemsListView);
setItemsListAdapter();
return itemsFragmentView;
}
public void updateArticleView(String categoryName) {
getSelectedCategoryList();
}
private void getSelectedCategoryList() {
List<String> testList = new ArrayList<>();
testList.add("TEST ITEM");
itemsListAdapter.update(testList);
}
private void setItemsListAdapter() {
itemsListAdapter = new ItemAdapter(getActivity(), R.layout.fragment_items, new ArrayList<String>());
itemsListView.setAdapter(itemsListAdapter);
}
}
ItemAdapter:
public class ItemAdapter extends ArrayAdapter<String> {
private List<String> items = new ArrayList<>();
private LayoutInflater rowInflater;
public ItemAdapter(Context context, int resource, List<String> itemsList) {
super(context, resource, itemsList);
this.items = itemsList;
this.rowInflater = LayoutInflater.from(context);
}
private class ItemHolder {
TextView itemNameView;
}
#Override
public View getView(int position, View rowView, ViewGroup parent) {
ItemHolder itemHolder;
if (rowView == null) {
rowView = rowInflater.inflate(R.layout.content_row_choose_item, parent, false);
itemHolder = new ItemHolder();
itemHolder.itemNameView = (TextView) rowView.findViewById(R.id.itemName);
rowView.setTag(itemHolder);
} else {
itemHolder = (ItemHolder) rowView.getTag();
}
String itemName = getItem(position);
if (StringUtils.isNotEmpty(itemName) && itemHolder.itemNameView != null) {
itemHolder.itemNameView.setText(itemName);
System.out.println("ITEM NAME ### " + itemHolder.itemNameView.getText());
}
return rowView;
}
public void update(List<String> items) {
this.items.clear();
this.items.addAll(items);
this.notifyDataSetChanged();
}
public List<String> getItems() {
return items;
}
}
Random stab...
If using a ListFragment, then fragment_items.xml needs a ListView with android:id="#android:id/list".
You are even trying to load the ListView with that id.
itemsFragmentView = inflater.inflate(R.layout.fragment_items, container, false);
itemsListView = (ListView) itemsFragmentView.findViewById(android.R.id.list);
However, you have android:id="#+id/itemsListView"
fragment_items:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#id/itemsFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="#+id/itemsListView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:divider="#null" />
</LinearLayout>
If using a ListFragment, you do not need to implement your own XML layout file. That being said, onCreateView doesn't need implemented. Use onActivityCreated instead.
#Override
public void onActivityCreated(Bundle savedInstanceState) {
itemsListView = getListView();
itemsListAdapter = new ItemAdapter(getActivity());
setListAdapter(itemsListAdapter);
super.onActivityCreated(savedInstanceState);
}
Now, if you want to add items to the adapter, I generally recommend you just use an ArrayAdapter<String>. This will provide you an add(String object) method that will both add to the underlying list and notify for updates.
Regarding the getView problems, can't really say. I don't really know why you need ItemAdapter since the default ArrayAdapter<String> will work assuming you pass it a layout with android:id="#android:id/text1, for example using android.R.layout.simple_list_item_1 in place of R.layout.content_row_choose_item
So, that would look something like.
#Override
public void onActivityCreated(Bundle savedInstanceState) {
itemsListView = getListView();
ArrayAdapter<String> itemsListAdapter = new ArrayAdapter<String>(
getActivity(), android.R.layout.simple_list_item_1);
setListAdapter(itemsListAdapter);
adapter.add("Hello");
adapter.add("World");
super.onActivityCreated(savedInstanceState);
}
The given MCVE was working fine. After 7 days debugging and uncommenting code I found the answer to my problem.
My list was correctly being updated, but wasn't being rendered because of a second ItemsFragemnt being initialized on Lists Activity load. This second fragment was overlaying the first one and that's why I wasn't seing my list being displayed/refreshed.
Lists:
First created fragment:
private void setListsAdapter() {
ViewPager tripleListViewPager = (ViewPager) findViewById(R.id.listsPager);
FragmentPagerAdapter tripleListFragmentAdapt = new ListsPagerAdapter(getSupportFragmentManager(), "LIST NAME", ApplicationUtils.getContext());
tripleListViewPager.setAdapter(tripleListFragmentAdapt); }
Inside ListsPagerAdapter there was a call to populate my ViewPager (NewItemPagerFragment) with CategoriesFragment and ItemsFragment.
Second created fragment - Overlay:
ItemsFragment itemFragment = new ItemsFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.itemsFragment, itemFragment);
transaction.addToBackStack(null);
transaction.commit();
I tried to breakpoint my code, mentioned before in Facts at question scope, but sometimes this is really painful. I came with the idea to use Log.d(TAG_KEY, TAG_NAME); and that was when I found out the answer: I realized that ItemsFragment was being called twice on Activity load.
I searched for new ItemsFragment in my project and saw that inside my NewItemPagerFragment onCreate, ItemsFragment was being called. Also before CategoriesFragment- just like this:
NewItemPagerFragment:
Fragment itemsFragment = new ItemsFragment();
FragmentManager fm1 = getChildFragmentManager();
FragmentTransaction ft1 = fm1.beginTransaction();
ft1.replace(R.id.itemsFragment, itemsFragment);
ft1.commit();
Fragment categoriesFragment = new CategoriesFragment();
FragmentManager fm = getChildFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.categoriesFragment, categoriesFragment);
ft.commit();
which explains Facts 2.. After commenting/remove this call on NewItemPagerFragment the problem was gone.
Bottom line is: Make sure your list is correctly being fulfilled/updated with things like notifyDataSetChanged as cricket_007 mentioned in his answer and other thousand posts I read on internet. Not less, make sure you are not overlaying the fragment calling its initialization twice.