I have a custom pager adapter (PagerIot) that I have successfully implemented using a fragment as shown below
public class SensorIconFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.layout_listview, container, false);
ButterKnife.bind(this, view);
pagerIot = (PagerIot)container;
I would however like to use the pager adapter in a activity but the problem is I need to know how to initialize the pager in an activity. In a fragment its quite simple because fragments have an onCreateViewMethod where a viewGroup is passed in as a parameter so I can simply say pPagerIot = (PagerIot)container;
In Activity however I cannot simply initialize the PagerIOT because onCreate does not pass in a ViewGroup so does anyone know how I can initialize the adapter in an Activity ?
This is my PagerIOT class below
public class PagerIot extends ViewPager
{
public PagerIot(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public void allowScrollingToTab(int tab)
{
// Set the limit of the number of pages in the page adapter
ManagementTabFragment.SectionsPagerAdapter adapter = (ManagementTabFragment.SectionsPagerAdapter)getAdapter();
adapter.allowScrollingToTab(tab);
}
}
I will also include the managenment tab referenced in the class above
package com.dtect.devicesensorinsight.home.tabs;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.dtect.common.ITabView;
import com.dtect.common.MyFragmentPagerAdapter;
import com.dtect.devicesensorinsight.R;
import com.dtect.devicesensorinsight.events.JumpToManagementTabEvent;
import com.dtect.devicesensorinsight.home.PagerIot;
import com.dtect.devicesensorinsight.home.tabs.management.CostCentreListFragment;
import com.dtect.devicesensorinsight.home.tabs.management.IotTabFragment;
import com.dtect.devicesensorinsight.home.tabs.management.SensorIconFragment;
//import com.dtect.devicesensorinsight.home.tabs.notifications.TenantDetailsFragment;
import com.dtect.devicesensorinsight.home.tabs.management.iot.SensorInformationChildFragment;
import com.dtect.devicesensorinsight.sensors.ItemClickedEvent;
import java.util.Locale;
import butterknife.BindView;
import butterknife.ButterKnife;
import de.greenrobot.event.EventBus;
public class ManagementTabFragment extends Fragment implements ITabView
{
public static final int TAB_USER_LANDINGPAGE = 0;
public static final int TAB_TENANT_SCANQRCODE= 1;
public static final int TAB_TENANT_DETAILS = 2;
public static final int TAB_UOM_SYMBOLS = 3;
public static final int TAB_LOCATIONS = 4;
public static final int TAB_IOT = 5;
#BindView(R.id.managementpager)
PagerIot viewPager;
private SectionsPagerAdapter sectionsPagerAdapter;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_management_pages, container, false);
ButterKnife.bind(this, view);
sectionsPagerAdapter = new SectionsPagerAdapter(getChildFragmentManager());
viewPager.setAdapter(sectionsPagerAdapter);
viewPager.setOffscreenPageLimit(5);
return view;
}
#Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
#Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
public void onEvent(JumpToManagementTabEvent tab) {
setSelectedPage(tab.tabIndex);
}
private void setSelectedPage(int index)
{
viewPager.setCurrentItem(index);
}
#Override
public MyFragmentPagerAdapter getAdapter() {
return sectionsPagerAdapter;
}
#Override
public ViewPager getViewPager() {
return viewPager;
}
/**
* A {#link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public class SectionsPagerAdapter extends MyFragmentPagerAdapter {
private int allowScrollingToTabOffset = 0;
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
public void allowScrollingToTab(int tab)
{
this.allowScrollingToTabOffset = tab;
notifyDataSetChanged();
}
#Override
public Fragment getItem(int position) {
switch (position)
{
case TAB_USER_LANDINGPAGE:
return new UserLandingPageFragment();
case TAB_UOM_SYMBOLS:
return new SensorIconFragment();
case TAB_LOCATIONS:
return new CostCentreListFragment();
case TAB_IOT:
return new IotTabFragment();
default:
return null;
}
}
#Override
public int getCount() {
return allowScrollingToTabOffset + 1;
}
#Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
return "" + position;
}
}
}
Related
I am trying to make an activity which has a fragment inside with a recyclerView and cards on it. Right now, it only shows the activity, the fragment is empty, and I don't know what is going on here.
This is the code of the activity, the fragment, and the adapter
Activity:
package com.laorden.goodreasons.habits;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.VisibleForTesting;
import android.support.design.widget.NavigationView;
import android.support.test.espresso.IdlingResource;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import android.view.Window;
import android.view.WindowManager;
import com.laorden.goodreasons.Injection;
import com.laorden.goodreasons.R;
import com.laorden.goodreasons.statistics.StatisticsActivity;
import com.laorden.goodreasons.util.ActivityUtils;
import com.laorden.goodreasons.util.EspressoIdlingResource;
public class HabitsActivity extends AppCompatActivity {
private DrawerLayout mDrawerLayout;
private HabitsPresenter mHabitsPresenter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.habits_act);
Window w = getWindow();
w.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
// Set up the toolbar.
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar ab = getSupportActionBar();
ab.setHomeAsUpIndicator(R.drawable.ic_menu);
ab.setDisplayHomeAsUpEnabled(true);
// Set up the navigation drawer.
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerLayout.setStatusBarBackground(R.color.colorPrimaryDark);
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
if (navigationView != null) {
setupDrawerContent(navigationView);
}
HabitsFragment habitsFragment =
(HabitsFragment) getSupportFragmentManager().findFragmentById(R.id.contentFrame);
if (habitsFragment == null) {
// Create the fragment
habitsFragment = HabitsFragment.newInstance();
ActivityUtils.addFragmentToActivity(
getSupportFragmentManager(), habitsFragment, R.id.contentFrame);
}
// Create the presenter
mHabitsPresenter = new HabitsPresenter(habitsFragment,
Injection.provideUseCaseHandler());
}
/* // Load previously saved state, if available.
if (savedInstanceState != null) {
TasksFilterType currentFiltering =
(TasksFilterType) savedInstanceState.getSerializable(CURRENT_FILTERING_KEY);
mTasksPresenter.setFiltering(currentFiltering);
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putSerializable(CURRENT_FILTERING_KEY, mTasksPresenter.getFiltering());
super.onSaveInstanceState(outState);
}*/
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// Open the navigation drawer when the home icon is selected from the toolbar.
mDrawerLayout.openDrawer(GravityCompat.START);
return true;
}
return super.onOptionsItemSelected(item);
}
private void setupDrawerContent(NavigationView navigationView) {
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.list_navigation_menu_item:
// Do nothing, we're already on that screen
break;
case R.id.statistics_navigation_menu_item:
Intent intent =
new Intent(HabitsActivity.this, StatisticsActivity.class);
startActivity(intent);
break;
default:
break;
}
// Close the navigation drawer when an item is selected.
menuItem.setChecked(true);
mDrawerLayout.closeDrawers();
return true;
}
});
}
#VisibleForTesting
public IdlingResource getCountingIdlingResource() {
return EspressoIdlingResource.getIdlingResource();
}
}
Fragment:
package com.laorden.goodreasons.habits;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import com.laorden.goodreasons.R;
import com.laorden.goodreasons.habits.domain.model.Habit;
import java.util.ArrayList;
import java.util.List;
public class HabitsFragment extends android.support.v4.app.Fragment implements HabitsContract.View {
private HabitsContract.Presenter mPresenter;
private HabitsAdapter mListAdapter;
private RecyclerView recyclerView;
public HabitsFragment() {
// Requires empty public constructor
}
public static HabitsFragment newInstance() {
return new HabitsFragment();
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
List<Habit> habitsList = new ArrayList<>();
habitsList.add(new Habit(R.drawable.smoke,"Quit smoking",300));
habitsList.add(new Habit(R.drawable.books,"Read more",600));
habitsList.add(new Habit(R.drawable.sleep,"Get more sleep",600));
mListAdapter = new HabitsAdapter(getContext(),habitsList);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.habits_frag, container, false);
recyclerView = root.findViewById(R.id.rv_list);
recyclerView.setAdapter(mListAdapter);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
return root;
}
#Override
public void onResume() {
super.onResume();
mPresenter.start();
}
#Override
public void setLoadingIndicator(boolean active) {
}
#Override
public void showHabits(List<Habit> habits) {
}
#Override
public void showHabitDetailsUi(String habitId) {
}
#Override
public boolean isActive() {
return false;
}
#Override
public void setPresenter(HabitsContract.Presenter presenter) {
mPresenter = presenter;
}
}
Adapter:
package com.laorden.goodreasons.habits;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.laorden.goodreasons.R;
import com.laorden.goodreasons.habits.domain.model.Habit;
import java.util.List;
public class HabitsAdapter extends RecyclerView.Adapter<HabitsAdapter.myViewHolder> {
Context mContext;
List<Habit> mData;
public HabitsAdapter(Context mContext, List<Habit> mData) {
this.mContext = mContext;
this.mData = mData;
}
#Override
public myViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(mContext);
View v = inflater.inflate(R.layout.card_item,parent,false);
return new myViewHolder(v);
}
#Override
public void onBindViewHolder(myViewHolder holder, int position) {
holder.background_image.setImageResource(mData.get(position).getBackground());
holder.tv_title.setText(mData.get(position).getHabitName());
holder.tv_nbSubscribers.setText(mData.get(position).getNumSubscribers() + " Joined");
}
#Override
public int getItemCount() {
return 0;
}
public class myViewHolder extends RecyclerView.ViewHolder {
ImageView background_image;
TextView tv_title,tv_nbSubscribers;
public myViewHolder(View itemView) {
super(itemView);
background_image = itemView.findViewById(R.id.card_background);
tv_title = itemView.findViewById(R.id.card_title);
tv_nbSubscribers = itemView.findViewById(R.id.card_numberUsers);
}
}
}
If you need any other code snippets, please tell me (maybe the xml
layouts)
Thanks
That is because you are returning 0 in the getItemCount method
Change this :
#Override
public int getItemCount() {
return 0;
}
To this:
#Override
public int getItemCount() {
return (mData != null ? mData.size():0);
}
you should set layout manager first
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.habits_frag, container, false);
recyclerView = root.findViewById(R.id.rv_list);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setAdapter(mListAdapter);
return root;
}
also you need to change the getItemCount into
#Override
public int getItemCount() {
if(mData!=null){return mData.size();}else return 0;
}
The reason you are getting empty list because your method getItemCount returns 0.
Here is the modified method.
#Override
public int getItemCount() {
return mData!=null ? mData.size():0;
}
I've been trying to implement a recycler view inside a fragment which displays parsed data using the retrofit library. Whenever I run the project the lists don't show and the monitor says "E/RecyclerView: No adapter attached; skipping layout". Here is my code:
MainActivity:
package com.example.ahmed.newsapp
import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.design.widget.TabLayout;
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private static final int ACTIVITY_NUM = 0;
// TODO - insert your themoviedb.org API KEY here
private final static String API_KEY = "<API KEY CENSORED>";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Find the view pager that will allow the user to swipe between fragments
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
// Create an adapter that knows which fragment should be shown
FragmentAdapter adapter = new FragmentAdapter(getSupportFragmentManager
());
// Set the adapter onto the view pager
viewPager.setAdapter(adapter);
TabLayout ob=(TabLayout) findViewById(R.id.sliding_tabs);
ob.setupWithViewPager(viewPager);
}
}
FragmentAdapter:
package com.example.ahmed.newsapp;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
/**
* Created by ahmed on 3/22/2017.
*/
public class FragmentAdapter extends FragmentPagerAdapter {
private String tabs[]=new String[]{"Home","Family Members","Colors"};
public FragmentAdapter(FragmentManager fm){
super(fm);
}
#Override
public Fragment getItem(int position) {
switch(position){
case 0:
return new HomeActivity();
case 1:
return new HomeActivity();
/* case 2:
return new ColorFragment();*/
}
return null;
}
#Override
public CharSequence getPageTitle(int position) {
return tabs[position];
}
#Override
public int getCount() {
return 2;
}
}
NewsAdapter:
package com.example.ahmed.newsapp;
/**
* Created by ahmed on 27-08-17.
*/
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.List;
public class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.NewsViewHolder> {
private List<News> news;
private int rowLayout;
private Context context;
public static class NewsViewHolder extends RecyclerView.ViewHolder {
LinearLayout moviesLayout;
TextView movieTitle;
TextView data;
TextView movieDescription;
TextView rating;
public NewsViewHolder(View v) {
super(v);
moviesLayout = (LinearLayout) v.findViewById(R.id.movies_layout);
movieTitle = (TextView) v.findViewById(R.id.title);
data = (TextView) v.findViewById(R.id.subtitle);
movieDescription = (TextView) v.findViewById(R.id.description);
rating = (TextView) v.findViewById(R.id.rating);
}
}
public NewsAdapter(List<News> news, Context context) {
this.news = news;
// this.rowLayout = rowLayout;
this.context = context;
}
#Override
public NewsViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item_news, parent, false);
return new NewsViewHolder(view);
}
#Override
public void onBindViewHolder(NewsViewHolder holder, final int position) {
holder.movieTitle.setText(news.get(position).getTitle());
holder.data.setText(news.get(position).getReleaseDate());
holder.movieDescription.setText(news.get(position).getOverview());
holder.rating.setText(news.get(position).getVoteAverage().toString());
}
#Override
public int getItemCount() {
return news.size();
}
}
HomeActivity:
package com.example.ahmed.newsapp;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import static android.content.ContentValues.TAG;
public class HomeActivity extends Fragment {
RecyclerView recyclerView;
private final static String API_KEY = "<API KEY CENSORED>";
NewsAdapter adapter;
List<News> news,dummy;
View rootview;
public HomeActivity() {
// Required empty public constructor
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootview = inflater.inflate(R.layout.activity_home, container, false);
if (API_KEY.isEmpty()) {
Toast.makeText(getContext(), "Please obtain your API KEY first from themoviedb.org", Toast.LENGTH_LONG).show();
return rootview;
}
ApiInterface apiService =
ApiClient.getClient().create(ApiInterface.class);
recyclerView = (RecyclerView) rootview.findViewById(R.id.home_page_recycler_view);
adapter= new NewsAdapter(dummy,getContext());
Call<NewsResponse> call = apiService.getTopRatedMovies(API_KEY);
call.enqueue(new Callback<NewsResponse>() {
#Override
public void onResponse(Call<NewsResponse> call, Response<NewsResponse> response) {
news = response.body().getResults();
adapter.notifyDataSetChanged();
adapter=new NewsAdapter(news,getContext());
recyclerView.setAdapter(adapter);
// adapter.setData(news);
Log.d(TAG, "Number of movies received: " + news.size());
}
#Override
public void onFailure(Call<NewsResponse> call, Throwable t) {
// Log error here since request failed
Log.e(TAG, t.toString());
}
});
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
return rootview;
}
}
i think the problem is in your FragmentAdapter class
just remove return null; statement from your FragmentAdapter like below code
#Override
public Fragment getItem(int position) {
Fragment fragment=null;
switch(position){
case 0:
fragment= new HomeActivity();
case 1:
fragment= new HomeActivity();
/* case 2:
return new ColorFragment();*/
}
return fragment;
}
change this
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
recyclerView = (RecyclerView) rootview.findViewById(R.id.home_page_recycler_view);
adapter= new NewsAdapter(dummy,getContext());
You don't need to recreate your adapter when you receive response.
It may looks like:
recyclerView = (RecyclerView) rootview.findViewById(R.id.home_page_recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
adapter = new NewsAdapter(null, getActivity());
recyclerView.setAdapter(adapter);
Call<NewsResponse> call = apiService.getTopRatedMovies(API_KEY);
call.enqueue(new Callback<NewsResponse>() {
#Override
public void onResponse(Call<NewsResponse> call, Response<NewsResponse> response) {
news = response.body().getResults();
adapter.setData(news);
Log.d(TAG, "Number of movies received: " + news.size());
}
...
And in NewsAdapter:
...
public void setData(Collection<News> newData) {
news.clear();
news.addAll(newData);
notifyDataSetChanged();
}
#Override
public int getItemCount() {
return news == null ? 0 : news.size();
}
...
I am trying to write different functionalities for my FloatingActionButton depending on the fragment that the mainActivity is currently hosting. Yet for for reason in my onClick() method, getSupportFragmentManager().findFragmentById() returns null.
I haven't seen any examples of this question implemented with a viewpager and I am curious if there is a different approach I have to take.
MainActivity
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.View;
public class MainActivity extends FragmentActivity {
private Adapter mAdapter;
private ViewPager mViewPager;
private static FloatingActionButton bButton;
private static String UID;
private Intent intent;
public static String getUID(){
return UID;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAdapter = new Adapter(getSupportFragmentManager());
mViewPager = (ViewPager)findViewById(R.id.vPager);
mViewPager.setAdapter(mAdapter);
intent = getIntent();
UID = intent.getStringExtra("uid");
bButton = (FloatingActionButton)findViewById(R.id.bButton);
bButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragContainer);
if(fragment == null){
Log.e("TAG","FRAGMENT IS NULL!!");
}
else{
Log.e("TAG","FRAGMENT IS NOT NULL!!");
}
}
});
}
}
NewsFeedFragment
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.ListFragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.firebase.client.Firebase;
import com.firebase.client.FirebaseError;
import com.mycompany.neighbors.R;
import com.mycompany.neighbors.SinglePost;
import java.util.ArrayList;
/**
* Created by joshua on 5/25/2016.
*/
public class NewsFeedFragment extends ListFragment implements AdapterView.OnItemClickListener{
private ListView lv;
private TextView tvUserName;
private TextView tvStatus;
private ArrayList<SinglePost> posts = new ArrayList<>();
private static final String POSTS_PATH = "MY_PATH";
private Firebase postsRef;
// private static final String FRAGMENT_POST = "post";
public void postFragment(){
Log.d("TAG", "Doing something else");
PostFragment postFragment = new PostFragment();
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.fragContainer,postFragment)
.addToBackStack(null)
.commit();
}
#Override
public void onViewCreated(View v, Bundle s){
lv = getListView();
lv.setOnItemClickListener(this);
}
#Override
public void onCreate(Bundle savedInstance){
super.onCreate(savedInstance);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState){
View v = inflater.inflate(R.layout.fragment_post_feed_item,parent,false);//changed
tvUserName = (TextView)v.findViewById(R.id.tvUN);
tvStatus = (TextView)v.findViewById(R.id.tvStatus);
postsRef = new Firebase(POSTS_PATH);
postsRef.addChildEventListener(new com.firebase.client.ChildEventListener() {
#Override
public void onChildAdded(com.firebase.client.DataSnapshot dataSnapshot, String s) {
SinglePost post = dataSnapshot.getValue(SinglePost.class);
post.setKey(dataSnapshot.getKey());
posts.add(0, post);
if(posts.size() > 0) {
PostAdapter adapter = new PostAdapter(posts);
setListAdapter(adapter);
}else{
Toast toast = Toast.makeText(getActivity(),"No data", Toast.LENGTH_SHORT);
toast.show();
}
}
#Override
public void onChildChanged(com.firebase.client.DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(com.firebase.client.DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(com.firebase.client.DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
return v;
}
#Override
public void onListItemClick(ListView l, View v, int position, long id){
SinglePost p = ((PostAdapter) getListAdapter()).getItem(position);
}
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
}
private class PostAdapter extends ArrayAdapter<SinglePost>{
public PostAdapter(ArrayList<SinglePost> singlePost){
super(getActivity(),android.R.layout.simple_list_item_1,singlePost);
}
#Override
public View getView(int position, View convertView, ViewGroup parent){
if(convertView == null){
convertView = getActivity().getLayoutInflater().inflate(R.layout.fragment_post_feed_item,null);
}
SinglePost p = getItem(position);
TextView tvUserName = (TextView)convertView.findViewById(R.id.tvUN);
tvUserName.setText(p.getUserName());
TextView tvStatus = (TextView)convertView.findViewById(R.id.tvStatus);
tvStatus.setText(p.getStatus());
return convertView;
}
}
}
I have 2 other fragments but i'll post one as an example. Here is my adapter for the viewpager.
Adapter
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import com.mycompany.neighbors.Fragments.MapFragment;
import com.mycompany.neighbors.Fragments.NewsFeedFragment;
import com.mycompany.neighbors.Fragments.ProfileFragment;
/**
* Created by joshua on 5/25/2016.
*/
public class Adapter extends FragmentPagerAdapter {
private String Fragment[] = {"Posts" , "Map" , "Profile"};
public Adapter(FragmentManager fm){
super (fm);
}
#Override
public Fragment getItem(int position) {
switch(position){
case 0:
return new NewsFeedFragment();
case 1:
return new MapFragment();
case 2:
return new ProfileFragment();
default:
return null;
}
}
#Override
public int getCount(){return Fragment.length;}
#Override
public CharSequence getPageTitle(int position) {
return Fragment[position];
}
}
Please check below link, It has very good explanation for your problem:
http://tamsler.blogspot.in/2011/11/android-viewpager-and-fragments-part-ii.html
Or you can try below code snippet:
1.Where you add fragment in view pager or view pager adapter:
MyFragment myFragment = MyFragment.newInstance();
mPageReferenceMap.put(index, "Some Tag");
getSupportFragmentManager().beginTransaction().add(myFragment,"Some Tag").commit();
2.To get the tag for the currently visible page, you then call:
int index = mViewPager.getCurrentItem();
String tag = mPageReferenceMap.get(index);
3.and then get the fragment page:
Fragment myFragment = getSupportFragmentManager().findFragmentByTag(tag);
I am using Sugar ORM to implement Data Persistence in my app. I am displaying my database contents in a RecyclerView. The problem is SugarORM doesn't have loaders so there is no way to refresh the RecyclerView with fresh data after adding/deleting an entry to the database. I have worked around the issue for phones by reinitializing my Adapter in OnResume() and displaying it in the Recycler View. But for Tablets, the logic isn't working because the Fragment never goes to OnPause.
I need to update my the RecyclerView in my FavouritesFragment when I remove an entry in my DetailsFragment
Here's the Github link https://github.com/Hackertronix/Project-Motion/tree/Stage_2
Here's the code for both fragments
FavoritesFragment.java
package com.execube.genesis.views.fragments;
import android.app.ActivityOptions;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.execube.genesis.R;
import com.execube.genesis.model.Movie;
import com.execube.genesis.utils.API;
import com.orm.SugarRecord;
import com.squareup.picasso.Picasso;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Prateek Phoenix on 6/7/2016.
*/
public class FavouritesFragment extends Fragment {
public static final String TAG= "FAVOURITES";
private static final String FAVOURITE_MOVIES_ARRAY = "favourite_movies";
private List<Movie> mMovies=new ArrayList<>();
private RecyclerView mFavouritesRecyclerView;
ArrayList<Movie> moviesArrayList;
private FavouritesAdapter mAdapter;
private TabLayout mTabLayout;
public FavouritesFragment() {
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
Log.v(TAG,"In OnCreate()");
super.onCreate(savedInstanceState);
}
#Override
public void onPause() {
Log.v(TAG,"OnPause() Called");
super.onPause();
}
#Override
public void onResume() {
/* Sugar ORM does not have a Loader
so to refresh the recyclerview adapter I am reinitializing it*/
Log.v(TAG,"OnResume() Called");
mMovies=Movie.listAll(Movie.class);
mAdapter=new FavouritesAdapter();
mFavouritesRecyclerView.setAdapter(mAdapter);
mFavouritesRecyclerView.invalidate();
super.onResume();
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
Log.v(TAG,"In OnCreateView()");
View view = inflater.inflate(R.layout.fragment_favourites,container,false);
mFavouritesRecyclerView=(RecyclerView)view.findViewById(R.id.favourites_recyclerview);
if(savedInstanceState!=null&&savedInstanceState.containsKey(FAVOURITE_MOVIES_ARRAY))
{
Log.v(TAG,"Restoring State");
mMovies=savedInstanceState.getParcelableArrayList(FAVOURITE_MOVIES_ARRAY);
}
else {
mMovies= Movie.listAll(Movie.class);
}
if(getActivity().getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT){
mFavouritesRecyclerView.setLayoutManager(new
GridLayoutManager(getActivity(), 2));
}
else{
mFavouritesRecyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 3));
}
mAdapter= new FavouritesAdapter();
mFavouritesRecyclerView.setAdapter(mAdapter);
mFavouritesRecyclerView.invalidate();
return view;
}
private class FavouritesHolder extends RecyclerView.ViewHolder implements View.OnClickListener
{
private ImageView mPosterImageView;
private Movie mMovie;
public FavouritesHolder(View itemView) {
super(itemView);
mPosterImageView=(ImageView)itemView.findViewById(R.id.poster);
itemView.setOnClickListener(this);
}
public void bind(Movie movie)
{
mMovie=movie;
Picasso mPicasso= Picasso.with(getActivity());
mPicasso.setIndicatorsEnabled(true);
mPicasso.load(API.IMAGE_URL+API.IMAGE_SIZE_500+mMovie.getPosterPath())
.placeholder(R.drawable.placeholder)
.error(R.drawable.error)
.into(mPosterImageView);
}
#Override
public void onClick(View v) {
ActivityOptions options=ActivityOptions.makeSceneTransitionAnimation(getActivity(),mPosterImageView,"posterImage");
((openDetailsListener)getActivity()).openDetails(mMovie,options);
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
moviesArrayList=new ArrayList<>(mMovies);
Log.v(TAG,"Saving State");
outState.putParcelableArrayList(FAVOURITE_MOVIES_ARRAY,moviesArrayList);
super.onSaveInstanceState(outState);
}
private class FavouritesAdapter extends RecyclerView.Adapter<FavouritesHolder>
{
#Override
public FavouritesHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view= LayoutInflater.from(getActivity()).inflate(R.layout.movie_item,parent,false);
return new FavouritesHolder(view);
}
#Override
public void onBindViewHolder(FavouritesHolder holder, int position) {
Movie movie= mMovies.get(position);
holder.bind(movie);
}
#Override
public int getItemCount() {
return mMovies.size();
}
}
public interface openDetailsListener{
void openDetails(Movie movie,ActivityOptions options);
}
}
DetailsFragment.java
package com.execube.genesis.views.fragments;
import android.annotation.TargetApi;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.Typeface;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.CardView;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.RatingBar;
import android.widget.TextView;
import android.widget.Toast;
import com.execube.genesis.R;
import com.execube.genesis.model.Movie;
import com.execube.genesis.model.Review;
import com.execube.genesis.model.Trailer;
import com.execube.genesis.utils.API;
import com.execube.genesis.utils.JSONParser;
import com.execube.genesis.utils.OkHttpHandler;
import com.orm.SugarRecord;
import com.squareup.picasso.Picasso;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import okhttp3.Call;
import okhttp3.Response;
import static com.execube.genesis.R.drawable.ic_favorite_black_24dp;
/**
* Created by Prateek Phoenix on 4/30/2016.
*/
public class DetailsFragment extends Fragment {
private static final String TAG = "DETAILS";
private static final int DEFAULT_NUM_COLORS = 5;
private Movie mMovie;
private Movie entry,tempMovie;
private List<Movie> movie;
public Intent intent;
private TextView mDetailTitle;
private TextView mReleaseDate;
private TextView mOverview;
private TextView mOverviewHeader;
private TextView mReviesHeader;
private TextView mTrailersHeader;
private ImageView mBackdrop;
private Toolbar mToolbar;
private RatingBar mRatingBar;
private ArrayList<Review> mReviews=new ArrayList<>();
private ArrayList<Trailer> mTrailers=new ArrayList<>();
public static final String MOVIE_REVIEWS_ARRAY ="movie_details";
private static final String MOVIE_TRAILERS_ARRAY = "movie_reviews";
private Typeface fontBold;
private Typeface fontMediumLight;
private Typeface fontMedium;
private RecyclerView mReviewRecyclerView;
private RecyclerView mTrailerRecyclerView;
private ProgressBar mReviewsProgressbar;
private ProgressBar mTrailersProgressbar;
private CoordinatorLayout mCoordinatorLayout;
private CardView mReviewsCardView;
private FloatingActionButton mFloatingActionButton;
private ReviewsAdapter mReviewAdapter;
private int NumOfReviews;
private TrailersAdapter mTrailerAdapter;
private String id;
private boolean isFav;
public DetailsFragment() {
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onSaveInstanceState(Bundle outState) {
Log.v(TAG,"Saving state in onSaveInstanceState");
outState.putParcelableArrayList(MOVIE_REVIEWS_ARRAY,mReviews);
outState.putParcelableArrayList(MOVIE_TRAILERS_ARRAY,mTrailers);
super.onSaveInstanceState(outState);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_detail, container, false);
mBackdrop = (ImageView) view.findViewById(R.id.details_poster);
mDetailTitle = (TextView) view.findViewById(R.id.detail_title_text);
mReleaseDate = (TextView) view.findViewById(R.id.release_date);
mOverview = (TextView) view.findViewById(R.id.overview);
mOverviewHeader = (TextView) view.findViewById(R.id.overview_header);
mReviesHeader=(TextView)view.findViewById(R.id.review_header);
mTrailersHeader=(TextView)view.findViewById(R.id.trailer_header);
mRatingBar = (RatingBar) view.findViewById(R.id.movie_rating);
mCoordinatorLayout=(CoordinatorLayout)view.findViewById(R.id.coordinator_layout);
mReviewRecyclerView= (RecyclerView)view.findViewById(R.id.review_recycler_view);
mTrailerRecyclerView=(RecyclerView)view.findViewById(R.id.trailer_recycler_view);
mReviewsProgressbar=(ProgressBar)view.findViewById(R.id.reviews_progressbar);
mTrailersProgressbar=(ProgressBar)view.findViewById(R.id.trailers_progressbar);
mFloatingActionButton=(FloatingActionButton)view.findViewById(R.id.fab);
mReviewsCardView= (CardView) view.findViewById(R.id.reviews_card);
intent = getActivity().getIntent();
Bundle bundle=getArguments();
mMovie=bundle.getParcelable("PARCEL");
tempMovie=mMovie;
id = String.valueOf(mMovie.getMovieId());
checkFav();
mFloatingActionButton.show();
assert mMovie != null;
//PREPPING THE URL FOR QUERY
String reviewQueryUrl = API.MOVIES_BASE_URL + id + "/reviews" + API.API_KEY;
String trailerQueryUrl = API.MOVIES_BASE_URL + id + "/videos" + API.API_KEY;
mDetailTitle.setText(mMovie.getTitle());
mReleaseDate.setText(mMovie.getReleaseDate());
mRatingBar.setProgress((int) mMovie.getVoteAverage());
mOverview.setText(mMovie.getOverview());
if (Build.VERSION.SDK_INT != 21) {
fontBold = Typeface.createFromAsset(getActivity().getAssets(), "fonts/Gotham-Rounded-Bold.ttf");
fontMedium = Typeface.createFromAsset(getActivity().getAssets(), "fonts/Gotham-Rounded-Medium.ttf");
fontMediumLight = Typeface.createFromAsset(getActivity().getAssets(), "fonts/Gotham-Rounded-Book_.ttf");
mDetailTitle.setTypeface(fontBold);
mReleaseDate.setTypeface(fontMedium);
mOverview.setTypeface(fontMediumLight);
mOverviewHeader.setTypeface(fontBold);
mReviesHeader.setTypeface(fontBold);
mTrailersHeader.setTypeface(fontBold);
}
//FETCHING JSON HERE
if(savedInstanceState!=null&&savedInstanceState.containsKey(MOVIE_REVIEWS_ARRAY))
{
Log.v(TAG,"Restoring from bundle");
mReviews=savedInstanceState.getParcelableArrayList(MOVIE_REVIEWS_ARRAY);
mTrailers=savedInstanceState.getParcelableArrayList(MOVIE_TRAILERS_ARRAY);
mReviewsProgressbar.setVisibility(View.GONE);
mTrailersProgressbar.setVisibility(View.GONE);
}
else {
OkHttpHandler reviewsHandler = new OkHttpHandler(reviewQueryUrl, reviewsCallback);
reviewsHandler.fetchData();
OkHttpHandler trailersHandler= new OkHttpHandler(trailerQueryUrl, trailersCallback);
trailersHandler.fetchData();
}
Picasso.with(getActivity()).load(API.IMAGE_URL + API.IMAGE_SIZE_500 + mMovie.getPosterPath())
.placeholder(R.drawable.placeholder)
.error(R.drawable.error)
.into(mBackdrop);
getActivity().startPostponedEnterTransition();
mReviewRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
mReviewAdapter= new ReviewsAdapter();
mReviewRecyclerView.setAdapter(mReviewAdapter);
LinearLayoutManager layoutmanager= new LinearLayoutManager(getActivity(),LinearLayoutManager.HORIZONTAL,false);
mTrailerRecyclerView.setLayoutManager(layoutmanager);
mTrailerAdapter= new TrailersAdapter();
mTrailerRecyclerView.setAdapter(mTrailerAdapter);
return view;
}
private void checkFav() {
movie=new ArrayList<>();
movie=SugarRecord.find(Movie.class,"m_id=?",id);
if(movie.size()==0)
{
Log.v(TAG,"Null");
mFloatingActionButton.setImageResource(R.drawable.ic_favorite_border_black_24dp);
}
else {
Log.v(TAG,"NOT Null");
mFloatingActionButton.setImageResource(R.drawable.ic_favorite_black_24dp);
}
mFloatingActionButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
movie=SugarRecord.find(Movie.class,"m_id=?",id);
if(movie.size()>0)
{
entry = movie.get(0);
entry.delete();
mFloatingActionButton.setImageResource(R.drawable.ic_favorite_border_black_24dp);
Snackbar snackbar = Snackbar.make(mCoordinatorLayout,"Movie removed from Favourites!!",Snackbar.LENGTH_SHORT);
View view= snackbar.getView();
TextView textView = (TextView)view.findViewById(android.support.design.R.id.snackbar_text);
textView.setTextColor(Color.YELLOW);
snackbar.show();
}
else
{
entry = tempMovie;
entry.save();
mFloatingActionButton.setImageResource(R.drawable.ic_favorite_black_24dp);
Snackbar snackbar = Snackbar.make(mCoordinatorLayout,"Movie added to Favourites!!",Snackbar.LENGTH_SHORT);
View view= snackbar.getView();
TextView textView = (TextView)view.findViewById(android.support.design.R.id.snackbar_text);
textView.setTextColor(Color.YELLOW);
snackbar.show();
}
}
});
}
//OKHTTP CALLBACK FOR NETWORK CALL
private okhttp3.Callback reviewsCallback = new okhttp3.Callback() {
#Override
public void onFailure(Call call, IOException e) {
//TODO handle failure on UI thread
}
#Override
public void onResponse(Call call, Response response) throws IOException {
try {
String JSONData= response.body().string();
JSONObject jsonObject = new JSONObject(JSONData);
NumOfReviews = jsonObject.getInt("total_results");
JSONParser parser = new JSONParser();
Log.v(TAG,JSONData);
mReviews=parser.parseReviews(JSONData);
} catch (JSONException e) {}
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
if(mReviewAdapter!=null)
{
mReviewsProgressbar.setVisibility(View.GONE);
mReviewAdapter.notifyDataSetChanged();
}
}
});
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
if (NumOfReviews==0)
{
mReviewsCardView.setVisibility(View.INVISIBLE);
}
}
});
}
};
private okhttp3.Callback trailersCallback = new okhttp3.Callback() {
#Override
public void onFailure(Call call, IOException e) {
//TODO handle failure on UI thread
}
#Override
public void onResponse(Call call, Response response) throws IOException {
try {
String json1= response.body().string();
JSONParser parser= new JSONParser();
Log.v(TAG, json1);
mTrailers = parser.parseTrailers(json1);
} catch (JSONException e) {}
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
if(mTrailerAdapter!=null)
{
mTrailersProgressbar.setVisibility(View.GONE);
mTrailerAdapter.notifyDataSetChanged();
}
}
});
}
};
private class ReviewViewHolder extends RecyclerView.ViewHolder{
private TextView mAuthorText;
private TextView mReviewText;
private Review mReview;
public ReviewViewHolder(View itemView) {
super(itemView);
mAuthorText= (TextView) itemView.findViewById(R.id.author_textview);
mReviewText= (TextView) itemView.findViewById(R.id.review_textview);
}
public void bind(Review review)
{
mReview= review;
mAuthorText.setText(mReview.getAuthor());
mReviewText.setText(mReview.getContent());
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP)
{
mAuthorText.setTypeface(fontBold);
mReviewText.setTypeface(fontMediumLight);
}
}
}
private class ReviewsAdapter extends RecyclerView.Adapter<ReviewViewHolder>{
#Override
public ReviewViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view= LayoutInflater.from(getActivity()).inflate(R.layout.review_item,parent,false);
return new ReviewViewHolder(view);
}
#Override
public void onBindViewHolder(ReviewViewHolder holder, int position) {
Review review= mReviews.get(position);
holder.bind(review);
}
#Override
public int getItemCount() {
if(mReviews==null)
{ return 0;}
else
{return mReviews.size();}
}
}
private class TrailerViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private ImageView mTrailerThumbnail;
private Trailer mTrailer;
public TrailerViewHolder(View itemView) {
super(itemView);
mTrailerThumbnail=(ImageView)itemView.findViewById(R.id.trailer_thumbnail);
itemView.setOnClickListener(this);
}
public void bind(Trailer trailer)
{
mTrailer=trailer;
Picasso picasso =Picasso.with(getActivity());
picasso.setIndicatorsEnabled(true);
picasso.load(API.YOUTUBE_THUMBNAIL_URL+mTrailer.getKey()+API.THUMBNAIL_QUALITY)
.into(mTrailerThumbnail);
}
#Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(API.YOUTUBE_TRAILER_URL+mTrailer.getKey()));
startActivity(intent);
}
}
private class TrailersAdapter extends RecyclerView.Adapter<TrailerViewHolder>
{
#Override
public TrailerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view= LayoutInflater.from(getActivity()).inflate(R.layout.trailer_item,parent,false);
return new TrailerViewHolder(view);
}
#Override
public void onBindViewHolder(TrailerViewHolder holder, int position) {
Trailer trailer= mTrailers.get(position);
holder.bind(trailer);
}
#Override
public int getItemCount() {
return mTrailers.size();
}
}
}
You can use an Interface to communicate between Fragments (Here's a question I asked an year ago and the accepted answer was really easy to understand).
Then, you need to call mAdapter.notifyDataSetChanged() in your callBack method.
I propose one way to solve this.
class TabletActivity extends Activity implements DetailFragment.Callback {
public void onCreate(Bundle savedInstanceState){
//Initialise fragments
}
void onItemDelete(){
// find the Master Fragment using FragmentManager;
MasterFragment f = (MasterFragment) getFragmentManager().findFragmentById();
if (f != null){
f.somethingHasChanged();
}
}
}
class DetailFragment extends Fragment {
private Callback callback;
public onAttach(Context context){
this.callback = (Context) context;
}
public void onViewCreated(View v, Bundle b){
Button b;
b.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
callback.onItemDelete();
}
)
}
public interface Callback {
void onItemDelete();
}
}
class MasterFragment extends Fragment {
public void somethingHasChanged(){
adapter.notifyDatasetChanged();
}
}
DetailFragment is where we initiate the changes, MasterFragment is consuming the changes. That communication is don't via the Activity. I personally don't recommend notifyAdapterChanges in OnResume() as you proposed because there is no guarantee that onResume will be call right after the changes in you data has been made.
Read more at:
https://developer.android.com/training/basics/fragments/communicating.html
I have a fragment where I am making network calls to an API. My model implements Parcelable in order to save the state on device rotation. I have implemented the method but when the device is rotated, it still makes a network request. Somehow the Parcelable implementation isn't working.
Here's my code
Movie.java (MODEL)
package com.execube.genesis.model;
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Created by Prateek Phoenix on 4/24/2016.
*/
public class Movie implements Parcelable {
private int mId;
private String mOriginalTitle;
private String mTitle;
private String mPosterPath;
private String mOverview;
private float mVoteAverage;
private Movie(Parcel source) {
mId=source.readInt();
mOriginalTitle=source.readString();
mTitle=source.readString();
mPosterPath=source.readString();
mOverview=source.readString();
mVoteAverage=source.readFloat();
}
public Movie() {
}
public int getId() {
return mId;
}
public void setId(int id) {
mId = id;
}
public String getOriginalTitle() {
return mOriginalTitle;
}
public void setOriginalTitle(String originalTitle) {
mOriginalTitle = originalTitle;
}
public String getTitle() {
return mTitle;
}
public void setTitle(String title) {
mTitle = title;
}
public String getPosterPath() {
return mPosterPath;
}
public void setPosterPath(String posterPath) {
mPosterPath = posterPath;
}
public String getOverview() {
return mOverview;
}
public void setOverview(String overview) {
mOverview = overview;
}
public float getVoteAverage() {
return mVoteAverage;
}
public void setVoteAverage(float voteAverage) {
mVoteAverage = voteAverage;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mId);
dest.writeString(mOriginalTitle);
dest.writeString(mTitle);
dest.writeString(mPosterPath);
dest.writeString(mOverview);
dest.writeFloat(mVoteAverage);
}
public static final Parcelable.Creator<Movie> CREATOR= new Parcelable.Creator<Movie>(){
#Override
public Movie createFromParcel(Parcel source) {
return new Movie(source);
}
#Override
public Movie[] newArray(int size) {
return new Movie[0];
}
};
}
PopularMoviesFragment.java
package com.execube.genesis.views;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.execube.genesis.R;
import com.execube.genesis.model.Movie;
import com.execube.genesis.utils.API;
import com.execube.genesis.utils.OkHttpHandler;
import com.squareup.picasso.Picasso;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.ArrayList;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
/**
* Created by Prateek Phoenix on 4/24/2016.
*/
public class PopularMoviesFragment extends Fragment {
private static final String TAG = "HELLO WORLD";
private static final String POPULAR_MOVIES_ARRAY ="popular_movies" ;
private ArrayList<Movie> mMovies;
private RecyclerView popularMoviesList = null;
private View progressBarPopular = null;
public PopularMoviesFragment() {
//empty constructor required
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState!=null)
{
mMovies=savedInstanceState.getParcelableArrayList(POPULAR_MOVIES_ARRAY);
}
else {
String url = API.BASE_URL+API.API_KEY+API.SORT_POPULARITY;
OkHttpHandler handler= new OkHttpHandler(url, apiCallback);
handler.fetchData();
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putParcelableArrayList(POPULAR_MOVIES_ARRAY,mMovies);//Saving state of the ArrayList to avoid the network calls.
super.onSaveInstanceState(outState);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View content = inflater.inflate(R.layout.fragment_popular_movies,container,false);
popularMoviesList = (RecyclerView) content.findViewById(R.id.popular_recyclerView);
progressBarPopular = content.findViewById(R.id.progressBar_popular);
if(getActivity().getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT){
popularMoviesList.setLayoutManager(new GridLayoutManager(getActivity(), 2));
}
else{
popularMoviesList.setLayoutManager(new GridLayoutManager(getActivity(), 3));
}
PopularMoviesAdapter mAdapter = new PopularMoviesAdapter();
popularMoviesList.setAdapter(mAdapter);
return content;
}
private Callback apiCallback = new Callback() {
#Override
public void onFailure(Call call, IOException e) {
//TODO show error message from here but in UI thread
}
#Override
public void onResponse(Call call, Response response) throws IOException {
try {
mMovies= parseItems(response.body().string());
} catch (Exception e) {
Log.v(TAG,"Exception caught: ",e);
}
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
progressBarPopular.setVisibility(View.GONE);
popularMoviesList.setVisibility(View.VISIBLE);
//TODO add adapter
}
});
}
};
private class PopularMoviesViewHolder extends RecyclerView.ViewHolder{
private ImageView mPosterImage;
public PopularMoviesViewHolder(View itemView) {
super(itemView);
mPosterImage= (ImageView)itemView.findViewById(R.id.poster);
}
}
private class PopularMoviesAdapter extends RecyclerView.Adapter<PopularMoviesViewHolder>
{
#Override
public PopularMoviesViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view= LayoutInflater.from(getActivity()).inflate(R.layout.movie_item,parent,false);
return new PopularMoviesViewHolder(view);
}
#Override
public void onBindViewHolder(PopularMoviesViewHolder holder, int position) {
final Movie movie=mMovies.get(position);
Picasso.with(getActivity()).load(API.IMAGE_URL+API.IMAGE_SIZE_185+movie.getPosterPath())
.into(holder.mPosterImage);
}
#Override
public int getItemCount() {
return mMovies.size();
}
}
private ArrayList<Movie> parseItems( String jsonResponse) throws JSONException{
JSONObject jsonData= new JSONObject(jsonResponse);
JSONArray moviesJSONArray= jsonData.getJSONArray("results");
ArrayList<Movie> Movies= new ArrayList<>();
for (int i = 0; i <moviesJSONArray.length() ; i++) {
Movie movie= new Movie();
JSONObject movieJson= moviesJSONArray.getJSONObject(i);
movie.setId(movieJson.getInt("id"));
movie.setOriginalTitle(movieJson.getString("original_title"));
movie.setTitle(movieJson.getString("title"));
movie.setPosterPath(movieJson.getString("poster_path"));
movie.setOverview(movieJson.getString("overview"));
movie.setVoteAverage((float) movieJson.getDouble("vote_average"));
Movies.add(movie);
}
return Movies;
}
}
OkhttpHandler.java (networking code)
package com.execube.genesis.utils;
import okhttp3.Cache;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
/**
* Created by Prateek Phoenix on 4/24/2016.
*/
public class OkHttpHandler {
private String queryUrl;
private static final String TAG = "CustomTAG1";
private String mResponse;
private Callback mCallback;
public OkHttpHandler(String Url, Callback callback) {
this.mCallback = callback;
this.queryUrl = Url;
}
public void fetchData() {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(queryUrl)
.build();
Call call = client.newCall(request);
call.enqueue(mCallback);
}
}
ViewPagerFragment.java
package com.execube.genesis.views;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.execube.genesis.R;
/**
* Created by Prateek Phoenix on 4/24/2016.
*/
public class ViewPagerFragment extends Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view= inflater.inflate(R.layout.fragment_viewpager,container,false);
ViewPager viewPager= (ViewPager)view.findViewById(R.id.viewPager);
TabLayout tabLayout=(TabLayout)view.findViewById(R.id.tabLayout);
final PopularMoviesFragment fragment1= new PopularMoviesFragment();
final TopRatedMoviesFragment fragment2= new TopRatedMoviesFragment();
viewPager.setAdapter(new FragmentPagerAdapter(getChildFragmentManager()) {
#Override
public Fragment getItem(int position) {
return position==0?fragment1:fragment2;
}
#Override
public int getCount() {
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
return position==0?"POPULAR":"TOP RATED";
}
});
tabLayout.setupWithViewPager(viewPager);
return view;
}
}
MoviesActivity.java
package com.execube.genesis.views;
import android.graphics.Color;
import android.os.Build;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import com.execube.genesis.R;
public class MoviesActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_movies);
View view= findViewById(R.id.viewpager_container);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
getWindow().setStatusBarColor(Color.TRANSPARENT);
}
FragmentManager fragmentManager= getSupportFragmentManager();
Fragment fragment= fragmentManager.findFragmentById(R.id.viewpager_container);
if(fragment==null)
{
fragment= new ViewPagerFragment();
fragmentManager.beginTransaction()
.add(R.id.viewpager_container,fragment)
.commit();
}
}
}
I think you maybe made an error in your Activity like add or replace your fragment when re-creating your activity (when your device is rotated, your activity is recreated too).
About handling orientation changed, you can setRetainInstance() for your Fragment. Handling Runtime Changes:
If restarting your activity requires that you recover large sets of data, re-establish a network connection, or perform other intensive operations, then a full restart due to a configuration change might be a slow user experience. Also, it might not be possible for you to completely restore your activity state
When the Android system shuts down your activity due to a configuration
change, the fragments of your activity that you have marked to retain are not destroyed. You can add such fragments to your activity to preserve stateful objects.
// this method is only called once for this fragment
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// retain this fragment
setRetainInstance(true);
}
// find the retained fragment on activity restarts
FragmentManager fm = getFragmentManager();
dataFragment = (DataFragment) fm.findFragmentByTag(“data”);
// create the fragment and data the first time
if (dataFragment == null) {
// add the fragment
dataFragment = new DataFragment();
fm.beginTransaction().add(dataFragment, “data”).commit();
// load the data from the web
dataFragment.setData(loadMyData());
}
Caution: While you can store any object, you should never pass an object that is tied to the Activity, such as a Drawable, an Adapter, a View or any other object that's associated with a Context. If you do, it will leak all the views and resources of the original activity instance. (Leaking resources means that your application maintains a hold on them and they cannot be garbage-collected, so lots of memory can be lost.)
Update
I'm not sure, but in your case, you should setRetainInstance() for you ViewPagerFragment and:
// make those fragments global variable.
PopularMoviesFragment fragment1= new PopularMoviesFragment();
TopRatedMoviesFragment fragment2= new TopRatedMoviesFragment();
Inside your activity, replace the following code:
FragmentManager fragmentManager= getSupportFragmentManager();
Fragment fragment= fragmentManager.findFragmentById(R.id.viewpager_container);
if(fragment==null)
{
fragment= new ViewPagerFragment();
fragmentManager.beginTransaction()
.add(R.id.viewpager_container,fragment)
.commit();
}
with the following instead:
if(savedInstanceState == null) {
fragment= new ViewPagerFragment();
fragmentManager.beginTransaction()
.add(R.id.viewpager_container,fragment)
.commit();
}
Try calling onSaveInstanceState in your main Activity with super.onSaveInstanceState(outState).