Refreshing Fragment from Activity - android

I am using a main activity to show different fragments. I need to refresh one of fragment according to broadcast result. What I mention about is below.
My fragment class:
public class ConservationFragment extends Fragment
{
FragmentType fragmentType;
private RecyclerView recyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager layoutManager;
public ConservationFragment()
{
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
}
#Override
public void onResume()
{
super.onResume();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View rootView = inflater.inflate(R.layout.fragment_conservation, container, false);
try
{
this.fragmentType = (FragmentType) getArguments().getSerializable("fragmenttype");
ArrayList<Message> messageRecords = getMessagesFromDB(fragmentType);
recyclerView = (RecyclerView) rootView.findViewById(R.id.conservationsRecyclerView);
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
mAdapter = new ConversationAdapter(messageRecords, getActivity());
recyclerView.setAdapter(mAdapter);
recyclerView.setItemAnimator(new DefaultItemAnimator());
return rootView;
} catch (Exception e)
{
Log.d("RUNTIME ERROR", "Please check ConversationFragment's onCreateView method.");
}
return inflater.inflate(R.layout.fragment_conservation, container, false);
}
public ArrayList<Message> getMessagesFromDB(FragmentType fragmentType)
{
..
}
}
How I initiate fragments in main activity ;
public class MainActivity extends AppCompatActivity
{
//This is our tablayout
private TabLayout tabLayout;
//This is our viewPager
private ViewPager viewPager;
ConservationFragment personalFragment;
ConservationFragment blockedFragment;
SmsReceiver receiver;
ViewPagerAdapter adapter;
String[] tabTitle = {"PERSONAL", "BLOCKED"}; //
int[] unreadCount = {1, 2};
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
receiver = new SmsReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
registerReceiver(receiver, intentFilter);
}
#Override
protected void onResume()
{
super.onResume();
//Initializing viewPager
viewPager = (ViewPager) findViewById(R.id.viewpager);
setupViewPager(viewPager);
//Initializing the tablayout
tabLayout = (TabLayout) findViewById(R.id.tablayout);
tabLayout.setupWithViewPager(viewPager);
try
{
setupTabIcons();
} catch (Exception e)
{
e.printStackTrace();
}
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener()
{
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
{
}
#Override
public void onPageSelected(int position)
{
viewPager.setCurrentItem(position, false);
}
#Override
public void onPageScrollStateChanged(int state)
{
}
});
}
private void setupViewPager(ViewPager viewPager)
{
Bundle personalCriterial= new Bundle();
personalCriterial.putSerializable("fragmenttype",FragmentType.PERSONAL);
Bundle blockedCriterial= new Bundle();
blockedCriterial.putSerializable("fragmenttype",FragmentType.BLOCKED);
adapter = new ViewPagerAdapter(getSupportFragmentManager());
personalFragment = new ConservationFragment();
personalFragment.setArguments(personalCriterial);
blockedFragment = new ConservationFragment();
blockedFragment.setArguments(blockedCriterial);
adapter.addFragment(personalFragment, tabTitle[0]);
adapter.addFragment(blockedFragment, tabTitle[1]);
viewPager.setAdapter(adapter);
}
private void setupTabIcons()
{
for (int i = 0; i < tabTitle.length; i++)
{
tabLayout.getTabAt(i).setCustomView(prepareTabView(i));
}
}
private View prepareTabView(int pos)
{
View view = getLayoutInflater().inflate(R.layout.custom_tab, null);
TextView tv_title = (TextView) view.findViewById(R.id.tv_title);
TextView tv_count = (TextView) view.findViewById(R.id.tv_count);
tv_title.setText(tabTitle[pos]);
return view;
}
public void receiveMessage(Intent intent)
{
//here I want to refresh one of my fragments. such as personalFragment..
}
}
Critical point is here; tab view should not go first tab.(Updatement should be in same fragment)
I am aware of code is so long but I have to show how I initiate objects to lead solutions. Thanks.

If you don't need to update the whole fragment, but only pass some data and refresh textviews or lists, you can always define public methods in fragment and call it from activity.
Example method in fragment:
public void updateWithData(String exampleString) {
myTextView.setText(exampleString);
}
Example usage in activity:
public void receiveMessage(Intent intent) {
myFragment.updateWithDate("Example string message");
}
This way, you don't need to recreate the whole fragment and you can update only relevant UI elements instead. However, keep in mind that it is up to you to make sure that fragment is created and shown when you will call this update method, otherwise you will get undefined behavior.
PS: It might be a good idea to create something like Updatable interface and implement it in your fragment, so you can reuse this update logic somewhere else in your application. But it's not required and for small scope, public methods should be sufficient enough.

Related

Why recyclerview items doesn't show until scroll between tabs?

