0

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.

A.Xu
  • 121
  • 14

1 Answers1

0

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);


}
A.Xu
  • 121
  • 14