5
\$\begingroup\$

I am working in project that uses a Tablayout inside fragment. I have three tabs that fetch data from web service. This part of the app shows questions.We have three categories: one for recent, the second for unanswered, and third for all questions view.

Here is my situation:

The web developer designed me a web service to return a question item. They all share the same structure, but the data changes according to requirement.

I have some questions:

  1. Should I create three fragments, or pass constant around to distinguish between fragment type as I use this constant to retrieve data from web?

  2. Should I pass fragmentmanger or childfragmentmanger to viewpageradapter, notice this tab's inside a fragment.

ViewPagerAdapter adapter = new ViewPagerAdapter(getChildFragmentManager());

This is the fragment class, any tips on how to improve it would be appreciated.

public class Questions_Fragment extends Fragment {
 private TabLayout mTablayout;
 private ViewPager mViewpager;
 public static Questions_Fragment newInstance() {
 Questions_Fragment fragment = new Questions_Fragment();
 return fragment;
 }
 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container,
 Bundle savedInstanceState) {
 View v = inflater.inflate(R.layout.questions_layout, null);
 mViewpager = (ViewPager) v.findViewById(R.id.viewPager);
 setupViewPager(mViewpager);
 mTablayout = (TabLayout) v.findViewById(R.id.tabs);
 mTablayout.setupWithViewPager(mViewpager);
 return v;
 }
 private void setupViewPager(ViewPager mViewpager) {
 ViewPagerAdapter adapter = new ViewPagerAdapter(getChildFragmentManager());
 adapter.addFrag( QuestionsFragModel.newInstance(VolleyRequestHandler.RECENT_INT) , getResources().getString(R.string.newest));
 adapter.addFrag( QuestionsFragModel.newInstance(VolleyRequestHandler.UNANSWER_INT) , getResources().getString(R.string.notanswered));
 adapter.addFrag( QuestionsFragModel.newInstance(VolleyRequestHandler.ALLPOSTS_INT) , getResources().getString(R.string.allposts));
 mViewpager.setAdapter(adapter);
 }

I have only three tabs, should I use FragmentStatePagerAdapter or FragmentPagerAdapter.

I read from this discussion and documentation that FragmentStatePagerAdapter stores all the fragments in memory, my fragments contain a little complex view card view with images and many textviews, that I show them and hide, according to each question.

  1. In my case, would it be better to use FragmentStatePagerAdapter or FragmentPagerAdapter?
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
 private List<Fragment> mFragmentList = new ArrayList<>();
 private List<String> mFragmentTitleList= new ArrayList<>();
 public ViewPagerAdapter(FragmentManager fm) {
 super(fm);
 }
 @Override
 public Fragment getItem(int position) {
 return mFragmentList.get(position);
 }
 @Override
 public int getCount() {
 return mFragmentList.size();
 }
 public void addFrag(Fragment fra , String title){
 mFragmentList.add(fra);
 mFragmentTitleList.add(title);
 }
 @Override
 public CharSequence getPageTitle(int position) {
 return mFragmentTitleList.get(position);
 }
}

My question view here is the fragment handler:

Should I fetch data from web each time fragment created by this method getQuestionsPosts() according to passed constant, then create textview to reload data from web in case it fails.

  1. Why does the passed constant give the wrong number only in middle tab sometimes?

  2. I want to clear and reload data each time fragment created, is this good practice or I should load data and update in user request (Swipe to Refresh pattern)