I have app that recive input from activity and needs to display it in recyclerview that imlement in tabs.
After the button pressed in the activity the values doesn't show in the target tab that I need (the 2nd one) and it shows there only after I scroll the last tab (4t) and return to the 2nd one.
Here is the code :
tab2
public class Tab2Fragment extends Fragment {
private ArrayList<exampleItem> mExampleList = new ArrayList<>();
RecyclerView mRecyclerView;
private exampleAdapter mAdapter = new exampleAdapter(mExampleList);
private RecyclerView.LayoutManager mLayoutManager;
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_two, container, false);
mRecyclerView = v.findViewById(R.id.recyclerview2);
buildRecyclerView(v);
loadData();
return v;
}
public void removeItem(int position) {
mExampleList.remove(position);
//mExampleList.clear();
//mRecyclerView.removeViewAt(position);
mAdapter.notifyItemRemoved(position);
mAdapter.notifyDataSetChanged();
}
public void changeItem(int position, String text) {
mExampleList.get(position).changeText1(text);
mAdapter.notifyItemChanged(position);
}
private void loadData() {
SharedPreferences sharedPreferences = this.getActivity().getSharedPreferences("shared preferences12", Context.MODE_PRIVATE);
Gson gson = new Gson();
String json = sharedPreferences.getString("task list12", null);
Type type = new TypeToken<ArrayList<exampleItem>>() {
}.getType();
mExampleList = gson.fromJson(json, type);
if (mExampleList == null) {
mExampleList = new ArrayList<>();
}
}
private void buildRecyclerView(View view) {
mRecyclerView = view.findViewById(R.id.recyclerview2);
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(getContext());
mAdapter = new exampleAdapter(mExampleList);
//mRecyclerView.swapAdapter(mAdapter,false);
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter.notifyDataSetChanged();
mRecyclerView.setAdapter(mAdapter);
mAdapter.setOnItemClickListener(new exampleAdapter.OnItemClickListener() {
#Override
public void onItemClick(int position) {
changeItem(position, "Clicked");
}
#Override
public void onDeleteClickListener(int position) {
removeItem(position);
}
});
}
}
mainActivty
public class MainActivity extends AppCompatActivity {
private TabAdapter adapter;
private TabLayout tabLayout;
private ViewPager viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager) findViewById(R.id.viewPager);
tabLayout = (TabLayout) findViewById(R.id.tabLayout);
adapter = new TabAdapter(getSupportFragmentManager());
adapter.addFragment(new Tab1Fragment(), "main");
adapter.addFragment(new Tab2Fragment(), "daily");
adapter.addFragment(new Tab3Fragment(), "weekly");
adapter.addFragment(new Tab4Fragment(), "monthly");
viewPager.setAdapter(adapter);
tabLayout.setupWithViewPager(viewPager);
}
}
You use notifyDataSetChanged() in changeItem and removeitem and buildRecyclerView functions.buildRecyclerView function is called before loadData and changeItem is called in onItemClick that I don't know is the same as the button you mention that you pressed. but in loadData function, you don't call notifyDataSetChanged() or other notify functions. probably this is the cause of your problem. please check that after every change in data list of recyclerview, notifyDataSetChanged() or other notify functions must is called

How to return data from BottomSheetDialogFragment to Parent Fragment

