I'm using TouchImageView to load images in full screen and have zoom/pinch capability.
The images are pulled from URL via a web service. The response is in JSON. At this part, I'm using Volley+GSON to obtain the response and use a custom adapter to populate the Pager.
Initially, the images are shown in a listview. When a user click an item, it will go full screen showing the chosen item.
However, in my case, this doesn't happen. Whatever position the user chose, it will still show the image at index 0.
Here is how I do it:
In this adapter, a user will click an item and it will pass the position to another activity.
public class ItemPhotoAdapter extends BaseAdapter {
private ArrayList<ItemImageModel> arrItemImage;
#Override
public ItemImageModel getItem(int i) {
return arrItemImage.get(i);
}
...
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder vh;
lf = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if(view == null){
vh = new ViewHolder();
view = lf.inflate(R.layout.row_photo_grid, null);
vh.item_image = (ImageView) view.findViewById(R.id.img_item);
view.setTag(vh);
} else {
vh = (ViewHolder) view.getTag();
}
ItemImageModel iim = arrItemImage.get(i);
Picasso.with(context) //
.load(iim.getResized()) //
.placeholder(R.drawable.placeholder) //
.error(R.drawable.error)
.into(vh.item_image);
vh.item_image.setOnClickListener(new OnImageClickListener(i));
return view;
}
...
private class OnImageClickListener implements View.OnClickListener {
int _position;
public OnImageClickListener(int position) {
this._position = position;
}
#Override
public void onClick(View view) {
Intent i = new Intent(context, PhotoGalleryActivity.class);
i.putExtra("position", _position);
context.startActivity(i);
}
}
}
In PhotoGalleryActivity, will load all the images back, but it doesn't start with the item the user chose.
public class PhotoGalleryActivity extends FragmentActivity {
private ArrayList<ItemImageModel> arrItemImages;
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_photo_gallery);
ViewPager mViewPager = (ViewPager) findViewById(R.id.pager);
pb = (ProgressBar) findViewById(R.id.loading);
ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
arrItemImages = new ArrayList<ItemImageModel>();
Intent i = getIntent();
final int position = i.getIntExtra("position", 1);
user_id = i.getStringExtra("user_id");
item_id = i.getStringExtra("item_id");
// Log.d(TAG, "Image position: " + position);
mAdapter = new PhotoGalleryAdapter(arrItemImages, getApplicationContext(), this);
mViewPager.setAdapter(mAdapter);
mViewPager.setCurrentItem(position);
// ViewPagerIndicator
CirclePageIndicator titleIndicator = (CirclePageIndicator)findViewById(R.id.titles);
titleIndicator.setViewPager(mViewPager);
loadPhotos();
}
...
private void loadPhotos() {
mRequestQueue = Volley.newRequestQueue(this);
String url = Constants.ITEM_DETAILS;
GsonRequest<ItemDetailContainer> myReq = new GsonRequest<ItemDetailContainer>(
Request.Method.GET, url, ItemDetailContainer.class,
createMyReqSuccessListener(), createMyReqErrorListener());
mRequestQueue.add(myReq);
}
...
}
I've found the solution.
To use SetCurrentItem correctly, in this case, I have to put it after all the images is loaded. Eg. after notifysetdatachanged.
In Volley response listener function,
private Response.Listener<ItemDetailContainer> createMyReqSuccessListener() {
return new Response.Listener<ItemDetailContainer>() {
#Override
public void onResponse(ItemDetailContainer response) {
try {
...
mAdapter.notifyDataSetChanged();
mViewPager.setCurrentItem(position); // this
} catch (Exception e) {
e.printStackTrace();
}
};
};
}
If you want to retain the tab index through screen rotation, you can save the value into a member variable first:
if (savedInstanceState != null) {
mLastTabIndex = savedInstanceState.getInt(KEY_TAB_INDEX, 0);
} else {
mLastTabIndex = -1;
}
And only after the tabs data have been loaded into tab adapter, would you check the member variable and set current tab index if present:
mPostTypes = result.getTypes();
mAdapter.notifyDataSetChanged();
if (mLastTabIndex > 0) {
mViewPager.setCurrentItem(mLastTabIndex);
}
Related
public class FormContentViewFragment extends Fragment implements View.OnClickListener {
private View view;
private View textView;
private TextView headerView;
private TextView fieldInstructionView;
private ImageButton backButton;
private ImageButton forwardButton;
private ProgressBar progressBar;
private ViewPager viewPager;
private int number;
private String value;
private String fieldinstruction;
private List<String> headerList = new ArrayList<String>();
private List<String> fieldInstructionList = new ArrayList<String>();
private LayoutInflater inflater;
private FormContentViewAdapter adapter;
public FormContentViewFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_form_content_view, container, false);
return view;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
backButton = (ImageButton) view.findViewById(R.id.back_button);
forwardButton = (ImageButton) view.findViewById(R.id.forward_button);
progressBar = (ProgressBar) view.findViewById(R.id.progress_bar);
adapter = new FormContentViewAdapter();
Log.e("onActivityCreated()......","..........before set adapter........");
viewPager = (ViewPager) view.findViewById(R.id.view_pager);
viewPager.setAdapter(adapter);
Log.e("onActivityCreated()......","..........after set adapter........");
getViewContent();
}
public void getViewContent() {
MainActivity.showLoader(getActivity());
final StringRequest stringRequest = new StringRequest(Request.Method.GET, "JSON URL", new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.e("Response", ".............." + response);
try {
JSONObject jsonObject = new JSONObject(response);
boolean status = jsonObject.getBoolean("status");
if (status == true) {
JSONArray list = jsonObject.getJSONArray("list");
for (int i = 0; i < list.length(); i++) {
JSONObject currentData = list.getJSONObject(i);
number = currentData.getInt("number");
Log.e("number", "....." + number);
value = currentData.getString("value");
Log.e("value", "....." + value);
fieldinstruction = currentData.getString("fieldinstruction");
Log.e("fieldInstruction", "......" + fieldinstruction);
headerList.add(value);
Log.e("headerList...", "......" + headerList);
fieldInstructionList.add(fieldinstruction);
Log.e("instructioList", "....." + fieldInstructionList);
Toast.makeText(getContext(), "Dispaly data", Toast.LENGTH_SHORT).show();
}
// headerView.setText(headerList.get(1));
// fieldInstructionView.setText(fieldInstructionList.toString());
}
MainActivity.hideLoader();
} catch (JSONException e) {
e.printStackTrace();
MainActivity.hideLoader();
}
Log.e("number out.....", "....." + number);
MainActivity.hideLoader();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
String errorResponse = String.valueOf(error.networkResponse.data);
Log.e("ErrorResponse", "........" + errorResponse);
MainActivity.hideLoader();
}
}) {
};
ApplicationController.getInstance().addToRequestQueue(stringRequest);
}
#Override
public void onClick(View view) {
}
class FormContentViewAdapter extends PagerAdapter {
public FormContentViewAdapter(){
Log.e("FormContentViewAdapter","..............inside....");
Log.e("headerList1...", "......" + headerList.toString());
Log.e("instructioList1...", "....." + fieldInstructionList.toString());
Log.e("FormContentViewAdapter","..............end of it....");
}
#Override
public int getCount() {
Log.e("headerList1...", "......" + headerList.toString());
Log.e("instructioList1...", "....." + fieldInstructionList.toString());
Log.e("value getCount().......","........"+number);
return number;
}
#Override
public boolean isViewFromObject(View view, Object object) {
Log.e("isViewFromObject().....","inside.........");
return false;
}
#Override
public View instantiateItem(ViewGroup container, int position) {
Log.e("instantiateItem()......","inside.........");
textView = inflater.inflate(R.layout.view_pager_content, container, false);
headerView = (TextView) textView.findViewById(R.id.header_text_view);
fieldInstructionView = (TextView) textView.findViewById(R.id.instruction_text_view);
headerView.setText(headerList.get(position));
Log.e("headerList2.....","............."+headerList.toString());
fieldInstructionView.setText(fieldInstructionList.toString());
Log.e("fieldInstructionList2........",".........."+fieldInstructionList.get(position));
container.addView(textView);
Log.e("instantiateItem()......","end of it.........");
return textView;
}
#Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
}
}
}
Error:
java.lang.IllegalStateException: The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDataSetChanged! Expected adapter item count: 0, found: 2 Pager id: com.formfilling:id/view_pager Pager class: class android.support.v4.view.ViewPager Problematic adapter: class com.formfilling.FormContentViewFragment$FormContentViewAdapter
at android.support.v4.view.ViewPager.populate(ViewPager.java:1171)
at android.support.v4.view.ViewPager.populate(ViewPager.java:1120)
at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1646)
I have single Fragment, within that ViewPager is there I want to set the different layout to that ViewPager So I also use an adapter to set the layout in ViewPager but it throws an error IllegalStateException. I already doing all things for that but it is not working.Give your suggestions
Actually, you are trying to reference Activity's number variable directly inside pagerAdapter's getCount() method. While the ViewPager is doing its thing, it references the adapter again and again. So it checks that getCount() .But your Background thread changes the number variable value to some new value ,which causes a mismatch in the previous value which was 0 in the pagerAdapter. Hence IllegalStateException will be thrown
Note:getCount() may be called several times by the ViewPager. It must remain constant, for the life of the PagerAdapter .
Recommended option is to keep the getCount value to some constant value if you know how many pages to be shown, but if it changes Dynamically, then there is a way, whenever your number changes, you have to set the adapter again to the viewPager, notifyDataSetChanged will not work for this situation.
you have to do something like this inside your onResponse method as shown below
number = currentData.getInt("number");
viewPager.setAdapter(adapter);
this will again clear the count and take a new count which will be your new value.
My adapter list is refreshing on broadcast receiver .
Everything is working fine if adapter list size is greater than 1 ,
means if my recyclerview has already one row shwoing then list refreshing just fine .
But if list size goes from 0 to 1 then my adapter notify dataset
Changed stop working . No data shows on recyclerview. I don't know why it is not working .
Recyclerview Class:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
v = inflater.inflate(R.layout.job_recyclerview, container, false);
getActivity());
initialise(v);
init();
showNoTaskMessage();
new loadListTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
mMyBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Here you can refresh your listview or other UI
SlidingTab.slidingTab.getTabAt(0).setText("New (" + SingleTon.getInstance().getNewjob() + ")");
SlidingTab.slidingTab.getTabAt(1).setText("In Progress (" + SingleTon.getInstance().getInprogressjob() + ")");;
SlidingTab.slidingTab.getTabAt(2).setText("Completed (" + SingleTon.getInstance().getCompletedjob() + ")");
}
};
try {
IntentFilter filter = new IntentFilter("newJob");
LocalBroadcastManager.getInstance(context).registerReceiver(mMyBroadcastReceiver,
filter);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return v;
}
Adapter class :
public JobAdapter(ArrayList<Info> myDataset, Context context) {
this.mDataset = myDataset;
this.mAct = context;
}
public void addApplications(ArrayList<Info> candidates) {
if (this.filterList == null) {
filterList = new ArrayList<>();
}
this.mDataset.clear();
this.mDataset.addAll(candidates);
this.filterList.addAll(mDataset);
this.notifyItemRangeInserted(0, candidates.size() - 1);
}
public void clearApplications() {
int size = this.mDataset.size();
if (size > 0) {
for (int i = 0; i < size; i++) {
mDataset.remove(0);
filterList.remove(0);
}
this.notifyItemRangeRemoved(0, size);
}
}
#Override
public int getItemViewType(int position) {
return VIEW_NORMAL;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_job_card, parent, false);
ViewHolder fh = new ViewHolder(v);
return fh;
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
// holder.jobPhone.setText(mDataset.get(position).mobileNo);
holder.jobNumber.setText(mDataset.get(position).jobNumber);
holder.jobTime.setText(mDataset.get(position).time);
holder.jobAddress.setText(mDataset.get(position).address);
// holder.jobInstructionText.setText(mDataset.get(position).spclInstruction);
if (mDataset.get(position).jobStatus != null && mDataset.get(position).jobStatus.equalsIgnoreCase("Completed")) {
holder.endsat.setText("Submitted at");
holder.jobTime.setText(mDataset.get(position).completedOnString);
holder.jobTimeLeft.setVisibility(View.INVISIBLE);
holder.timerImage.setVisibility(View.INVISIBLE);
} else {
if (mDataset.get(position).status.equalsIgnoreCase("Active")) {
holder.jobTimeLeft.setText(mDataset.get(position).appointmentTime);
} else {
holder.jobTimeLeft.setText("-" + mDataset.get(position).appointmentTime);
}
}
holder.jobLayout1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
SingleTon.getInstance().setWorkDescHolder(mDataset.get(position).descHolder);
FragmentManager fragmentManager = ((FragmentActivity) mAct).getSupportFragmentManager();
FragmentTransaction ft = ((FragmentActivity) mAct).getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.glide_fragment_horizontal_in, R.anim.glide_fragment_horizontal_out);
ft.replace(R.id.content_frame1, new DetailsFragment(), "persondetails");
ft.addToBackStack("persondetails");
// Start the animated transition.
ft.commit();
}
});
}
#Override
public int getItemCount() {
return mDataset.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView jobNumber, jobTimeLeft, jobStatus, jobAddress, jobEmail, jobPhone, timeTimer, jobInstructionText, jobTime, endsat;
private ImageView timerImage;
private FrameLayout frameLayout;
private CardView cardView;
private LayoutRipple jobLayout1;
public ViewHolder(View v) {
super(v);
this.jobNumber = (TextView) v.findViewById(R.id.job_number);
this.jobTime = (TextView) v.findViewById(R.id.job_time);
this.jobTimeLeft = (TextView) v.findViewById(R.id.job_timertext);
this.timerImage = (ImageView) v.findViewById(R.id.timerimage);
this.cardView = (CardView) v.findViewById(R.id.card_view);
// this.jobStatus = (TextView) v.findViewById(R.id.job_status);
this.jobAddress = (TextView) v.findViewById(R.id.job_addresstext);
// this.jobInstructionText = (TextView) v.findViewById(R.id.instruction_text);
// this.jobLayout = (LayoutRipple)v.findViewById(R.id.job_cardLayout);
this.jobLayout1 = (LayoutRipple) v.findViewById(R.id.cardLayout1);
this.endsat = (AppCompatTextView) v.findViewById(R.id.endsat);
this.jobNumber.setTypeface(Utils.RegularTypeface(mAct));
this.jobAddress.setTypeface(Utils.RegularTypeface(mAct));
this.jobTimeLeft.setTypeface(Utils.RegularTypeface(mAct));
this.jobTime.setTypeface(Utils.RegularTypeface(mAct));
}
}
}
Please help me finding the bug or some other approach . Thanks
Call the data loading task inside the onReceive() of BroadcastReceiver
mMyBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Here you can refresh your listview or other UI
new loadListTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
SlidingTab.slidingTab.getTabAt(0).setText("New (" + SingleTon.getInstance().getNewjob() + ")");
SlidingTab.slidingTab.getTabAt(1).setText("In Progress (" + SingleTon.getInstance().getInprogressjob() + ")");;
SlidingTab.slidingTab.getTabAt(2).setText("Completed (" + SingleTon.getInstance().getCompletedjob() + ")");
}
};
And also do following changes in your Adapter class.
public void addApplications(ArrayList<Info> candidates) {
if (this.filterList == null) {
filterList = new ArrayList<>();
}
this.mDataset.clear();
this.mDataset.addAll(candidates);
this.filterList.addAll(mDataset);
this.notifyItemRangeInserted(0, candidates.size());
}
public void clearApplications() {
int size = this.mDataset.size();
if (size > 0) {
for (int i = 0; i < size; i++) {
mDataset.remove(i);
filterList.remove(i);
}
this.notifyItemRangeRemoved(0, size);
}
}
Hope that works!
Change this:
mMyBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Here you can refresh your listview or other UI
recycleAdapter.addItems(SingleTon.getInstance()
.getInfoArrayList());
// I'm assuming your "SingleTon.getInstance().getInfoArrayList()" is the received data.
}
On your Adapter
public void addItems(List<Info> itemsList) {
// This check could be avoided if you declared your mDataset final
if(mDataset == null) {
mDataset = new ArrayList<>();
}
int prevSize = mDataset.size();
mDataset.addAll(itemsList);
notifyItemRangeInserted(prevSize, itemsList.size());
}
You shouldn't call notifyDataSetChanged() after this.notifyItemRangeInserted(0, candidates.size() - 1); try something like this:
put this method to your adapter class
public void setData(ArrayList<Info> infos) {
this.mDataset = infos;
notifyDataSetChanged();
}
and call it like this:
ArrayList<Info> list = SingleTon.getInstance().getInfoArrayList().isEmpty();
if (list != null && !list.isEmpty()) {
recycleAdapter.setData(list);
}
correct this method in your adapter
#Override
public int getItemCount() {
return mDataset != null && !mDataset.isEmpty() ? mDataset.size() : 0;
}
Base on your code, we need a variable list to store your info data.
//Declare the info list
private ArrayList<Info> mInfos = new ArrayList<Info>()
In your onCreateView(), set mInfos to your recycleAdapter
recycleAdapter = new JobAdapter(mInfos, getActivity());
recyclerView.setAdapter(recycleAdapter);
So, every time you want to set new info list. Just assign it to mInfos
and make sure, you clear your previous list data to avoid duplicate data.
mInfos.clear()
mInfos.addAll(SingleTon.getInstance().getInfoArrayList());
//refresh data
recycleAdapter.notifyDataSetChanged();
I am not sure where you are using clearApplications() in JobAdapter.class.
But, it seems to be wrong. In the for-loop, you are trying to remove the value at index 0 every time rather than index 'i'. Hope this helps.
when you are using custom adapter then notifyDatasetChange() not called from outside that adapter so make addItem function in adapter and add new List in Adapter list and call notifyDataSetChanged
public void addItem(List<Model> list) {
if (lit != null) {
clear();
adapterList.addAll(list);
}
notifyDataSetChanged();
}
Do Change In your recyclerview class.
//Change condition ">1" to "!=null"
if (SingleTon.getInstance().getInfoArrayList().size() != null) {
recycleAdapter.addApplications(SingleTon.getInstance().getInfoArrayList());
recycleAdapter.notifyDataSetChanged();
and then do change in your adapter.
public void addApplications(ArrayList<Info> candidates) {
if (this.filterList == null) {
filterList = new ArrayList<>();
}
this.mDataset.clear();
this.mDataset.addAll(candidates);
this.filterList.addAll(mDataset);
this.notifyItemRangeInserted(0, mDataset.size()); //notify to mDataset
}
hope this will work!
I am working on an app that includes shopping feature and items are added to cart.
I have navigation drawer. In that, I have my first fragment called as "POSFragment" in which I have implemented a viewpager as data to be shown in the form of swipeable tabs. The data will be inflated dynamically. So, I have used PagerTabStrip and a viewpager. There is a common fragment called "MenuDetailFragment" in which data will be inflated dynamically through a webservice. the adapter for this fragment is "MenuPagerAdapter". Now, In this fragment the data will shown in listview. In Listview in each row items can be incremented or decremented using plus and minus Buttons in each row. Between these button there is textview where the quantity will be displayed correspondingly. I have used a Linkedhashmap on both buttons so, the items along with the quantity is saved in linkedhashmap and then in Sharedpreferences. It's working fine till now. The issue occurs when I swipe in the View pager and next fragment appears and When I click on increment button or decrement button on item there. In shared preferences, It starts saving the current fragment items and previous fragment data is not there anymore. I have already used the "yourcustomviewpager.setOffscreenPageLimit(3)" So, I can see the selected items with the quantities whe I swipe to and fro but the data i stored in sharedpreferences using Linkedhashmap is not there instead current fragment's data is saved. I want that the new data is added to previous data and data in all the fragments should persist. Is there a way to do so? I have been facing this issue for quite a long time.
Here are some screenshots and relevant code snippet.
public class PosFragment extends Fragment {
private ViewPager viewPager;
View rootview;
String code;
String name;
String desc;
String rate;
String key;
Button viewCartBtn;
static TextView displayPrice;
static TextView noOfItemsInCart;
RippleView rippleView;
//private sendPosition pos;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
Log.e("oncreateview", "called");
// Inflate the layout for this fragment
rootview = inflater.inflate(R.layout.pos_fragment_layout, container, false);
initViews();
new AsyncTaskGetMenu().execute();
return rootview;
}
public void initViews() {
Log.e("init", "called");
viewPager = (ViewPager) rootview.findViewById(R.id.viewPager);
Button viewCartButton = (Button) rootview.findViewById(R.id.view_cart_btn);
viewPager.setOffscreenPageLimit(3);
viewCartBtn = (Button) rootview.findViewById(R.id.view_cart_btn);
AppMethods.setGlametrixBoldFont(getActivity(), viewCartBtn);
displayPrice = (TextView) rootview.findViewById(R.id.textView_totalprice_cart);
noOfItemsInCart = (TextView) rootview.findViewById(R.id.cart_items_quantity);
viewCartBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), ViewCartActivity.class);
intent.putExtra(AppConstants.SUBTOTAL, Integer.parseInt(displayPrice.getText().toString()));
startActivity(intent);
}
});
LinearLayout itemsInCartLinearLayout = (LinearLayout) rootview.findViewById(R.id.ll_items_in_cart);
itemsInCartLinearLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), ViewCartActivity.class);
intent.putExtra(AppConstants.SUBTOTAL, Integer.parseInt(displayPrice.getText().toString()));
startActivity(intent);
}
});
}
This is "MenuDetailFragment" class
public class MenuDetailFragment extends Fragment {
View rootview;
private ListView listView;
private ArrayList<MenuHeadingDetailsModel> menuheadingDetailList;
private Communicate comm;
LinkedHashMap<String, ViewCartDetailsModel> viewCartDetailsModelMap = new LinkedHashMap<>();
ViewCartDetailsModel viewCartDetailsModel;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
// Inflate the layout for this fragment
rootview = inflater.inflate(R.layout.menu_list, container, false);
InitializeViews();
return rootview;
}
public void InitializeViews() {
listView = (ListView) rootview.findViewById(R.id.menu_items_list);
Bundle bundle = getArguments();
menuheadingDetailList = bundle.getParcelableArrayList(AppConstants.MENU_KEY);
listView.setAdapter(new MenuAdapter(getActivity(), menuheadingDetailList));[enter image description here][1]
This is"MenuPagerAdapter" class
public class MenuPagerAdapter extends FragmentStatePagerAdapter {
List<MenuModel> menu;
public MenuPagerAdapter(FragmentManager fm, List<MenuModel> menuList) {
super(fm);
this.menu = menuList;
}
#Override
public CharSequence getPageTitle(int position) {
return menu.get(position).getHeading().toString();
}
private List<MenuHeadingDetailsModel> getMenuHeadingDetails(int pos) {
return this.menu.get(pos).getMenuHeadingDetailList();
}
#Override
public Fragment getItem(int position) {
Fragment fragment = new MenuDetailFragment();
Bundle bundle = new Bundle();
bundle.putParcelableArrayList(AppConstants.MENU_KEY, (ArrayList<? extends Parcelable>) getMenuHeadingDetails(position));
fragment.setArguments(bundle);
return fragment;
}
#Override
public int getCount() {
return menu.size();
}
#Override
public void unregisterDataSetObserver(DataSetObserver observer) {
if (observer == null) {
super.unregisterDataSetObserver(observer);
}
}
#Override
public void destroyItem (ViewGroup container, int position, Object object)
{
Log.e("destroyitem","called");
}
}
class MenuAdapter extends BaseAdapter {
//ViewHolder holder;
Context context;
List<MenuHeadingDetailsModel> myItems = new ArrayList<>();
Button buttonPlus, buttonMinus;
int totalAmount = 0;
int pagePosition;
public MenuAdapter(Context context, List<MenuHeadingDetailsModel> myItems) {
this.context = context;
this.myItems = myItems;
}
#Override
public int getCount() {
return myItems.size();
}
#Override
public Object getItem(int position) {
return myItems.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder = new ViewHolder();
final LayoutInflater inflater = getActivity().getLayoutInflater();
convertView = inflater.inflate(R.layout.menu_list_item, null);
viewHolder.codeText = (TextView) convertView.findViewById(R.id.textView_code);
viewHolder.nameText = (TextView) convertView.findViewById(R.id.textView_name);
AppMethods.setGlametrixBoldFont(getActivity(), viewHolder.nameText);
viewHolder.descText = (TextView) convertView.findViewById(R.id.textView_desc);
viewHolder.rateText = (TextView) convertView.findViewById(R.id.textView_rate);
viewHolder.textViewNoOfItems = (TextView) convertView.findViewById(R.id.tv_no_of_items);
buttonMinus = (Button) convertView.findViewById(R.id.button_minus);
buttonPlus = (Button) convertView.findViewById(R.id.button_plus);
final MenuHeadingDetailsModel menu = myItems.get(position);
viewHolder.codeText.setText(menu.getCode());
viewHolder.nameText.setText(menu.getItemName());
viewHolder.descText.setText(menu.getDescription());
viewHolder.rateText.setText(menu.getRate());
viewHolder.textViewNoOfItems.setText("" + menu.getQuantity());
buttonPlus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MenuHeadingDetailsModel menuList = myItems.get(position);
menuList.setQuantity(menuList.getQuantity() + 1);
myItems.set(position, menuList);
int itemRate = Integer.parseInt(myItems.get(position).getRate());
int itemQuan = menuList.getQuantity();
String code = menuList.getCode();
String name = menuList.getItemName();
int totalAmountPerItem = itemQuan * itemRate;
viewCartDetailsModel = new ViewCartDetailsModel(code, name, itemQuan, itemRate);
viewCartDetailsModelMap.put(viewCartDetailsModel.getCode(), viewCartDetailsModel);
Log.e("hashmap", "size" + viewCartDetailsModelMap.size());
Gson gson = new Gson();
String hashMapToString = gson.toJson(viewCartDetailsModelMap);
AppPreferences.saveDataInSharedpreferences(getActivity(), AppConstants.VIEW_ITEMS_INT_CART_KEY, hashMapToString);
totalAmount += itemRate;
int amount = totalAmount;
onButtonPressedForAmount(amount);
notifyDataSetChanged();
int quan = 0;
TextView tv;
for (int i = 0; i < listView.getCount(); i++) {
View view = listView.getAdapter().getView(i, null, null);
tv = (TextView) view.findViewById(R.id.tv_no_of_items);
quan = quan + Integer.parseInt(tv.getText().toString());
}
onButtonClickedForQuantity(quan);
}
}
);
buttonMinus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MenuHeadingDetailsModel menuList = myItems.get(position);
if ((menuList.getQuantity() - 1) >= 0) {
menuList.setQuantity(menuList.getQuantity() - 1);
myItems.set(position, menuList);
int itemRate = Integer.parseInt(myItems.get(position).getRate());
int itemQuan = menuList.getQuantity();
String code = menuList.getCode();
String name = menuList.getItemName();
//int totalAmountPerItem = itemQuan * itemRate;
viewCartDetailsModel = new ViewCartDetailsModel(code, name, itemQuan, itemRate);
if (itemQuan == 0) {
viewCartDetailsModelMap.remove(code);
} else {
viewCartDetailsModelMap.put(viewCartDetailsModel.getCode(), viewCartDetailsModel);
}
Gson gson = new Gson();
String hashMapToString = gson.toJson(viewCartDetailsModelMap);
AppPreferences.saveDataInSharedpreferences(getActivity(), AppConstants.VIEW_ITEMS_INT_CART_KEY, hashMapToString);
if (totalAmount > 0) {
totalAmount -= itemRate;
Log.e("totalamount", "minus" + totalAmount);
int amount = totalAmount;
onButtonPressedForAmount(amount);
}
} else {
menuList.setQuantity(0);
myItems.set(position, menuList);
}
notifyDataSetChanged();
int quan = 0;
TextView tv;
for (int i = 0; i < listView.getCount(); i++) {
View view = listView.getAdapter().getView(i, null, null);
tv = (TextView) view.findViewById(R.id.tv_no_of_items);
quan = quan + Integer.parseInt(tv.getText().toString());
}
onButtonClickedForQuantity(quan);
}
}
);
return convertView;
}
public void onButtonPressedForAmount(int userData) {
if (comm != null) {
comm.sendAmount(userData);
}
}
public void onButtonClickedForQuantity(int quantity) {
if (comm != null) {
comm.sendQuantity(quantity);
}
}
class ViewHolder {
TextView nameText;
TextView codeText;
TextView descText;
TextView rateText;
TextView textViewNoOfItems;
}
}
//For settings fonts to the alert diaolog for customization of items
//public void setGlametrixBoldFont(TextView textView) {
//Typeface typeface = Typeface.createFromAsset(getActivity().getAssets(), "fonts/GlametrixBold.otf");
//textView.setTypeface(typeface);
// }
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
comm = (Communicate) activity;
} catch (Exception e) {
AppMethods.getStackTrace(e);
}
}
public interface Communicate {
public void sendAmount(int amount);
public void sendQuantity(int quantity);
}
// public void getPosition(int Position) {
//
// int pagePosition = Position;
// Log.e("pos", " " + pagePosition);
// }
}
You can get your current fragment inside view pager by following below way
SampleFragment sampleFr = (SampleFragment) viewPager.getAdapter().instantiateItem(viewPager, 0);
Now you can access any data you want using that fragment.
For the first time adding fragments in view pager do like below way.
BaseFragment frTimeLine = (BaseFragment) Fragment.instantiate(this, SampleFragment.class.getName());
fragments.add(frTimeLine);
BaseFragment frEarnTiqs = (BaseFragment) Fragment.instantiate(this, SampleFragment1.class.getName());
fragments.add(frEarnTiqs);
adapter = new ViewPagerAdapter(getSupportFragmentManager(), getResources(), fragments);
viewPager.setAdapter(adapter);
viewPager.setOffscreenPageLimit(3);
I have a simple weather app that consists of a view pager with 3 fragments (Current, Hourly and Daily weather forecast). When I launch my app for the very first time it works fine as well as I close and open it. However, I have noticed that when my app has been in the background processes for a while and then I open it, it crashes with this exception:
java.lang.NullPointerException: Attempt to read from field 'koemdzhiev.com.stormy.weather.Forecast koemdzhiev.com.stormy.ui.MainActivity.mForecast' on a null object reference
at koemdzhiev.com.stormy.ui.Current_forecast_fragment.updateDisplay(Current_forecast_fragment.java:120)
at koemdzhiev.com.stormy.ui.MainActivity$3$3.run(MainActivity.java:234)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5294)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699)
I suspect that this exception has something to do with the fact that I am not saving data using the saveInstance method.
This is my current fragment code:
public class Current_forecast_fragment extends Fragment {
private static final String TAG = "MainActivity";
private MainActivity mActivity;
TextView mTimeLabel;
TextView mTemperatureLabel;
TextView mHumidityValue;
TextView mPrecipValue;
TextView mSummaryLabel;
TextView mLocationLabel;
TextView mWindSpeedValue;
TextView mFeelsLike;
ImageView mIconImageView;
ImageView mDegreeImageView;
public SwipeRefreshLayout mSwipeRefreshLayout;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mActivity = ((MainActivity) getActivity());
}
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.current_forefast_fragment, container, false);
mTimeLabel = (TextView)v.findViewById(R.id.timeLabel);
mTemperatureLabel = (TextView)v.findViewById(R.id.temperatureLabel);
mHumidityValue = (TextView)v.findViewById(R.id.humidityValue);
mPrecipValue = (TextView)v.findViewById(R.id.precipValue);
mSummaryLabel = (TextView)v.findViewById(R.id.summaryLabel);
mLocationLabel = (TextView)v.findViewById(R.id.locationLabel);
mWindSpeedValue = (TextView)v.findViewById(R.id.windSpeedValue);
mFeelsLike = (TextView)v.findViewById(R.id.feels_like_label);
mIconImageView = (ImageView)v.findViewById(R.id.iconImageView);
mDegreeImageView = (ImageView)v.findViewById(R.id.degreeImageView);
mSwipeRefreshLayout = (SwipeRefreshLayout)v.findViewById(R.id.current_swipe_refresh_layout);
mSwipeRefreshLayout.setColorSchemeResources(R.color.orange, R.color.blue, R.color.green);
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
Log.d("TAG", "Swiping in current!");
//if there is internet and if the mSwipeRefreshLayout in the Hourly and daily fragments are not already running...
if (mActivity.isNetworkAvailable()) {
if (!mActivity.mHourly_forecast_fragment.mSwipeRefreshLayout.isRefreshing() && !mActivity.mDaily_forecast_fragment.mSwipeRefreshLayout.isRefreshing()) {
if (mActivity.isLocationServicesEnabled()) {
if (mActivity.latitude != 0.0 && mActivity.longitude != 0.0) {
mActivity.getForecast(mActivity.latitude, mActivity.longitude);
} else {
mActivity.getLocation();
}
}else{
mActivity.alertForNoLocationEnabled();
}
}else{
mSwipeRefreshLayout.setRefreshing(false);
Toast.makeText(mActivity, "currently refreshing...", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(mActivity, "No Internet Connection!", Toast.LENGTH_LONG).show();
mSwipeRefreshLayout.setRefreshing(false);
}
}
});
//Start the swipe refresh layout on start up is internet available
if(mActivity.isNetworkAvailable())
mSwipeRefreshLayout.post(new Runnable() {
#Override
public void run() {
mSwipeRefreshLayout.setRefreshing(true);
Log.d("TAG","running swiping...");
}
});
return v;
}
public void updateDisplay() {
if(mActivity.mForecast != null) {
Current current = mActivity.mForecast.getCurrent();
//setting the current weather details to the ui
mTemperatureLabel.setText(current.getTemperature() + "");
mTimeLabel.setText("At " + current.getFormattedTime() + " it is");
mHumidityValue.setText(current.getHumidity() + "%");
mPrecipValue.setText(current.getPrecipChange() + "%");
mSummaryLabel.setText(current.getSummery());
mWindSpeedValue.setText(current.getWindSpeed() + "");
mFeelsLike.setText("Feels like: " + current.getFeelsLike());
mLocationLabel.setText(mActivity.locationName);
Drawable drawable = ContextCompat.getDrawable(mActivity, current.getIconId());
mIconImageView.setImageDrawable(drawable);
}else{
Toast.makeText(getActivity(),"Could not update data at this time! Please, try again.",Toast.LENGTH_LONG).show();
}
}
}
Fragment page adapter code:
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
private Current_forecast_fragment mCurrent_forecast_fragment;
private Hourly_forecast_fragment mHourly_forecast_fragment;
private Daily_forecast_fragment mDaily_forecast_fragment;
CharSequence Titles[]; // This will Store the Titles of the Tabs which are Going to be passed when ViewPagerAdapter is created
int NumbOfTabs; // Store the number of tabs, this will also be passed when the ViewPagerAdapter is created
// Build a Constructor and assign the passed Values to appropriate values in the class
public ViewPagerAdapter(FragmentManager fm,CharSequence mTitles[], int mNumbOfTabsumb,Current_forecast_fragment current_fragment,
Hourly_forecast_fragment hourly_fragment,
Daily_forecast_fragment daily_fragment) {
super(fm);
this.mCurrent_forecast_fragment = current_fragment;
this.mHourly_forecast_fragment = hourly_fragment;
this.mDaily_forecast_fragment = daily_fragment;
this.Titles = mTitles;
this.NumbOfTabs = mNumbOfTabsumb;
}
//This method return the fragment for the every position in the View Pager
#Override
public Fragment getItem(int position) {
if(position == 0) // if the position is 0 we are returning the First tab
{
return this.mCurrent_forecast_fragment;
}
else if (position == 1) // As we are having 2 tabs if the position is now 0 it must be 1 so we are returning second tab
{
return this.mHourly_forecast_fragment;
}else {
return this.mDaily_forecast_fragment;
}
}
// This method return the titles for the Tabs in the Tab Strip
#Override
public CharSequence getPageTitle(int position) {
return Titles[position];
}
// This method return the Number of tabs for the tabs Strip
#Override
public int getCount() {
return NumbOfTabs;
}
}
My main activity code:
public class MainActivity extends AppCompatActivity {
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.mCurrent_forecast_fragment = new Current_forecast_fragment();
this.mHourly_forecast_fragment = new Hourly_forecast_fragment();
this.mDaily_forecast_fragment = new Daily_forecast_fragment();
// Creating The ViewPagerAdapter and Passing Fragment Manager, Titles fot the Tabs and Number Of Tabs.
adapter = new ViewPagerAdapter(getSupportFragmentManager(), Titles, Numboftabs, mCurrent_forecast_fragment,
mHourly_forecast_fragment, mDaily_forecast_fragment);
// Assigning ViewPager View and setting the adapter
pager = (ViewPager) findViewById(R.id.pager);
pager.setOffscreenPageLimit(3);
pager.setAdapter(adapter);
// Assiging the Sliding Tab Layout View
tabs = (SlidingTabLayout) findViewById(R.id.tabs);
tabs.setDistributeEvenly(true); // To make the Tabs Fixed set this true, This makes the tabs Space Evenly in Available width
// Setting Custom Color for the Scroll bar indicator of the Tab View
tabs.setCustomTabColorizer(new SlidingTabLayout.TabColorizer() {
#Override
public int getIndicatorColor(int position) {
return ContextCompat.getColor(MainActivity.this, R.color.tabsScrollColor);
}
});
// Setting the ViewPager For the SlidingTabsLayout
tabs.setViewPager(pager);
}
I have this method in MainActivity which updates the data in the fragments:
public void getForecast(double latitude, double longitude) {
//scedule no response from the server task...
mScheduledFuture = exec.schedule(mNotAbleToGetWeatherDataTask,12, TimeUnit.SECONDS);
Log.d(TAG, "getForecast initiated...");
String API_KEY = "3ed3a1906736c6f6c467606bd1f91e2c";
String forecast = "https://api.forecast.io/forecast/" + API_KEY + "/" + latitude + "," + longitude + "?units=si";
if (isNetworkAvailable()) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(forecast)
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
runOnUiThread(new Runnable() {
#Override
public void run() {
toggleSwipeRefreshLayoutsOff();
}
});
#Override
public void onResponse(Response response) throws IOException {
runOnUiThread(new Runnable() {
#Override
public void run() {
toggleSwipeRefreshLayoutsOff();
}
});
try {
String jsonData = response.body().string();
if (response.isSuccessful()) {
mForecast = parseForecastDetails(jsonData);
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.d(TAG, "isSuccessful - run on UNI threth (update display)...");
//THIS LINE BELLOW CAUSES THE NPE...
mCurrent_forecast_fragment.updateDisplay();
mHourly_forecast_fragment.setUpHourlyFragment();
mDaily_forecast_fragment.setUpDailyFragment();
toggleSwipeRefreshLayoutsOff();
//set the isFirstTime to true so that the next refresh wont get location
isFirstTimeLaunchingTheApp = false;
}
});
} else {
alertUserAboutError();
}
} catch (IOException | JSONException e) {
Log.e(TAG, "Exception caught:", e);
}
}
Is because mActivity is null.
Add this line in onResume() method
mActivity = ((MainActivity) getActivity());
Like this
#Override
public void onResume() {
super.onResume();
mActivity = ((MainActivity) getActivity());
}
I have a ListView in which there several rows containing two buttons and a ProgressBar (Visibility:GONE) each.
My purpose is to display the ProgressBar upon click on the buttons and after completing a certain set of background operations remove that row entirely.
The problem here is that after removing the item from the ArrayList which the ListView is created upon and calling notifyDataSetChanged the row is removed successfully but the ProgressBar remains visible.
Shouldn't it be removed along with it's parent view?
Checkout the following record to see the problem in action.
Here is the source of my entire fragment:
public class FriendRequestFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
private static final String TAG = "FriendRequestFragment";
ArrayList<FriendRequest> friendRequests;
#InjectView(R.id.friendRequestList)
ListView mListView;
#InjectView(R.id.noRequestsText)
TextView noRequestsText;
#InjectView(R.id.swipe)
SwipeRefreshLayout swipeRefreshLayout;
// NotificationHandler nh;
/**
* The Adapter which will be used to populate the ListView/GridView with
* Views.
*/
private FriendRequestAdapter mAdapter;
private Context c;
private boolean isProcessing = false;
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public FriendRequestFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Util.trackFragment(this);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_friendrequest_list, container, false);
ButterKnife.inject(this, view);
c = getActivity();
friendRequests = new ArrayList<>();
swipeRefreshLayout.setOnRefreshListener(this);
mAdapter = new FriendRequestAdapter(getActivity(), friendRequests);
mListView.setAdapter(mAdapter);
mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
int topRowVerticalPosition =
(view == null || view.getChildCount() == 0) ?
0 : view.getChildAt(0).getTop();
swipeRefreshLayout.setEnabled(firstVisibleItem == 0 && topRowVerticalPosition >= 0);
Log.d(TAG, "SwipeRefresh: " + String.valueOf(firstVisibleItem == 0 && topRowVerticalPosition >= 0));
}
});
loadRequests();
return view;
}
private void loadRequests() {
// nh = new NotificationHandler(getActivity());
swipeRefreshLayout.setRefreshing(true);
Log.d(TAG, "loading requests init");
HashMap<String, Integer> params = new HashMap<>();
params.put("profile_id", Util.getCurrentProfileID(c));
final String uniqueID = Util.getCurrentProfileID(c) + String.valueOf(System.currentTimeMillis() / 1000 / 1200);
new ApiRequest(Util.URL_GET_FRIEND_REQUESTS, params, new AjaxCallback<String>() {
#Override
public void callback(String url, String result, AjaxStatus status) {
super.callback(url, result, status);
ApiResponse apiResponse = new ApiResponse(url, result, uniqueID);
Log.d(TAG, "Friend Requests Response: " + result);
if (apiResponse.isSuccessful()) {
JSONArray jsonArray = apiResponse.getDataJSONArray();
try {
for (int i = 0; i < jsonArray.length(); i++) {
friendRequests.add(new FriendRequest(jsonArray.getJSONObject(i)));
}
mAdapter.notifyDataSetChanged();
} catch (JSONException e) {
e.printStackTrace();
}
mListView.setVisibility(View.VISIBLE);
} else if (apiResponse.getErrorMessage().equals("request_not_found")) {
noRequestsText.setVisibility(View.VISIBLE);
}
swipeRefreshLayout.setRefreshing(true);
}
}).setUniqueID(uniqueID).execute();
}
#Override
public void onRefresh() {
loadRequests();
}
private void acceptRequest(final int position, final View rootView) {
if (isProcessing) {
CustomToast.makeToast(getActivity(), CustomToast.TYPE_ALERT, getString(R.string.please_wait), CustomToast.LENGTH_SHORT);
return;
}
rootView.findViewById(R.id.loading).setVisibility(View.VISIBLE);
rootView.findViewById(R.id.acceptBtn).setVisibility(View.GONE);
rootView.findViewById(R.id.denyBtn).setVisibility(View.GONE);
isProcessing = true;
Log.d("FriendRequest", "accepting:" + position);
FriendRequest request = friendRequests.get(position);
HashMap<String, Integer> params = new HashMap<>();
params.put("request_id", request.getRequestID());
params.put("profile_id", ProfilesSingleton.getInstance().getCurrentProfile().getProfileID());
new ApiRequest(Util.URL_ACCEPT_REQUEST, params, new AjaxCallback<String>() {
#Override
public void callback(String url, String object, AjaxStatus status) {
super.callback(url, object, status);
ApiResponse apiResponse = new ApiResponse(object);
if (apiResponse.isSuccessful()) {
friendRequests.remove(position);
CustomToast.makeToast(getActivity(), CustomToast.TYPE_DEFAULT,
getString(R.string.you_are_now_friends_with) + " " + friendRequests.get(position).getFullName(),
CustomToast.LENGTH_SHORT);
mAdapter.notifyDataSetChanged();
}else {
rootView.findViewById(R.id.loading).setVisibility(View.GONE);
rootView.findViewById(R.id.acceptBtn).setVisibility(View.VISIBLE);
rootView.findViewById(R.id.denyBtn).setVisibility(View.VISIBLE);
}
isProcessing = false;
}
}).execute();
}
private void denyRequest(final int position, final View rootView) {
if (isProcessing) {
CustomToast.makeToast(getActivity(), CustomToast.TYPE_ALERT, getString(R.string.please_wait), CustomToast.LENGTH_SHORT);
return;
}
rootView.findViewById(R.id.loading).setVisibility(View.VISIBLE);
rootView.findViewById(R.id.acceptBtn).setVisibility(View.GONE);
rootView.findViewById(R.id.denyBtn).setVisibility(View.GONE);
Log.d("FriendRequest", "denying:" + position);
FriendRequest request = friendRequests.get(position);
HashMap<String, Integer> params = new HashMap<>();
params.put("request_id", request.getRequestID());
params.put("profile_id", ProfilesSingleton.getInstance().getCurrentProfile().getProfileID());
new ApiRequest(Util.URL_DENY_REQUEST, params, new AjaxCallback<String>() {
#Override
public void callback(String url, String object, AjaxStatus status) {
super.callback(url, object, status);
ApiResponse apiResponse = new ApiResponse(object);
if (apiResponse.isSuccessful()) {
friendRequests.remove(position);
mAdapter.notifyDataSetChanged();
}else {
rootView.findViewById(R.id.loading).setVisibility(View.GONE);
rootView.findViewById(R.id.acceptBtn).setVisibility(View.VISIBLE);
rootView.findViewById(R.id.denyBtn).setVisibility(View.VISIBLE);
}
}
}).execute();
}
public class FriendRequestAdapter extends ArrayAdapter<FriendRequest> {
public FriendRequestAdapter(Context context, ArrayList<FriendRequest> objects) {
super(context, 0, objects);
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View rootView = convertView;
final ViewHolder holder;
final FriendRequest friendRequest = getItem(position);
if (rootView == null) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
rootView = inflater.inflate(R.layout.friend_request_item, parent, false);
holder = new ViewHolder();
holder.profilePhoto = (RoundedImageView) rootView.findViewById(R.id.profilePhoto);
holder.fullName = (TextView) rootView.findViewById(R.id.fullName);
holder.acceptBtn = (ImageView) rootView.findViewById(R.id.acceptBtn);
holder.denyBtn = (ImageView) rootView.findViewById(R.id.denyBtn);
holder.loading = (ProgressBar) rootView.findViewById(R.id.loading);
rootView.setTag(holder);
} else {
holder = (ViewHolder) rootView.getTag();
}
holder.fullName.setText(friendRequest.getFullName());
if (friendRequest.getFullPhotoPath().equals("")) {
ImageUtil.replaceWithInitialsView(getContext(), holder.profilePhoto, friendRequest.getInitials());
} else {
Util.aQuery.id(holder.profilePhoto).image(friendRequest.getFullPhotoPath(), false, true, 50, R.drawable.avatar_profile, null, AQuery.FADE_IN);
}
final View finalRootView = rootView;
holder.acceptBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
acceptRequest(position, finalRootView);
}
});
holder.denyBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
denyRequest(position, finalRootView);
}
});
return rootView;
}
public class ViewHolder {
RoundedImageView profilePhoto;
TextView fullName;
ImageView acceptBtn, denyBtn;
ProgressBar loading;
}
}
}
Add a field in your FriendRequest class that saves the current state of the progress bar. based on it set the visibility of the progress bar.
The same view row has been sent to another row. in your getView method you must always set the progress bar visibility based on its status.
Code Sample:
final View finalRootView = rootView;
if (friendRequest.acceptingRequestInProgress())
holder.loading.setVisibility(View.Visibile);
else
holder.loading.setVisibility(View.Gone);
holder.acceptBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
friendRequest.setAcceptingInProgress(true);
acceptRequest(position, finalRootView);
}
});
holder.denyBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
denyRequest(position, finalRootView);
}
});
Another place to modify:
if (apiResponse.isSuccessful()) {
friendRequest.setAcceptingInProgress(false);
friendRequests.remove(position);
mAdapter.notifyDataSetChanged();
}
Note: this is also handles the case when the user scrolls the list
view and the row view in progress is no longer visible. this will
hands the view to another row. But since we check the row state the
progress bar will be stopped. and when user scrolls back to the row
view in progress and hands it a reusable view the progress bar will be
visible again if accepting is still in progress.
Views are getting reused by the ListView and in the getView() method you are not cleaning up the reused view, that's why the progress bar will become visible for an item that shouldn't display it.
Similarly if an item would be removed some items with progress bars visible would loose their progress bar, handing them over to an item that didn't need it.
In getView(), after initializing the holder, you should check if progress bar is necessary.
Start with storing progress bar values at the beginning:
private ArrayList<Integer> progresses = new ArrayList<Integer>();
Update these values every time the list changes (when list changes in loadRequests and when value changes not sure where).
And in getView()
if (progresses.get(position) == 100) {
holder.loading.setVisibility(View.GONE);
} else {
holder.loading.setVisibility(View.VISIBLE);
holder.loading.setProgress(progresses.get(position));
}
The problem is due to visibility of progressbar is VISIBLE default so in getView() after you call notifyDataSetChanged(), the progressbar becomes visible to row position (i - 1).
holder.loading = (ProgressBar) rootView.findViewById(R.id.loading);
holder.loading.setVisibility(View.GONE);
Set progressbar visibility to GONE in getView() and this problem will not come