public class QuestionsFragModel extends Fragment implements OnClickListener {
 private RecyclerView Ques_list;
 private ProgressBar list_prog;
 private ListViewAdapter adapter;
 private List<QuestionItem> Questions = new ArrayList<>();
 private TextView reload;
 private VolleyRequestHandler _VolleyRequestHandler;
 private int CONST_TYPE = 0;
 public static final String PASSED_INT = "passed_number";
 private CoordinatorLayout _coordiatelayout;
 static QuestionsFragModel newInstance(int type) {
 QuestionsFragModel f = new QuestionsFragModel();
 Bundle bundle = new Bundle();
 bundle.putInt(PASSED_INT , type);
 f.setArguments(bundle);
 return f;
 }
 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container,
 Bundle savedInstanceState) {
 View v = inflater.inflate(R.layout.question_layout, container, false);
 CONST_TYPE = getArguments() != null ? getArguments().getInt(PASSED_INT) : 7;
 _VolleyRequestHandler = new VolleyRequestHandler(getActivity());
 _coordiatelayout = (CoordinatorLayout) v.findViewById(R.id.coordiatelayout);
 Ques_list = (RecyclerView) v.findViewById(R.id.questionlist);
 Ques_list.setLayoutManager(new LinearLayoutManager(getActivity()));
 adapter = new ListViewAdapter(getActivity(), Questions);
 Ques_list.setAdapter(adapter);
 list_prog = (ProgressBar) v.findViewById(R.id.progressbar);
 reload = (TextView) v.findViewById(R.id.reload);
 getQuestationsPosts();
 reload.setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View position) {
 getQuestationsPosts();
 }
 });
 final FloatingActionButton floatingView = (FloatingActionButton) v.findViewById(R.id.FloatingView);
 if (floatingView != null) {
 floatingView.setOnClickListener(this);
 }
 return v;
 }
 public void getQuestationsPosts() {
 API api = new API(getActivity());
 if (api.isNetworkConnected()) {
 list_prog.setVisibility(View.VISIBLE);
 reload.setVisibility(View.GONE);
 FetchQuestationsFromWeb();
 } else {
 Snackbar.make(_coordiatelayout, getResources().getString(R.string.nointernet), Snackbar.LENGTH_LONG).show();
 Ques_list.setVisibility(View.GONE);
 reload.setVisibility(View.VISIBLE);
 }
 }
 private void onSuccessResponse(Object response){
 list_prog.setVisibility(View.GONE);
 reload.setVisibility(View.GONE);
 Ques_list.setVisibility(View.VISIBLE);
 if(Questions != null){
 Questions.clear();
 }
 Questions = (List < QuestionItem>) response;
 adapter = new ListViewAdapter(getActivity() ,Questions);
 Ques_list.setAdapter(adapter);
 }
 private void onErrorResponse(String error){
 list_prog.setVisibility(View.GONE);
 reload.setVisibility(View.VISIBLE);
 Snackbar.make(_coordiatelayout , error , Snackbar.LENGTH_LONG).show();
 }
 private void FetchQuestationsFromWeb() {
 _VolleyRequestHandler.HandleRequests(Request.Method.POST , CONST_TYPE, null, new VolleyResponseCallBack() {
 @Override
 public void RequestSuccess(Object response) {
 onSuccessResponse(response);
 }
 @Override
 public void RequestFailed(String error) {
 onErrorResponse(error);
 }
 });
 }
 @Override
 public void onClick(View arg0) {
 startActivity(new Intent(getActivity(), Add_Question.class));
 }
}

The List adapter is where all fragments get their view.

I am new to recycling views, so I am not sure what the best practice relating the Typeface and animation on it. I also have some questions about this as well:

  1. What is the best location and method to use TypeFace, Animation?

  2. Why do some items show different behaviour as I mentioned?

public class ListViewAdapter extends RecyclerView.Adapter<ListViewAdapter.ViewHolder> {
 private Context _Context;
 private List<QuestionItem> Questions = new ArrayList<>();
 private API api;
 private int num;
 private int lastPosition = -1;
 public static final String BASE_POST_URl = "url....";
 public ListViewAdapter(Context context, List<QuestionItem> Questions) {
 this._Context = context;
 this.Questions = Questions;
 api = new API(context);
 }
 public ListViewAdapter(Context context, List<QuestionItem> Questions,
 int num) {
 this._Context = context;
 this.Questions = Questions;
 this.num = num;
 api = new API(context);
 }
 @Override
 public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
 LayoutInflater inflater = LayoutInflater.from(_Context);
 View itemView = inflater.inflate(R.layout.question_row, parent, false);
 return new ViewHolder(itemView);
 }
 @Override
 public void onBindViewHolder(final ViewHolder holder, final int position) {
 Typeface tf = Typeface.createFromAsset(_Context.getAssets(),
 "fonts/GE_SS_Two_Bold.otf");
 Typeface tfreg = Typeface.createFromAsset(_Context.getAssets(),
 "fonts/GE_SS_Two_Light.otf");
 ImageLoader _ImageLoader = MySingleton.getInstance(_Context).getmImageLoader();
 if (Questions.get(position).user.userimageURL != null) {
 if (!Questions.get(position).user.getUserimageURL().isEmpty()) {
 //holder.userimageprog.setVisibility(View.VISIBLE);
 holder.imageView.setImageUrl(Profile_Fragment.BASE_URL + Questions.get(position).user.getUserimageURL(), _ImageLoader);
 }
 }
 if(Questions.get(position).Que_image_url != null){
 if (!Questions.get(position).getQue_image_url().isEmpty()) {
 holder._FrameLayout.setVisibility(View.VISIBLE);
 holder.post_img.setVisibility(View.VISIBLE);
 //holder.post_img_pro.setVisibility(View.VISIBLE);
 holder.post_img.setImageUrl(BASE_POST_URl + Questions.get(position).getQue_image_url(), _ImageLoader);
 }
 }
 holder.imageView.setDefaultImageResId(R.drawable.profile);
 holder.username.setTypeface(tf);
 holder.desc.setTypeface(tfreg);
 holder.Date.setTypeface(tfreg);
 holder.AnswersCount.setTypeface(tfreg);
 if(Questions.get(position).user.username != null){
 holder.username.setText(Questions.get(position).user.username);
 }
 if(Questions.get(position).Que_Content != null){
 holder.desc.setText(Questions.get(position).Que_Content);
 }
 if(Questions.get(position).category != null){
 holder.Category.setText(Questions.get(position).category);
 }
 if(Questions.get(position).Que_Date != null){
 holder.Date.setText(Questions.get(position).Que_Date);
 }
 if (!Questions.get(position).getComment().isEmpty()) {
 holder.arrow.setVisibility(View.VISIBLE);
 holder.AnswersCount.setVisibility(View.VISIBLE);
 holder.AnswersCount.setText(_Context.getResources().getString(R.string.youhaveanswer));
 }
 holder.arrow.setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View v) {
 Intent intent = new Intent (_Context , ViewAnswers.class);
 intent.putExtra("passedobject", (Parcelable) Questions.get(position));
 _Context.startActivity(intent);
 }
 });