I am populating a RecyclerView inside a bottomsheet and displaying the BottomSheet as a BottomSheetDialogFragment. WHen an item from the RecyclerView is clicked, i want to Auto fill a form using details from that item.
How do i pass a class(model) object containing the data from the BottomSheetDialogFragment to the Fragment where i instantiated the BottomSheetDialogFragment on. Here's my code
Fragment i want to auto populate fields
public class FormFragment extends Fragment implements onItemSelected {public class fetchSimilarContacts extends AsyncTask<Void, Void, String> {
String result, res, search;
fetchSimilarContacts(String sear){
search = sear;
}
#Override
protected void onPostExecute(String aVoid) {
try {
if (res.equals("200")){
try {
// bring up bottom sheet
bottomSheetDialogFragment = new formBottomSheet();
Bundle bun = new Bundle();
bun.putParcelableArrayList("data", contItems);
bottomSheetDialogFragment.setArguments(bun);
bottomSheetDialogFragment.show(getActivity().getSupportFragmentManager(), bottomSheetDialogFragment.getTag());
}
catch (Exception ex){
ex.printStackTrace();
}
}
else{
Toast.makeText(getActivity().getApplicationContext(), "Could not connect to server", Toast.LENGTH_LONG).show();
}
}
}
}}
I get the data and populate the RecyclerView using the asynctask function above. Here's the formBottomSheet class
public class formBottomSheet extends BottomSheetDialogFragment{
similarContactAdapter mAdapter;
RecyclerView rec;
ArrayList<hash> contItems;
View v;
onItemSelected itemSelected;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//contItems = new ArrayList<hash>();
if(getArguments() != null){
contItems = getArguments().getParcelableArrayList("data");
}
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
/*return super.onCreateView(inflater, container, savedInstanceState);*/
v = inflater.inflate(R.layout.form_bottomsheet_recyclerview, container, false);
rec = (RecyclerView) v.findViewById(R.id.recycler);
itemSelected = (onItemSelected) getParentFragment();
//contItems = new ArrayList<hash>();
mAdapter = new similarContactAdapter(contItems, getActivity().getApplicationContext(), new similarContactAdapter.onItemClickListener() {
#Override
public void onItemClick(hash hsh) {
//after clicking on an item in the RecyclerView, i get the item's data here, how to i pass the data from here to the Form Fragment where i instantiated the bottom sheet fragment dialog?
Toast.makeText(getActivity().getApplicationContext(), "", Toast.LENGTH_LONG).show();
}
});
final RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity().getApplicationContext());
rec.setLayoutManager(mLayoutManager);
rec.setItemAnimator(new DefaultItemAnimator());
rec.setAdapter(mAdapter);
mAdapter.notifyDataSetChanged();
return v;
}
#Override
public void setupDialog(Dialog dialog, int style) {
super.setupDialog(dialog, style);
}
public interface onItemSelected {
void SendHashItem(hash hsh);
} }
after clicking on an item in the RecyclerView, i get the item's data here, how to i pass the data from here to the Form Fragment where i instantiated the BottomSheetFragmentDialog?
Here's my activity
protected void onCreate(Bundle savedInstanceState) {
try{
super.onCreate(savedInstanceState);
// Hide the status bar.
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_dashboard);
//initialize
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
viewPager = (ViewPager) findViewById(R.id.viewp);
setupViewPager(viewPager);
title = findViewById(R.id.title);
tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
tabLayout.setSelectedTabIndicatorColor(ContextCompat.getColor(getApplicationContext(), R.color.transparent));
setupTabIcons();
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
View tabView = tab.getCustomView();
// get inflated children Views the icon and the label by their id
TextView tab_label = (TextView) tabView.findViewById(R.id.tab);
// change the label color, by getting the color resource value
tab_label.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimary));
// change the image Resource
// i defined all icons in an array ordered in order of tabs appearances
// call tab.getPosition() to get active tab index.
tab_label.setCompoundDrawablesWithIntrinsicBounds(0, tabIconsActive[tab.getPosition()], 0, 0);
//"#4CAF50");
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
View tabView = tab.getCustomView();
// get inflated children Views the icon and the label by their id
TextView tab_label = (TextView) tabView.findViewById(R.id.tab);
// change the label color, by getting the color resource value
tab_label.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.white));
// change the image Resource
// i defined all icons in an array ordered in order of tabs appearances
// call tab.getPosition() to get active tab index.
tab_label.setCompoundDrawablesWithIntrinsicBounds(0, tabIcons[tab.getPosition()], 0, 0);
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
tabLayout.setScrollPosition(position, 0 , true);
tabLayout.setSelected(true);
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
viewPager.setCurrentItem(0);
tabLayout.getTabAt(0).select();
setToolbarTitle();
}
catch(Exception e){
e.printStackTrace();
}
}
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(new VideoFragment(), "Video");
adapter.addFragment(new ThreeSixtyFragment(), "360");
adapter.addFragment(new FormFragment(), "Form");
adapter.addFragment(new SettingsFragment(), "Settings");
viewPager.setAdapter(adapter);
}
private void setupTabIcons() {
TextView tabThree = (TextView) LayoutInflater.from(this).inflate(R.layout.cust_tab, null);
tabThree.setText("Video");
tabThree.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimary));
tabThree.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.ic_video_red, 0, 0);
tabLayout.getTabAt(0).setCustomView(tabThree);
TextView tabTwo = (TextView) LayoutInflater.from(this).inflate(R.layout.cust_tab, null);
tabTwo.setText("360");
tabTwo.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.ic_360_white, 0, 0);
tabLayout.getTabAt(1).setCustomView(tabTwo);
TextView tabOne = (TextView) LayoutInflater.from(this).inflate(R.layout.cust_tab, null);
tabOne.setText("Form");
tabOne.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.ic_form_white, 0, 0);
tabLayout.getTabAt(2).setCustomView(tabOne);
TextView tabFive = (TextView) LayoutInflater.from(this).inflate(R.layout.cust_tab, null);
tabFive.setText("Settings");
tabFive.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.ic_settings_white, 0, 0);
tabLayout.getTabAt(3).setCustomView(tabFive);
}
#Override
public void onFragmentInteraction(Uri uri) {
}
class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
Both your FormFragment and your formBottomSheet are fragments that live inside the same Activity instance.
Sometimes a Fragment will have "parent" or "child" Fragments, but that is not the case here because your FormFragment uses getActivity().getSupportFragmentManager() to show the bottom sheet, rather than getChildFragmentManager(). This is totally fine, but it's something to keep in mind.
What this means is that the best way for formBottomSheet to "talk to" FormFragment is to instead talk to the Activity and then have the Activity pass that along to FormFragment.
formBottomSheet -> Activity -> FormFragment
Talking to the Activity is pretty easy. You can just call getActivity() and cast it to whatever your Activity's class name is:
mAdapter = new similarContactAdapter(contItems, getActivity().getApplicationContext(), new similarContactAdapter.onItemClickListener() {
#Override
public void onItemClick(hash hsh) {
MyActivity activity = (MyActivity) getActivity();
activity.onHashItem(hsh);
}
});
Inside your Activity, you can use the FragmentManager to get ahold of your FormFragment and then send the message along to it. This relies on the FormFragment either having an id (if you set an android:id attribute on it in XML or if you used replace(R.id.some_id, ...) then you can use the id) or a tag (if you set an android:tag attribute on it in XML or if you used replace(..., "TAG") then you can use the tag).
public void onHashItem(hash hsh) {
FragmentManager fm = getSupportFragmentManager();
// use only one of the two following lines
FormFragment fragment = (FormFragment) fm.findFragmentById(R.id.some_id); // if using id
FormFragment fragment = (FormFragment) fm.findFragmentByTag("TAG"); // if using tag
fragment.onHashItem(hsh);
}
Finally, you can create the onHashItem() method in your FormFragment:
public void onHashItem(hash hsh) {
// do whatever you want
}

