I´m using in my Android (4.0+) app fragment (in Activity) with Tab bar.
I want to create Espresso test but if I create main Activity and open the fragment. I get this Exception:
java.lang.IllegalStateException: ViewPager does not have adapter instance.
at com.astuetz.PagerSlidingTabStrip.setViewPager(PagerSlidingTabStrip.java:177)
at cz.villamemories.detoxme.staticcontent.StaticContentFragment.onCreateView(StaticContentFragment.java:197)
My code in fragment:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mViewPagerAdapter = new StaticContentPagerAdapter(
this.getChildFragmentManager(), mItemsList, categories);
mPager.setAdapter(mViewPagerAdapter);
mTabs.setViewPager(mPager); //line 197
Do you have some tip where can be a problem? What is wrong?
I was also facing the issue with ViewPager in fragment. This problem occurs me because of my viewpager has a multiple root elements.
#RunWith(JUnit4.class)
public class FragmentTest {
private static final String TAG = "FragmentTest";
#Rule
public ActivityTestRule<MainActivity> mActivity = new ActivityTestRule<MainActivity>(MainActivity.class);
#Test
public void checkTabSwiping() {
onView(nthChildOf(withId(R.id.main_content), 5)).check(matches(withId(R.id.homecontentgrouppager)));
}
public static Matcher<View> firstChildOf(final Matcher<View> parentMatcher) {
return new TypeSafeMatcher<View>() {
#Override
public void describeTo(Description description) {
description.appendText("with first child view of type parentMatcher");
}
#Override
public boolean matchesSafely(View view) {
if (!(view.getParent() instanceof ViewGroup)) {
return parentMatcher.matches(view.getParent());
}
ViewGroup group = (ViewGroup) view.getParent();
return parentMatcher.matches(view.getParent()) && group.getChildAt(0).equals(view);
}
};
}
public static Matcher<View> nthChildOf(final Matcher<View> parentMatcher,
final int childPosition){
return new TypeSafeMatcher<View>() {
#Override
public void describeTo(Description description) {
description.appendText("with " + childPosition + " child view of type parentMatcher");
}
#Override
public boolean matchesSafely(View view) {
if (!(view.getParent() instanceof ViewGroup)) {
return parentMatcher.matches(view.getParent());
}
ViewGroup group = (ViewGroup) view.getParent();
return parentMatcher.matches(view.getParent()) && view.equals(group.getChildAt(childPosition));
}
};
}
}
and this is my homefragment.xml file
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:background="#color/black"
android:orientation="vertical">
<android.support.v4.view.ViewPager
android:id="#+id/promotionalviewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"></android.support.v4.view.ViewPager>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="#dimen/size_5"
android:gravity="center_horizontal">
<LinearLayout
android:id="#+id/viewPagerCountDots"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:gravity="center_horizontal"
android:orientation="horizontal" />
</RelativeLayout>
I hope it may help you to create a test case in Expresso Framework.
Related
I have 2 recycler views and a view pager in a fragment.
Everything else works fine but both recycler view items are showing a random mark on the upper left corner of every items. And same thing is happening for the view pager items.
This fragment is in a fragment activity and view pager is using pager adapter. And I am using Picasso library to load images on the items and also using network policy to cache the images in disk.
recycler view items appearing like this
view pager items appearing like this
Recycler View adapter
public class CourseListAdapter extends RecyclerView.Adapter<CourseListAdapter.CourseListViewHolder> {
public static final int HOME_PAGE = 1;
public static final int DISPLAY_COURSE = 2;
private Picasso mPicasso;
private List<DisplayCourse> courseList;
private static final String TAG = "CourseListAdapter";
private OnItemClickListener mListener;
public interface OnItemClickListener {
void onItemClick(int position, View view);
}
private String mSender;
public void setOnItemClickListener(OnItemClickListener listener) {
mListener = listener;
}
public CourseListAdapter(List<DisplayCourse> courseList, String sender) {
this.courseList = courseList;
this.mSender = sender;
mPicasso = Picasso.get();
}
#NonNull
#Override
public CourseListViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
switch (viewType) {
case 1:
View view1 = inflater.inflate(R.layout.recom_course_home_layout, parent, false);
return new CourseListViewHolder(view1, mListener);
case 2:
View view2 = inflater.inflate(R.layout.display_course_layout, parent, false);
return new CourseListViewHolder(view2, mListener);
default:
View view3 = inflater.inflate(R.layout.section_video_item_layout, parent, false);
return new CourseListViewHolder(view3, mListener);
}
}
#Override
public void onBindViewHolder(#NonNull CourseListViewHolder holder, int position) {
holder.title.setText(courseList.get(position).getCourseTitle());
mPicasso.load(courseList.get(position).getThumbnailURL())
.networkPolicy(NetworkPolicy.OFFLINE)
.into(holder.thumbnail, new Callback() {
#Override
public void onSuccess() {
}
#Override
public void onError(Exception e) {
mPicasso.load(courseList.get(position).getThumbnailURL())
.error(R.drawable.ofklogo)
.into(holder.thumbnail, new Callback() {
#Override
public void onSuccess() {
}
#Override
public void onError(Exception e) {
}
});
}
});
}
#Override
public int getItemCount() {
return courseList.size();
}
public static class CourseListViewHolder extends RecyclerView.ViewHolder {
ImageView thumbnail;
TextView title;
public CourseListViewHolder(#NonNull View itemView, final OnItemClickListener listener) {
super(itemView);
title = itemView.findViewById(R.id.courseTitle);
thumbnail = itemView.findViewById(R.id.courseThumbNailImageView);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int position = getAdapterPosition();
if (listener != null) {
if (position != RecyclerView.NO_POSITION) {
listener.onItemClick(position, view);
}
}
}
});
}
}
#Override
public int getItemViewType(int position) {
if (mSender.equals("home_page")) {
return HOME_PAGE;
} else if (mSender.equals("displayCourse")) {
return DISPLAY_COURSE;
}
return -1;
}
}
View pager adapter
public class VideoSliderAdapter extends PagerAdapter {
private boolean doNotifyDataSetChangedOnce = false;
private static final String TAG = "VideoSliderAdapter";
private YouTubePlayerView youTubePlayerView;
private View gradientView;
private ImageView thumbNail;
private LinearLayout layout;
private Picasso picasso;
private List<Video> videoList;
private Context mContext;
private Lifecycle mLifeCycle;
public VideoSliderAdapter(List<Video> videoList, Context context, Lifecycle lifecycle) {
this.videoList = videoList;
this.mContext = context;
this.mLifeCycle = lifecycle;
doNotifyDataSetChangedOnce = true;
picasso = Picasso.get();
}
#Override
public int getCount() {
if (doNotifyDataSetChangedOnce) {
doNotifyDataSetChangedOnce = false;
notifyDataSetChanged();
}
return videoList.size();
}
#Override
public int getItemPosition(#NonNull Object object) {
return POSITION_NONE;
}
#Override
public boolean isViewFromObject(#NonNull View view, #NonNull Object object) {
return (view == (CardView) object);
}
#NonNull
#Override
public Object instantiateItem(#NonNull ViewGroup container, int position) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.video_paly_layout, container, false);
TextView title = view.findViewById(R.id.videoTitle);
title.setText(videoList.get(position).getVideoTitle());
gradientView = view.findViewById(R.id.gradientView);
thumbNail = view.findViewById(R.id.videoThumbNail);
picasso.load(videoList.get(position).getVideoThumbNail())
.networkPolicy(NetworkPolicy.OFFLINE)
.into(thumbNail, new Callback() {
#Override
public void onSuccess() {
}
#Override
public void onError(Exception e) {
picasso.load(videoList.get(position).getVideoThumbNail())
.error(R.drawable.ofklogo)
.into(thumbNail, new Callback() {
#Override
public void onSuccess() {
}
#Override
public void onError(Exception e) {
}
});
}
});
layout = view.findViewById(R.id.videoPlayLayout);
youTubePlayerView = view.findViewById(R.id.youtube_player_view);
mLifeCycle.addObserver(youTubePlayerView);
new AddListener(youTubePlayerView, position).execute();
container.addView(view);
return view;
}
#Override
public void destroyItem(#NonNull ViewGroup container, int position, #NonNull Object object) {
container.removeView((CardView) object);
}
Recycler view holder layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="150dp"
android:layout_height="200dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
app:cardCornerRadius="8dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/courseThumbNailImageView"
android:layout_width="match_parent"
android:layout_height="130dp"
android:layout_alignParentTop="true"
android:scaleType="fitXY"
android:src="#drawable/art_thumb" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/courseThumbNailImageView">
<TextView
android:id="#+id/courseTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:maxLines="2"
android:text="Course title"
android:textAlignment="center"
android:textColor="#android:color/black"
android:textStyle="bold" />
</RelativeLayout>
</RelativeLayout>
</androidx.cardview.widget.CardView>
view pager layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView 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="200dp"
app:cardCornerRadius="8dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView
android:id="#+id/youtube_player_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:autoPlay="false" />
<ImageView
android:id="#+id/videoThumbNail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY" />
<View
android:id="#+id/gradientView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/gradient_drawable" />
<LinearLayout
android:id="#+id/videoPlayLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="16dp">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="8dp"
android:src="#drawable/play_button" />
<TextView
android:id="#+id/videoTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="2"
android:text="Course title"
android:textColor="#android:color/white"
android:textStyle="bold" />
</LinearLayout>
</RelativeLayout>
</androidx.cardview.widget.CardView>
When loading image using Picasso use: setIndicatorsEnabled(false)
picasso.load(videoList.get(position).getVideoThumbNail())
.networkPolicy(NetworkPolicy.OFFLINE)
.setIndicatorsEnabled(false)
.into(...);
The colors indicate this:
Green: Image is fetched from memory
Blue: Image is fetched from disk
Red: Image is fetched from network
I am creating Android app, using room database.
I have two tables DogsTable:
#PrimaryKey(autoGenerate = true)
int dog_id;
String dogName;
and CatsTable (both tables have constructor and getter methods ):
#PrimaryKey(autoGenerate = true)
int cat_id;
String catName;
1- How to display in one RecyclerView two different object type
ArrayList<DogsTable> dog_list;
ArrayList<CatsTable> cat_list;
I am getting the values of dog_list and cat_list from ViewModel Query as show in MainActivity.class.
2- How to fix getItemCount() method? I don't know how to return two different object cat_list.size(); and dog_list.size();
3- Also in onBindViewHolder() method I don`t know how to get cat_list values to display them in UI?
4- Another problem is in swapToDelete() Method in MainActivity.class, I can get the dog id to delete it, but I can not get the cat id to delete it, how can I get the cat id ?
5- How can I display (dog1,dog2 , dog3) as show in first image? (i inserted the value manually in the first image just to show how i want to display them )
Existing Output as below:
My code
MainActivity.java
public class MainActivity extends AppCompatActivity implements MainActivityAdapter.ItemClickListener {
MyViewModel viewModel;
MainActivityAdapter adapter;
RecyclerView recyclerView;
LinearLayoutManager layoutManager;
Button btn_addDog, btn_addCat;
EditText et_addDogName, et_addCatName;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
actionButton();
buildRecyclerView();
setUpViewModel_dogs();
swapToDelete_dog();
}
private void initViews() {
et_addDogName = findViewById(R.id.addDogNameET_xml);
et_addCatName = findViewById(R.id.addCatNameET_xml);
}
public void actionButton() {
btn_addDog = findViewById(R.id.AddDog_btn_xml);
btn_addCat = findViewById(R.id.AddCat_btn_xml);
btn_addDog.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
insertDog();
}
});
btn_addCat.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
insertCat();
}
});
}
private void buildRecyclerView() {
recyclerView = findViewById(R.id.recyclerView_id);
adapter = new MainActivityAdapter(this, this);
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
}
// Query
public void setUpViewModel_dogs() {
viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
viewModel.getAllDogs().observe(this, new Observer<List<DogsTable>>() {
#Override
public void onChanged(#Nullable List<DogsTable> dogsTables) {
adapter.setDog_list((ArrayList<DogsTable>) dogsTables);
}
});
}
public void setUpViewModel_cats(){
viewModel.getAllCats().observe(this, new Observer<List<CatsTable>>() {
#Override
public void onChanged(#Nullable List<CatsTable> catsTables) {
adapter.setCat_list((ArrayList<CatsTable>) catsTables);
}
});
}
// Add
public void insertDog() {
String dogName = String.valueOf(et_addDogName.getText()).trim();
DogsTable obj_dog = new DogsTable(dogName);
viewModel.insertDog(obj_dog);
Toast.makeText(this, "Dog Added", Toast.LENGTH_SHORT).show();
}
public void insertCat() {
String catName = String.valueOf(et_addCatName.getText());
CatsTable obj_cat = new CatsTable(catName);
viewModel.insertCat(obj_cat);
Toast.makeText(this, "cat Added", Toast.LENGTH_SHORT).show();
}
// Delete
public void swapToDelete_dog() {
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(final RecyclerView.ViewHolder viewHolder, int direction) {
List<DogsTable> dog_pos = adapter.getDog_list();
viewModel.deleteDog(dog_pos.get(viewHolder.getAdapterPosition()));
}
}
).attachToRecyclerView(recyclerView);
}
public void swapToDelete_cat() {
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int item_id = item.getItemId();
if (item_id == R.id.menu_add) {
Intent in = new Intent(this, Add.class);
startActivity(in);
}
return super.onOptionsItemSelected(item);
}
#Override
public void onItemClickListener(int pet_id) {
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="#+id/addDogNameET_xml"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:hint="add Dog name" />
<Button
android:id="#+id/AddDog_btn_xml"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="add" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="#+id/addCatNameET_xml"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:hint="add Cat name" />
<Button
android:id="#+id/AddCat_btn_xml"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="add" />
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView_id"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="MissingConstraints" />
</LinearLayout>
MainActivityAdapter.java
public class MainActivityAdapter extends RecyclerView.Adapter<MainActivityAdapter.MyViewHolder> {
Context mContext;
ArrayList<DogsTable> dog_list;
ArrayList<CatsTable> cat_list;
ItemClickListener mItemClickListener;
public MainActivityAdapter(Context context , ItemClickListener itemClickListener) {
this.mContext = context;
this.mItemClickListener = itemClickListener;
}
public interface ItemClickListener {
void onItemClickListener(int pet_id);
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(mContext).inflate(R.layout.activity_main_adapter, viewGroup, false);
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
DogsTable dog_pos = dog_list.get(position);
// CatsTable catsTable = cat_list.get(position);
holder.dogName.setText(String.valueOf(dog_pos.getDogName()));
// holder.catName.setText(String.valueOf(catsTable.getCatName()));
}
#Override
public int getItemCount() {
if (dog_list == null ) {
return 0;
} else {
return dog_list.size();
}
}
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener , ItemClickListener {
TextView dogName;
TextView catName;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
dogName = itemView.findViewById(R.id.dogName_xml);
catName = itemView.findViewById(R.id.catName_xml);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
int pet_id = dog_list.get(getAdapterPosition()).getDogs_id();
mItemClickListener.onItemClickListener(pet_id);
}
#Override
public void onItemClickListener(int pet_id) {
int pos = dog_list.get(getAdapterPosition()).getDogs_id();
mItemClickListener.onItemClickListener(pet_id);
}
}
public void setDog_list(ArrayList<DogsTable> dog_list) {
this.dog_list = dog_list;
notifyDataSetChanged();
}
public ArrayList<DogsTable> getDog_list() {
return dog_list;
}
public void setCat_list(ArrayList<CatsTable> cat_list) {
this.cat_list = cat_list;
}
}
activity_main_adapter.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="wrap_content"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Dogs: " />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/dogName_xml"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cats: " />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:id="#+id/catName_xml"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
To support different view types, RecyclerView.Adapter provides a useful method int getItemViewType(int position):
Return the view type of the item at position for the purposes of view recycling.
The default implementation of this method returns 0, making the assumption of a single view type for the adapter. Unlike ListView adapters, types need not be contiguous. Consider using id resources to uniquely identify item view types.
Then, in onCreateViewHolder you can see that a second parameter is int viewType which comes from the method int getItemViewType(int position). Based on that, you can instantiate a ViewHolder you need, e.g. DogViewHolder or CatViewHolder.
But what about storing multiple view models in a single adapter and defining which ViewHolder type should be actually instantiated? Here are two most popular approaches:
Declaring multiple containers for multiple types and defining a custom logic for getItemViewType method, e.g. all odd numbers will go in the dogs' list and even numbers will go in the cats' list (or any other method, but beware that you will have to cope with different lists' sizes and all the view types you need). Also, getItemsCount should be overriden appropriately (return list1.size() + list2.size + ... + listN.size();)
Put all the view models in a single list and perform some kind of attributes checks: either it will be some property or the type itself (not recommended for scalability reasons). Then your code will look like this:
public int getItemViewType(int position) {
CommonParentForUpcasting item = items.get(position);
if (item instanceOf Dog) { // or something like item.type == Animal.CAT
return R.id.holder_dog;
} else {
return R.id.holder_cat;
}
}
If you want to come up with a second solution, this solution should suit you well.
Also, make sure to check this StackOverflow answer.
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.
I have Fragment which have a searchview and viewpager . My viewpager has 3 fragments and each fragment calling adapter . Now to implement searchview , i need to call adapter of visible fragment in view pager .
SlidingTab(Fragment with searchview and ViewPager):
<LinearLayout 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:id="#+id/frame_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.RareMediaCompany.BDTrial.SlidingTab">
<include
android:id="#+id/toolbar1"
layout="#layout/toolbar_job" />
<com.RareMediaCompany.BDTrial.Utils.CustomTabLayout
android:id="#+id/sliding_tabs"
style="#style/CustomTabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#eeeeee"
app:tabIndicatorColor="#f39220"
app:tabIndicatorHeight="3dp"
app:tabMaxWidth="0dp"
app:tabMode="fixed"
app:tabPaddingEnd="0dp"
app:tabPaddingStart="0dp"
app:tabTextAppearance="#android:style/TextAppearance.Widget.TabWidget"
app:tabSelectedTextColor="#808080" />
<LinearLayout
android:id="#+id/linear1"
android:background="#android:color/white"
android:layout_width="match_parent"
android:layout_height="70dp"
android:orientation="horizontal"
android:weightSum="1">
<android.support.v7.widget.SearchView
android:layout_width="300dp"
android:layout_height="45dp"
android:id="#+id/searchView"
android:layout_weight="0.9"
android:layout_marginRight="5dp"
android:layout_gravity="center"
style="#style/CitySearchView"
android:background="#drawable/searchview"
android:layout_marginLeft="10dp"/>
<LinearLayout
android:id="#+id/list_linearlayout"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_weight="0"
android:layout_gravity="center"
android:background="#f39220">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_weight="0.3"
android:src="#drawable/list_icon_white"/>
</LinearLayout>
<LinearLayout
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_gravity="center"
android:layout_weight="0"
android:layout_marginRight="10dp"
android:background="#75aadb">
<ImageView
android:layout_width="20dp"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginRight="2dp"
android:layout_weight="0.3"
android:src="#drawable/mapmarker"/>
</LinearLayout>
</LinearLayout>
<!--android:layout_width="320dp"-->
<!--android:layout_height="wrap_content"-->
<!--android:layout_marginLeft="10dp"-->
<!--android:layout_marginTop="10dp"-->
<!--android:id="#+id/searchview"/>-->
<android.support.v4.view.ViewPager
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#android:color/white" />
</LinearLayout>
SlidingTab.class (Implementing SearchView)
public class SlidingTab extends Fragment {
private static final String TAG = "TabLayout";
private static String POSITION = "POSITION";
private Context context;
private SearchView searchview;
private Toolbar toolbar ;
/*searching/filteration query*/
private SearchView.OnQueryTextListener OnQuerySearchView = new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String arg0) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean onQueryTextChange(String arg0) {
// TODO Auto-generated method stub
// if (searchCheck) {
Log.i("Recycler query", arg0);
// Fragment frag = new PageAdapter(getChildFragmentManager(),context).getItem(viewPager.getCurrentItem());
PageAdapter adapter = ((PageAdapter) viewPager.getAdapter());
Fragment fragment = adapter.getFragment(viewPager.getCurrentItem());
return false;
}
};
public SlidingTab() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.sliding_tab, container, false);
viewPager = (ViewPager) v.findViewById(R.id.view_pager);
viewPager.setOffscreenPageLimit(2);
viewPager.setAdapter(new PageAdapter(getChildFragmentManager(), context));
slidingTab = (TabLayout) v.findViewById(R.id.sliding_tabs);
searchview = (SearchView)v.findViewById(R.id.searchView);
searchview.setOnQueryTextListener(OnQuerySearchView);
return v;
}
PageAdapter.class
public class PageAdapter extends FragmentStatePagerAdapter {
private static final String TAG = "PageAdapter";
final int PAGE_COUNT = 3;
private String tabTitles[] = new String[]{"New", "In Progress", "Completed"};
private Context context;
public PageAdapter(FragmentManager fm, Context context) {
super(fm);
this.context = context;
}
#Override
public Fragment getItem(int position) {
Log.d(TAG, "New Instance Created :" + position);
switch (position) {
case 0:
return new JobFragment();
case 1:
return new InProgressJobFragment();
case 2:
return new CompletedJobFragment();
}
return null;
}
#Override
public CharSequence getPageTitle(int position) {
return tabTitles[position];
}
#Override
public int getCount() {
return PAGE_COUNT;
}
}
Fragment RecyclerView Adapter (Call by each fragment in view pager and have searchview filter method)
public class JobAdapter extends RecyclerView.Adapter<JobAdapter.ViewHolder> {
private static final String TAG = "EMPLOYEE ADAPTER";
private static final int VIEW_NORMAL = 0;
private ArrayList<Info> mDataset;
private ArrayList<Info> filterList;
private Context mAct;
public class ViewHolder extends RecyclerView.ViewHolder {
}
}
public void addApplications(ArrayList<Info> candidates) {
}
public void clearApplications() {
}
public JobAdapter(ArrayList<Info> myDataset, Context context) {
this.mDataset = myDataset;
this.mAct = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.job_card_new, parent, false);
ViewHolder fh = new ViewHolder(v);
return fh;
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
// }
**// *searching/filtration on List*/**
public void filter(String charText) {
filterList.clear();
if (charText.length() == 0) {
if(mDataset != null) {
filterList.addAll(mDataset);
}
} else {
if (mDataset != null){
for (Info wp : mDataset) {
if(wp.jobNumber !=null){
if(Pattern.compile(Pattern.quote(charText), Pattern.CASE_INSENSITIVE).matcher(wp.jobNumber).find()){
// if (wp.heading1.toLowerCase().contains(charText.toLowerCase())) {
filterList.add(wp);
}}else{
}
this.notifyItemRangeRemoved(0, filterList.size());
}
}
}
notifyDataSetChanged();
}
#Override
public int getItemCount() {
return mDataset.size();
}
}
Please help me in implementing searchview in viewpager .
With help of uploaded code
I can tell that
make method in your fragments named search and
call adapter filter method
public void search(String text)
{
adapter.filter(text)
}
you can check instance of fragment and call search method of fragment after this line
Fragment fragment = adapter.getFragment(viewPager.getCurrentItem());
I think the best design for this is to use the Activity as the central "hub" for events that need to go the fragments.
So this is how I would do this:
First start with a listener interface. This can be declared as an inner interface of the Activity:
static interface QueryListener {
void onQueryChange(String query);
}
Activity gets properties for holding listeners and methods for adding and removing listeners (declared synchronized to prevent those pesky ConcurrentModificationExceptions:
private List<QueryListener> mQueryListeners = new ArrayList<>();
public synchronized void addQueryListener(#NonNull QueryListener listener) {
// check if the listener was already added
// you could also use a Set instead of a List for this
if (mQueryListeners.contains(listener)) return;
mQueryListeners.add(listener);
}
public synchronized void removeQueryListener(#NonNull QueryListener listener) {
mQueryListeners.remove(listener);
}
Activity also gets a method that can be called by the fragment with the SearchView:
public synchronized void changeQuery(String query) {
for (QueryListener listener : mQueryListeners) {
listener.onQueryChange(query);
}
}
Now your fragments with the adapters need to implement QueryListener and register/unregister themselves:
Add this line somewhere in onCreate():
((YourActivity) getActivity()).addQueryListener(this);
Unregister in onDestroy():
#Override
public void onDestroy() {
((YourActivity) getActivity()).removeQueryListener(this);
super.onDestroy();
}
add the QueryListener method implementation:
#Override
public void onQueryChange(String query) {
// if (isVisible()) { if desired
mAdapter.filter(query);
}
Note: You don't have to have the fragment implement QueryListener; you can use an anonymous class. But you'll have to hold the reference to it so you can call removeQueryListener() with it later.
Now just hook up the SearchView:
#Override
public boolean onQueryTextChange(String query) {
((YourActivity) getActivity()).changeQuery(query);
}
Another pattern I've used is to create a dedicated class for registering/notifying listeners. I create a single instance of this class and have a method on the Activity to access it:
QueryHandler handler = ((YourActivity) getActivity()).getQueryHandler();
// QueryHandler has all the listener properties and methods shown for the Activity
...
handler.changeQuery(query);
Alternatively, you can also use one of the many open-source event bus packages like Otto to pass events amongst your fragments.
I am new to Android and am trying a sample application for showing ViewPagers in a Master-Detail Flow using custom PagerAdapters and FragmentStatePagerAdapters. My application has a list of dummy items managed by a SQLiteDatabase which contain a title String, a description String, a Boolean like status, and a list of images (I plan to implement them as downloading from String urls but presently I'm just trying with a single image resource). I am having two problems in the Detail View.
My intention is to use a ViewPager with a FragmentStatePagerAdapter to show the detail view, which consists of a ViewPager with a custom PagerAdapter for showing the list of images, TextView for title and description, a ToggleButton for the like status and a delete button for deleting items from the list.
Issues:
The ViewPager with the custom PagerAdapter does not display the image. It occupies the expected space and swipes performed on it also behave as expected. Only the image is not visible.
[RESOLVED] On using the delete button, I am able to delete the item from the database, and also update the Master View accordingly, but I am not able to update the Detail View, and the app crashes.
Here is my code:
Code that calls ItemDetailActivity.java
#Override
public void onClick(View v) {
Intent detailIntent = new Intent(getContext(), ItemDetailActivity.class);
detailIntent.putExtra(ItemDetailFragment.ARG_LIST_POSITION, holder.position);
getContext().startActivity(detailIntent);
}
ItemDetailActivity.java
public class ItemDetailActivity extends FragmentActivity {
static ItemDetailPagerAdapter idpa;
static ViewPager detailPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item_detail);
idpa = new ItemDetailPagerAdapter(getSupportFragmentManager());
// Show the Up button in the action bar.
getActionBar().setDisplayHomeAsUpEnabled(true);
detailPager = (ViewPager) findViewById(R.id.item_detail_container);
detailPager.setAdapter(idpa);
detailPager.setCurrentItem(getIntent().getIntExtra(ItemDetailFragment.ARG_LIST_POSITION, 0));
}
}
activity_item_detail.xml
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/item_detail_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.trial.piclist.ItemDetailActivity"
tools:ignore="MergeRootFrame" />
ItemDetailFragment.java
public class ItemDetailFragment extends Fragment {
public static final String ARG_ITEM_ID = "item_id";
public static final String ARG_LIST_POSITION = "list_index";
public static final String ARG_TWO_PANE = "is_two_pane";
int position = -1;
long id = -1;
boolean twoPane = false;
ViewPager pager;
private PicItem mItem;
public ItemDetailFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
twoPane = getArguments().getBoolean(ARG_TWO_PANE, false);
position = getArguments().getInt(ARG_LIST_POSITION, -1);
id = getArguments().getLong(ARG_ITEM_ID, -1);
if (id == -1)
id = ItemListFragment.getIdByPosition(position);
setmItem(id);
}
public void setmItem(long id) {
if (id >= 0) {
try {
ItemListActivity.lds.open();
mItem = ItemListActivity.lds.getById(id);
ItemListActivity.lds.close();
} catch (Exception e) {
System.out.println(e.getMessage());
}
if (mItem != null) {
List<String> pics = new ArrayList<String>();
pics.add("1");
pics.add("2");
pics.add("3");
pics.add("4");
pics.add("5");
mItem.setPics(pics);
}
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_item_detail,
container, false);
DetailViewHolder holder = new DetailViewHolder();
pager = (ViewPager) rootView.findViewById(R.id.pager);
ImagePagerAdapter adapter = new ImagePagerAdapter(mItem, getActivity(),
inflater, position);
pager.setAdapter(adapter);
holder.position = getArguments().getInt(ARG_LIST_POSITION);
holder.ttv = (TextView) rootView.findViewById(R.id.item_title);
holder.dtv = (TextView) rootView.findViewById(R.id.item_detail);
holder.likeButton = (ToggleButton) rootView
.findViewById(R.id.item_like);
holder.deleteButton = (Button) rootView.findViewById(R.id.item_delete);
rootView.setTag(holder);
if (mItem != null) {
holder.ttv.setText(mItem.getTitle());
holder.dtv.setText(mItem.getDescription());
holder.likeButton.setChecked(mItem.getIsLiked());
holder.likeButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ItemListActivity.lds.open();
ItemListActivity.lds.toggleLike(mItem.getId());
mItem.toggleIsLiked();
ItemListActivity.lds.close();
ItemListFragment.listDisplayHelper.toggleLiked(position);
}
});
holder.deleteButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ItemListActivity.lds.open();
ItemListActivity.lds.removeItem(mItem.getId());
ItemListActivity.lds.close();
ItemListFragment.listDisplayHelper.remove(position);
ItemListActivity.idpa.notifyDataSetChanged();
// What do I do so that the FragmentStatePagerAdapter is
// updated and the viewpager shows the next item.
}
});
}
return rootView;
}
static private class DetailViewHolder {
TextView ttv;
TextView dtv;
ToggleButton likeButton;
Button deleteButton;
int position;
}
}
fragment_item_detail.xml
<LinearLayout 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:orientation="vertical"
android:padding="16dp"
tools:context="com.trial.piclist.ItemDetailFragment" >
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="200dip">
</android.support.v4.view.ViewPager>
<TableRow
android:id="#+id/tableRow1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="#+id/item_title"
style="?android:attr/textAppearanceLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello"
android:textIsSelectable="true" />
<Space
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1" />
<include
android:layout_width="wrap_content"
android:layout_height="wrap_content"
layout="#layout/controls_layout" />
</TableRow>
<ScrollView
android:id="#+id/descScrollView"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/item_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello" />
</LinearLayout>
</ScrollView>
</LinearLayout>
controls_layout.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"
android:orientation="horizontal" >
<ToggleButton
android:id="#+id/item_like"
android:layout_width="30dip"
android:layout_height="30dip"
android:layout_gravity="right"
android:background="#android:drawable/btn_star"
android:gravity="center"
android:text="#string/like_list_item"
android:textOff="#string/empty_text"
android:textOn="#string/empty_text" />
<Button
android:id="#+id/item_delete"
style="?android:attr/buttonStyleSmall"
android:layout_width="30dip"
android:layout_height="30dip"
android:background="#android:drawable/ic_menu_delete"
android:text="#string/empty_text" />
</LinearLayout>
Custom PagerAdapter
ImagePagerAdapter.java
public class ImagePagerAdapter extends PagerAdapter {
LayoutInflater inflater;
List<View> layouts = new ArrayList<>(5);
// Constructors.
#Override
public Object instantiateItem(ViewGroup container, int position) {
if (layouts.get(position) != null) {
return layouts.get(position);
}
View layout = inflater.inflate(R.layout.detail_image,
((ViewPager) container), true);
try {
ImageView loadSpace = (ImageView) layout
.findViewById(R.id.detail_image_view);
loadSpace.setBackgroundColor(0x000000);
loadSpace.setImageResource(R.drawable.light_grey_background);
loadSpace.setAdjustViewBounds(true);
} catch (Exception e) {
System.out.println(e.getMessage());
}
layout.setTag(images.get(position));
layouts.set(position, layout);
return layout;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
}
#Override
public int getCount() {
return 5;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return (((View) object).findViewById((view.getId())) != null);
}
}
FragmentPagerAdapter
ItemDetailPagerAdapter.java
public class ItemDetailPagerAdapter extends FragmentStatePagerAdapter {
public ItemDetailPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
Fragment fragment = new ItemDetailFragment();
Bundle args = new Bundle();
args.putLong(ItemDetailFragment.ARG_ITEM_ID, ItemListFragment.getIdByPosition(position));
args.putInt(ItemDetailFragment.ARG_LIST_POSITION, position);
args.putBoolean(ItemDetailFragment.ARG_TWO_PANE, ItemListActivity.mTwoPane);
fragment.setArguments(args);
return fragment;
}
#Override
public int getCount() {
openDatabase();
int c = database.getCount();
closeDatabase();
return c;
}
#Override
public int getItemPosition(Object object) {
long mId = ((ItemDetailFragment) object).getmId();
int pos = POSITION_NONE;
openDatabase();
if (database.contains(mId)) {
pos = database.getPositionById(mId);
}
closeDatabase();
return pos;
}
}
Any help is much appreciated. Thanks :)
In your ItemDetailFragment, remove the viewpager from the holder, it should be directly into the returned view, something like this:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_item_detail,
container, false);
pager = (ViewPager) rootView.findViewById(R.id.pager);
ImagePagerAdapter adapter = new ImagePagerAdapter(mItem, getActivity(),inflater, position);
pager.setAdapter(adapter);
return rootView;
}
and the ViewHolder pattern should be applied inside your PagerAdapter.
In ImagePagerAdapter.java, correct the isViewFromObject method -
#Override
public boolean isViewFromObject(View view, Object object) {
return (view == (View) object);
}
This will correct the issue of the ImageView.
In ItemDetailPagerAdapter.java, override the getItemPosition method -
#Override
public int getItemPosition(Object object) {
int ret = POSITION_NONE;
long id = ((ItemDetailFragment) object).getId();
openDatabase();
if (databaseContains(id)) {
ret = positionInDatabase(id);
}
closeDatabase();
return ret;
}
On deleting call the FragmentStatePagerAdapter.NotifyDataSetChanged() method. This will make the Adapter update itself on deleting.
Although, the FragmentStatePagerAdapter uses a list of Fragments and of stored states to implement the adapter. That is also causing trouble. To remove that, implement your own list of Fragments.