// Animation animation = null;
// animation = AnimationUtils.loadAnimation(_Context,
// R.anim.up_from_bottom);
// animation.setDuration(500);
// view.setAnimation(animation);
// animation = null;
//
// Animation animation = AnimationUtils.loadAnimation(_Context,
// (pos > lastPosition) ? R.anim.up_from_bottom
// : R.anim.down_from_top);
// view.startAnimation(animation);
// lastPosition = pos;
 }
 @Override
 public long getItemId(int position) {
 return position;
 }
 @Override
 public int getItemCount() {
 return Questions.size();
 }
 public class ViewHolder extends RecyclerView.ViewHolder {
 protected NetworkImageView imageView, post_img;
 protected TextView desc, Category, username, Date, AnswersCount;
 protected ProgressBar userimageprog, post_img_pro;
 protected ImageView arrow;
 protected FrameLayout _FrameLayout;
 public ViewHolder(View itemView) {
 super(itemView);
 imageView = (NetworkImageView) itemView.findViewById(R.id.ques_user_img);
 desc = (TextView) itemView.findViewById(R.id.ques_content);
 Category = (TextView) itemView.findViewById(R.id.category);
 post_img = (NetworkImageView) itemView.findViewById(R.id.post_img);
 userimageprog = (ProgressBar) itemView.findViewById(R.id.userimgae_prog);
 post_img_pro = (ProgressBar) itemView.findViewById(R.id.post_prog);
 username = (TextView) itemView.findViewById(R.id.username_ques);
 Date = (TextView) itemView.findViewById(R.id.date);
 AnswersCount = (TextView) itemView.findViewById(R.id.answers_con);
 arrow = (ImageView) itemView.findViewById(R.id.imageView1);
 _FrameLayout = (FrameLayout)itemView.findViewById(R.id.frameLayout2);
 }
 }
}

question row view

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:cardview="http://schemas.android.com/apk/res-auto"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:layout_gravity="center_horizontal"
 android:layout_marginLeft="8dp"
 android:layout_marginRight="8dp"
 cardview:cardBackgroundColor="@android:color/white"
 cardview:cardCornerRadius="5dp"
 cardview:cardElevation="2dp">
 <LinearLayout
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:layout_margin="10dp"
 android:orientation="vertical">
 <TextView
 android:id="@+id/category"
 android:layout_width="match_parent"
 android:layout_height="0dp"
 android:layout_weight="1"
 android:background="@color/blue"
 android:padding="10dp"
 android:text="TextView"
 android:textColor="@android:color/white" />
 <LinearLayout
 android:layout_width="match_parent"
 android:layout_height="0dp"
 android:layout_weight="1"
 android:orientation="horizontal">
 <FrameLayout
 android:id="@+id/frameLayout1"
 android:layout_width="60dp"
 android:layout_height="wrap_content"
 android:layout_gravity="center"
 android:layout_marginBottom="10dp"
 android:layout_marginLeft="4dp"
 android:layout_marginRight="4dp"
 android:layout_marginTop="10dp">
 <ProgressBar
 android:id="@+id/userimgae_prog"
 style="?android:attr/progressBarStyleSmall"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_gravity="center"
 android:visibility="gone" />
 <com.android.volley.toolbox.NetworkImageView
 android:id="@+id/ques_user_img"
 android:layout_width="60dp"
 android:layout_height="60dp"
 />
 </FrameLayout>
 <LinearLayout
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_gravity="center"
 android:orientation="vertical">
 <TextView
 android:id="@+id/username_ques"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_marginLeft="10dp"
 android:text="Asmaa Samir"
 android:textColor="@android:color/black"
 android:textStyle="bold" />
 <TextView
 android:id="@+id/date"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_marginLeft="10dp"
 android:layout_marginTop="3dp"
 android:text="2 days ago"
 android:textColor="@android:color/black" />
 </LinearLayout>
 </LinearLayout>
 <LinearLayout
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_gravity="center"
 android:layout_weight="1"
 android:orientation="vertical">
 <TextView
 android:id="@+id/ques_content"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_gravity="center"
 android:layout_margin="4dp"
 android:text="ماهى اسباب ضعف الرؤيه أمام الحاسوب؟"
 android:textColor="@android:color/black"
 android:textStyle="bold" />
 </LinearLayout>
 <FrameLayout
 android:id="@+id/frameLayout2"
 android:layout_width="60dp"
 android:layout_height="60dp"
 android:layout_gravity="center"
 android:layout_marginBottom="10dp"
 android:layout_marginLeft="4dp"
 android:layout_marginRight="4dp"
 android:layout_marginTop="10dp"
 android:visibility="gone">
 <ProgressBar
 android:id="@+id/post_prog"
 style="?android:attr/progressBarStyleSmall"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_gravity="center"
 android:visibility="gone" />
 <com.android.volley.toolbox.NetworkImageView
 android:id="@+id/post_img"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_gravity="center"
 android:scaleType="centerCrop"
 android:visibility="visible" />
 </FrameLayout>
 <LinearLayout
 android:layout_width="wrap_content"
 android:layout_height="0dp"
 android:layout_gravity="right"
 android:layout_weight="1"
 android:orientation="horizontal">
 <TextView
 android:id="@+id/answers_con"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_margin="10dp"
 android:layout_weight="1"
 android:text="32 إجابه"
 android:textColor="@android:color/black"
 android:visibility="gone" />
 <ImageView
 android:id="@+id/imageView1"
 android:layout_width="40dp"
 android:layout_height="40dp"
 android:layout_gravity="center"
 android:src="@drawable/qustion_8"
 android:visibility="gone" />
 </LinearLayout>
 </LinearLayout>