Communicating between 2 fragments in a Viewpager - Updating RecyclerView in Fragment B from Fragment A

I'm building a simple stock display app that allows you to fetch stocks of interest (frag A), store them in a TinyDB, and display them in a recyclerView (frag B).
The framework used to work fine - until I decided to incorporate a viewpager and Tablayout host. I cannot get the RecyclerView in Frag B to display new data live. This is because the activity viewpager initializes both fragments at launch, meaning you can't call the onCreateView code again, I believe.
Communicating between two fragments through an Activity has been touched before on this site, but I found the best example to be this one:
(https://github.com/kylejablonski/InterfaceDemo),
which uses two interfaces, one to communicate from Frag A to Activity, and another one to communicate from Activity to Frag B. But I have a serious problem -
Currently, clicking both the "clear portfolio" and "add stock" to portfolio buttons in Frag A result in an empty screen in Frag B, which means something is being called yet new data is not being displayed/associated with the Adapter
Activity (https://github.com/EXJUSTICE/Investr/blob/master/app/src/main/java/com/xu/investo/ViewHolderActivity.java)
public class ViewHolderActivity extends AppCompatActivity implements CommunicateToActivity,CommunicateToFragment{
//Job of ViewHolderActivity is to allow swiping between list and MainFragment/Fragment
TabLayout tablayout;
ViewPager viewPager;
List<HistoricalQuote> historicaldata;
Bundle bundle;
Adapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_holder);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
viewPager =(ViewPager)findViewById(R.id.viewpager);
tablayout= (TabLayout)findViewById(R.id.tabs);
tablayout.setupWithViewPager(viewPager);
setupViewPager(viewPager);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
}
//----------------------- Interface code-----------
#Override
public void communicateup(){
communicatedown();
//call communicate down STRAIGHT, since we call it from mainfrag
}
#Override
public void communicatedown(){
//This line works
ListFragment currentFragment =(ListFragment)adapter.instantiateItem(viewPager,1);
currentFragment.refreshUI();
}
private void setupViewPager(ViewPager viewPager) {
adapter = new Adapter(getSupportFragmentManager());
adapter.addFragment(new MainFragment(), "Add Stock");
adapter.addFragment(new ListFragment(), "Portfolio");
viewPager.setAdapter(adapter);
}
static class Adapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public Adapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
Frag A (MainFragment)
(https://github.com/EXJUSTICE/Investr/blob/master/app/src/main/java/com/xu/investo/MainFragment.java)
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View view =inflater.inflate(R.layout.content_main,container,false);
stocknames = new ArrayList<String>();
stocktickers = new ArrayList<String>();
tinyDB = new TinyDB(getContext());
/*
menu.setDisplayShowHomeEnabled(true);
//menu.setLogo("INSERT LOGO HERE");
menu.setDisplayUseLogoEnabled(true);
menu.setTitle(" Stock Selector");
*/
fetch =(Button) view.findViewById(R.id.fetchBtn);
enterID =(EditText)view.findViewById(R.id.enterID);
display =(TextView)view.findViewById(R.id.display);
mCalendar = Calendar.getInstance();
clear = (Button)view.findViewById(R.id.clearportfolio);
fetch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//TODO all the main page should do is add stocktickers and names to portfolio
//Fetch id and the dates
id =enterID.getText().toString();
/*to = Calendar.getInstance();
from = Calendar.getInstance();
to.setTime(dateto);
from.setTime(datefrom);
*/
FetchXDayData getData = new FetchXDayData();
getData.execute(id);
}
});
clear.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
tinyDB.clear();
recyclerinterface.communicateup();
}
});
return view;
}
//----------------------------INTERFACE CODE
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
recyclerinterface = (CommunicateToActivity) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement RecyclerUpdateInterface");
}
}
///-------End of Oncreate---------------------------------------------------------------
//Called by AsyncTask, moving result to main thread
public void moveResultToUI(Stock result){
this.stock = result;
Toast.makeText(getActivity(),"Stock "+stock.getName()+" successfully added to portofolio",Toast.LENGTH_LONG).show();
//reverse the list of course, stock names and tickrs to portfolio
stocknames.add(stock.getName());
stocktickers.add(stock.getSymbol());
/*DEBUG Test code, Test. 30012017 WORKS
for (int i =0;i<historicaldata.size();i++){
HistoricalQuote current = historicaldata.get(i);
Toast toast = Toast.makeText(this,current.getClose().toString(),Toast.LENGTH_SHORT);
toast.show();
}
*/
//
if (stock != null){
display.setText("Name: "+stock.getName() +"\n"+"Price: "+ stock.getQuote().getPrice()+"\n"+ "Change(%)"+stock.getQuote().getChangeInPercent());
/*SMA = getSMA(10);
decision=checkSimpleCrossover(SMA,stock.getQuote().getPrice().longValue());
decisionView.setText("SMA: " + SMA + "\n"+decision);
*/
tinyDB.putListString("names",stocknames);
tinyDB.putListString("tickers",stocktickers);
//call interface activity comming up to Activity, then down to next fragment
recyclerinterface.communicateup();
}else{
Toast error = Toast.makeText(getActivity(),"Network Problem",Toast.LENGTH_SHORT);
error.show();
}
}
Frag B (ListFragment)
(https://github.com/EXJUSTICE/Investr/blob/master/app/src/main/java/com/xu/investo/ListFragment.java)
public class ListFragment extends Fragment {
private HistoricalQuote[] hisstocks;
private Stock[] stocks;
private RecyclerView recyclerView;
private StockAdapter mAdapter;
public ArrayList<String> stocknames;
public ArrayList<String>stocktickers;
TinyDB tinyDB;
#Override
public void onCreate(Bundle savedInstanceState){
//exists only to set the options menu
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
//fetching arraylists
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.content_list, container, false);
//Convert the arraylist into an array for arrayadapter
stocknames = new ArrayList<String>();
stocktickers = new ArrayList<String>();
tinyDB = new TinyDB(getContext());
stocknames = tinyDB.getListString("names");
stocktickers= tinyDB.getListString("tickers");
if (!stocknames.isEmpty()){
for (int i =0;i<stocknames.size();i++){
Toast toast= Toast.makeText(getActivity(),stocknames.get(i),Toast.LENGTH_SHORT);
toast.show();
}
}
recyclerView = (RecyclerView)view.findViewById(R.id.recylerView);
recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.HORIZONTAL));
//http://stackoverflow.com/questions/24618829/how-to-add-dividers-and-spaces-between-items-in-recyclerview
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.setItemAnimator(new DefaultItemAnimator());
//layoutManager necessary because it positions views on screen, in this case linearly
if (stocknames.isEmpty() ||stocknames ==null){
recyclerView.setVisibility(View.GONE);
}else{
updateUI();
}
return view;
}
public void refreshUI(){
stocknames.clear();
stocktickers.clear();
stocknames = tinyDB.getListString("names");
stocktickers= tinyDB.getListString("tickers");
if (mAdapter == null) {
mAdapter = new StockAdapter(stocknames,stocktickers);
recyclerView.setAdapter(mAdapter);
} else {
recyclerView.invalidate();
mAdapter.notifyDataSetChanged();
}
}
public void updateUI() {
//updateUI must be called EXPLICITLY!
stocknames = tinyDB.getListString("names");
stocktickers= tinyDB.getListString("tickers");
if (mAdapter == null) {
mAdapter = new StockAdapter(stocknames,stocktickers);
recyclerView.setAdapter(mAdapter);
} else {
mAdapter.notifyDataSetChanged();
}
}
private class StockAdapter extends RecyclerView.Adapter<StockHolder>{
private ArrayList<String>stocknames;
private ArrayList<String>stocktickers;
public StockAdapter(ArrayList<String>names,ArrayList<String> tickers){
this.stocknames=names;
this.stocktickers=tickers;
}
#Override
public StockHolder onCreateViewHolder(ViewGroup parent, int viewType){
LayoutInflater layoutinflater = LayoutInflater.from(getActivity());
View view= layoutinflater.inflate(R.layout.row,parent,false);
return new StockHolder (view);
}
//Bind datato stockholder depending on position in arraylist
public void onBindViewHolder(StockHolder holder, int position){
String stockname = stocknames.get(position);
String stockticker =stocktickers.get(position);
holder.bindStock(stockname,stockticker);
}
#Override
public int getItemCount (){
return stocknames.size();
}
}
private class StockHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
private String stockname;
private String stockticker;
private TextView nametextView;
private TextView tickertextView;
public StockHolder(View itemView){
super(itemView);
itemView.setOnClickListener(this);
nametextView =(TextView)itemView.findViewById(R.id.name);
tickertextView= (TextView)itemView.findViewById(R.id.ticker);
}
#Override
public void onClick(View v){
Intent launchGraph= new Intent(v.getContext(),GraphActivity.class);
launchGraph.putExtra("stockticker",stockticker);
launchGraph.putExtra("stockname",stockname);
startActivity(launchGraph);
//Animations?
}
//Actual binder method, maybe add a current
public void bindStock(String stocknom, String stocktick){
this.stockname=stocknom;
this.stockticker = stocktick;
nametextView.setText(stockname);
tickertextView.setText(stockticker);
}
}
Thanks in advance.
EDIT: Solved issue by creating a new adapter and linking it to new arraylists pulled from the TinyDB, thereby effectively swapping adapters.
Solved the issue by creating a whole new RecyclerView adapter, to which new arraylist data was binded to, and the whole recyclerview was then set to use this new adapter. All of this was done in a single step from FragA, using interfaces shown in the code in the solution.
Method shown below:
public void refreshUI(){
tinyDB = null;
tinyDB = new TinyDB(getContext());
newnames = tinyDB.getListString("names");
newtickers= tinyDB.getListString("tickers");
mAdapter = new StockAdapter(newnames,newtickers);
recyclerView.setAdapter(mAdapter);
}

Fragment in ViewPager is not displaying anything in its RecyclerView on rotation

I have 4 Fragments in a ViewPager that is integrated with a TabLayout. Each of those Fragments holds a RecyclerView because I'm displaying an unknown amount of list items. The items are loaded by date, so I have two buttons that let you change days, and then the appropriate data in the list items is loaded based on the date that is set. The buttons are part of the outer activity.
Everything so far works perfectly BUT once I rotate the device the fragments don't load anything. Nothing is displayed inside the Fragments. The views in the outer activity are displayed fine though. The weird thing is that if I touch one of the buttons that changes the date, the Fragments are loaded and the data is displayed correctly. But I need everything to be displayed immediately after rotation not just when I click one of those buttons. Here is my code:
public class MainActivity extends AppCompatActivity implements DatePickerFragment.DateDialogInterface
{
private final static String COLOR_CONTROL_CHOSEN = "color_control_chosen";
private static final String DIALOG_DATE = "dialog_date";
private static final String TAG = "MainActivity";
private static final String SET_LOCATION = "set_location";
public static final String LEAGUE_POSITION = "league_position";
private Toolbar mToolbar;
private ViewPager mViewPager;
private TabLayout mTabLayout;
private ImageButton mPrevDateButton, mNextDateButton;
private TextView mDateTextView, mLeagueTextView;
private String mTodaysDate;
private Date mLastSelectedDate, mTodaysDateObj;
private ProgressBar mProgressBar;
private FragmentPagerAdapter mAdapterViewPager;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mToolbar = (Toolbar) findViewById(R.id.outnix_toolbar);
mViewPager = (ViewPager) findViewById(R.id.main_activity_view_pager);
mTabLayout = (TabLayout) findViewById(R.id.main_activity_tab_layout);
mDateTextView = (TextView) findViewById(R.id.display_date_text_view);
mLeagueTextView = (TextView) findViewById(R.id.league_title_header);
mPrevDateButton = (ImageButton) findViewById(R.id.previous_date_button);
mNextDateButton = (ImageButton) findViewById(R.id.next_date_button);
mProgressBar = (ProgressBar) findViewById(R.id.loading_circle);
mProgressBar.setVisibility(View.GONE);
setTodaysDate();
mDateTextView.setText("Today");
setSupportActionBar(mToolbar);
assert getSupportActionBar() != null;
getSupportActionBar().setDisplayShowTitleEnabled(false);
NavDrawerFragment navDrawerFrag = (NavDrawerFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_nav_drawer);
navDrawerFrag.setUp((DrawerLayout) findViewById(R.id.nav_drawer), mToolbar);
setUpViewPagerAdapterOnCreate();
mTabLayout.setupWithViewPager(mViewPager);
mDateTextView.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
FragmentManager fm = getSupportFragmentManager();
DatePickerFragment dialog = new DatePickerFragment();
Bundle args = new Bundle();
args.putSerializable("ARG_DATE", mLastSelectedDate);
dialog.setArguments(args);
dialog.show(fm, DIALOG_DATE);
}
});
THESE TWO LISTENERS ARE WHAT DISPLAY THE DATA AFTER A ROTATION CHANGE
//////////////////////////////////////////////////////////////////
mPrevDateButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
{
mProgressBar.setVisibility(View.VISIBLE);
updateDate(-1);
setupViewPagerAdapter(getViewPagerPos());
}
});
mNextDateButton.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
mProgressBar.setVisibility(View.VISIBLE);
updateDate(1);
setupViewPagerAdapter(getViewPagerPos());
}
});
}
////////////////////////////////////////////////////////////////////
/* #Override
protected void onResume()
{
super.onResume();
setupViewPagerAdapter(getViewPagerPos());
}*/
private void setUpViewPagerAdapterOnCreate() //only called when opened from LauncherActivity
{
setupViewPagerAdapter(0);
int touchColorPixel = getIntent().getIntExtra(COLOR_CONTROL_CHOSEN, ContextCompat.getColor(this, R.color.blue));
if(touchColorPixel == ContextCompat.getColor(this, R.color.orange))
mViewPager.setCurrentItem(0);
else if(touchColorPixel == ContextCompat.getColor(this, R.color.blue))
mViewPager.setCurrentItem(1);
else
mViewPager.setCurrentItem(3);
}
private void setupViewPagerAdapter(int currentPos)
{
mAdapterViewPager = new MainPagerAdapter(getSupportFragmentManager());
mViewPager.setAdapter(mAdapterViewPager);
mViewPager.setOffscreenPageLimit(4);
mViewPager.setCurrentItem(currentPos);
}
#Override
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putSerializable(DIALOG_DATE, mLastSelectedDate); //save the last date selected (or last date displayed) on rotation change.
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
setDateFromDialog((Date) savedInstanceState.getSerializable(DIALOG_DATE)); //restore the last date selected to the new rotation change
}
public ProgressBar getProgressBar()
{
return mProgressBar;
}
#Override
public void setDateFromDialog(Date date)
{
String newDate = getFormattedDate(date);
updateTodaysDate();
mLastSelectedDate = date;
setupViewPagerAdapter(getViewPagerPos());
if(newDate.equals(mTodaysDate))
mDateTextView.setText("Today");
else
mDateTextView.setText(newDate);
}
private int getViewPagerPos()
{
return mViewPager.getCurrentItem();
}
}
The 2 buttons mPrevDateButton and mNextDateButtonare the buttons that when clicked "fix" the problem. Inside their click listeners, the updateDate() method is only doing stuff related to a TextView object and is why I didn't include the definitions (I'm trying to keep the post as short as possible). So I know for sure it has something to do with my setupViewPagerAdapter() method. I've tried adding this method in onCreate() and onResume() but the Fragments still stay blank.
Here is my ViewPager adapter code:
public class MainPagerAdapter extends FragmentPagerAdapter
{
private final String[] mFragmentTitleList = {"My Games", "All Games", "All Places", "My Places"}; //tab title names
private final static int NUM_FRAGMENTS = 4;
public MainPagerAdapter(FragmentManager fm)
{
super(fm);
}
#Override
public Fragment getItem(int position)
{
switch(position)
{
case 0:
return MyGamesFragment.newInstance();
case 1:
return AllGamesFragment.newInstance();
case 2:
return AllPlacesFragment.newInstance();
case 3:
return MyPlacesFragment.newInstance();
default:
return null;
}
}
#Override
public int getCount()
{
return NUM_FRAGMENTS;
}
#Override
public CharSequence getPageTitle(int position)
{
return mFragmentTitleList[position];
}
}
Here is one of the 4 fragments. They pretty much all have similar design.
public class AllGamesFragment extends Fragment
{
private SwipeRefreshLayout mSwipeRefreshLayout;
private RecyclerView mAllGamesRecyclerView;
private GameAdapter mGameAdapter;
private List<Game> mGameList = new ArrayList<>();
private MainActivity mMainActivity; //keeps a reference to MainActivity to access public methods
public static AllGamesFragment newInstance()
{
return new AllGamesFragment();
}
#Override
public void onAttach(Context context)
{
super.onAttach(context);
mMainActivity = (MainActivity) context;
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setRetainInstance(true);
mMainActivity.getProgressBar().setVisibility(View.VISIBLE);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.recycler_view_all_games, container, false);
mAllGamesRecyclerView = (RecyclerView) view.findViewById(R.id.all_games_recycler_view);
mAllGamesRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe_refresh);
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener()
{
#Override
public void onRefresh()
{
getGamesData();
mSwipeRefreshLayout.setRefreshing(false);
}
});
return view;
}
#Override
public void onResume()
{
super.onResume();
getGamesData();
}
private void setupAdapter()
{
if(isAdded())
{
mGameAdapter = new GameAdapter(mGameList);
mAllGamesRecyclerView.setAdapter(mGameAdapter);
}
}
private void getGamesData()
{
new GetDataTask(mMainActivity.getLastSelectedDate()).execute();
}
private class GetDataTask extends Scraper.GameDataTask
{
GetDataTask(Date date)
{
super(date, getActivity());
}
#Override
protected void onPostExecute(List<Game> games)
{
mGameList = games;
setupAdapter();
mMainActivity.getProgressBar().setVisibility(View.GONE);
}
}
private class GameAdapter extends RecyclerView.Adapter<GameHolder>
{
private List<Game> mGames;
public GameAdapter(List<Game> games)
{
mGames = games;
}
#Override
public GameHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
LayoutInflater inflater = LayoutInflater.from(getActivity());
View view = inflater.inflate(R.layout.list_game_item, parent, false);
return new GameHolder(view, getActivity());
}
#Override
public void onBindViewHolder(GameHolder holder, int position)
{
holder.bindGameData(mGames.get(position));
}
#Override
public int getItemCount()
{
return mGames.size();
}
}
I've looked at so many posts on here, changed my code many times and I still can't get it to work. I'm just baffled that it "fixes" when I click one of the date buttons. If you would like me to post more code of something let me know. Sorry for the long post but I feel the context is needed. I really appreciate any help!
I figured it out! I had to switch to a FragmentStatePagerAdapter rather than use a FragmentPagerAdapter. I believe it has something to do with the Fragments being destroyed and recreated again.
I also read that another way would be to wrap the ViewPager in a Fragment and when you create its adapter you use getChildFragmentManager() rather than getSupportFragmentManager() like this:
mAdapterViewPager = new MyPagerAdapter(getChildFragmentManager());
I didn't want to have to add an entire Fragment around my ViewPager just to fix this issue so I switched to using FragmentStatePagerAdapter and it worked! Hope this helps someone else out there.
Making viewPager adapter extends FragmentStatePagerAdapter and not FragmentPagerAdapter should solve the problem.