</android.support.v7.widget.CardView>

Sorry for my long question but I appreciate each one help me.

asked Dec 17, 2015 at 11:52
\$\endgroup\$
1

1 Answer 1

1
\$\begingroup\$

I am glad to answer my question but I am looking for other options

  1. Should I create three fragments or pass a constant to distinguish between fragment type as I use this constant to retrieve data from web?

I think it's recommended to decrease number of classes as much as possible, if they do the same function, and this what occur in my case.

  1. Should I pass fragmentmanager or childfragmentmanager to viewpageradapter, notice this tab's inside a fragment.

According to documentation and discussion: I figure there differences between FragmentManager and ChildFragmentManager, FragmentManager for interacting fragment with activity , ChildFragmentManager for interacting between fragment inside one fragment, in my case I use ViewPager inside fragment then prefer ChildFragmentManger.

  1. In my case, is it better to use FragmentStatePagerAdapter or FragmentPagerAdapter?

After long researches in this topic [1] [2] , I can sum important difference between them FragmentStatePagerAdapter works well with heavy fragments as it store just states of fragment and completely removes fragment in transaction check source code line 139: mCurTransaction.remove(fragment).

On the other hand FragmentPagerAdapter pushes all fragments into memory this mean keep fragment in transaction in back stack it just detached them check source code line 117 mCurTransaction.detach((Fragment)object), so in my case as I use images I prefer FragmentStatePagerAdapter.

Notice if you user FragmentStatePagerAdapter you must check saved bundle and return passed data in case you pass any , in my case I should return passed int , bundle carry the same name used in your activity.

if (savedInstanceState != null) {
 CONST_TYPE = getArguments().getInt(PASSED_INT);
 } else {
 CONST_TYPE = getArguments() != null ? getArguments().getInt(PASSED_INT) : 0;
 }

this Answer Q4

Q5 I clear list and reload data each time fragment created , is this good practice or I should load data and update in user request (Swipe to Refresh pattern )

A5 I am not sure this time but I prefer SwipeRefreshLayout as user can refresh any time he want this quick tutorial for it .

Q6 what is the best place and way to use TypeFace , Animation ?

waiting someone answer it ....

Q7 why some items show different behaviour as I mention ?

A7 its the most important answer to me , why adapter give wrong view , it cause of using if statement , when using if in adapter you must use else

ex showing question image

 if(Questions.get(position).Que_image_url != null){
 if (!Questions.get(position).getQue_image_url().isEmpty()) {
 holder._FrameLayout.setVisibility(View.VISIBLE);
 holder.post_img.setVisibility(View.VISIBLE);
 holder.post_img.setImageUrl(BASE_POST_URl + Questions.get(position).getQue_image_url(), _ImageLoader);
 }else{
 holder._FrameLayout.setVisibility(View.GONE);
 holder.post_img.setVisibility(View.GONE); 
 }
 }else{
 // extra code 
 }
answered Jan 5, 2016 at 9:45
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.