Sliding Tabs to load XML Data using RecyclerView Adapter is not displaying content properly

I have been working on an app to take the blog feed and parse and display it in the app using the Recycler and Card View. I got to the point of adding sliding tabs to display articles in each of the categories in the site in separate tabs. I parse the feed using the category URL and am able to display it using the same Recycler view adapter.
Here comes the problem, as I swipe through the tabs quickly, the content doesn't load in some cases. In some cases, I get articles from one category displayed in another category's tab.
Below is the code for my Tabs fragment:
public class TabsFragment extends Fragment {
ViewPager mViewPager;
ViewPagerAdapter mAdapter;
SlidingTabLayout mSlidingTabLayout;
CharSequence Titles[] = {"Home", "Events", "Category", "Bookmarks", "News"};
int NoOfTabs = 5;
private ProgressBar mProgressBar;
private RecyclerView mRecyclerView;
private MyRecyclerViewAdapter myRecyclerViewAdapter;
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.activity_tabs, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
mAdapter = new ViewPagerAdapter(Titles, NoOfTabs);
mProgressBar = (ProgressBar) view.findViewById(R.id.loading_spinner);
mViewPager = (ViewPager) view.findViewById(R.id.pager);
mViewPager.setAdapter(mAdapter);
mSlidingTabLayout = (SlidingTabLayout) view.findViewById(R.id.tabs);
mSlidingTabLayout.setCustomTabColorizer(new SlidingTabLayout.TabColorizer() {
#Override
public int getIndicatorColor(int position) {
return getResources().getColor(R.color.secondaryBackgroundColor);
}
#Override
public int getDividerColor(int position) {
return getResources().getColor(R.color.secondaryBackgroundColor);
}
});
mSlidingTabLayout.setViewPager(mViewPager);
}
public class ViewPagerAdapter extends PagerAdapter {
CharSequence mTitles[];
int mNoOfTabs;
public ViewPagerAdapter(CharSequence[] titles, int noOfTabs) {
mTitles = titles;
mNoOfTabs = noOfTabs;
}
public CharSequence getPageTitle(int position) {
return mTitles[position];
}
#Override
public int getCount() {
return mNoOfTabs;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
View view = getActivity().getLayoutInflater().inflate(R.layout.pager_item_articles,
container, false);
container.addView(view);
ProcessArticles processArticles;
processArticles = new ProcessArticles(null, mTitles[position]);
processArticles.execute();
mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity().getApplicationContext()));
myRecyclerViewAdapter = new MyRecyclerViewAdapter(new ArrayList<Article>(),
getActivity().getApplicationContext());
mRecyclerView.setAdapter(myRecyclerViewAdapter);
return view;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
#Override
public boolean isViewFromObject(View view, Object object) {
return object == view;
}
}
public class ProcessArticles extends GetXmlData {
public ProcessArticles(String searchCriteria, String category) {
super(searchCriteria, category);
}
#Override
public void execute() {
super.execute();
ProcessData processData = new ProcessData();
processData.execute();
}
public class ProcessData extends DownloadXmlData {
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
ParseArticles parseArticles = new ParseArticles(getData());
boolean operationStatus = parseArticles.process();
if (operationStatus) {
ArrayList<Article> allArticles = parseArticles.getArticles();
myRecyclerViewAdapter.loadNewData(allArticles);
} else {
Toast.makeText(getActivity().getApplicationContext(), "Error establishing correction.", Toast.LENGTH_SHORT).show();
Log.d("MainActivity", "Error establishing correction.");
}
}
}
}
}
The code for the activity displaying the tabs is:
public class TabsActivity extends BaseActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_tabs);
activateToolbarWithHomeEnabled();
if (savedInstanceState == null) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
TabsFragment fragment = new TabsFragment();
transaction.replace(R.id.tab_content_frame, fragment);
transaction.commit();
}
}
}
How do I separate the content according to category in the tabs? I have tried to reduce the amount of code, so, I have used the same Recycler adapter. Is there any solution to this problem? Or should I change the method of implementation? I am looking to implement something like the Play Newsstand app.

Categories

Resources