bundle.getParcelableArrayList() returning null

Jayson Meribe :

I am trying to pull an ArrayList of Candle Entries from a bundle. But after receiving an out of bounds exception I had realized that my returned array was empty. I am very new to Android programming and still trying to figure things out. Thanks

Here is my code with how I get my data and me placing the data into a bundle: package com.example.bullfinance;

import android.nfc.Tag;
import android.os.Bundle;
import android.util.Log;

import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.github.mikephil.charting.data.CandleEntry;
import com.google.android.material.bottomnavigation.BottomNavigationView;

import androidx.appcompat.app.AppCompatActivity;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.NavigationUI;
import androidx.appcompat.widget.Toolbar;
import androidx.appcompat.app.ActionBar;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;


public class stockinfo extends AppCompatActivity {

    public String url = "";
    public Bundle bundle;
    public String tickerSymbol;




    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_stockinfo);
        BottomNavigationView navView = findViewById(R.id.nav_view);
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
       /* AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
                R.id.navigation_home, R.id.navigation_News, R.id.navigation_PatternIndicators, R.id.navigation_SpecialStats)
                .build();*/
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        //NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
        NavigationUI.setupWithNavController(navView, navController);

        bundle = getIntent().getExtras();
        tickerSymbol = bundle.getString("STOCKTICKER");



        setToolBarTitle();
        PutChartData();




    }

    public void setToolBarTitle()
    {
        Toolbar toolbar = findViewById(R.id.toolbar);

        setSupportActionBar(toolbar);

        ActionBar theToolbar = getSupportActionBar();

        theToolbar.setDisplayHomeAsUpEnabled(true);

        url = "https://financialmodelingprep.com/api/v3/company/profile/" + this.getIntent().getExtras().getString("STOCKTICKER");

        JsonObjectRequest toolBarTitleRequest = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                try
                {
                    ActionBar nameRequestToolbar = getSupportActionBar();

                    JSONObject myJsonObject = response.getJSONObject("profile");

                    nameRequestToolbar.setTitle(myJsonObject.getString("companyName"));

                } catch (JSONException e) {
                    e.printStackTrace();
                }

            }
        }, new Response.ErrorListener() {

            @Override
            public void onErrorResponse(VolleyError error) {

            }
        });

        NetworkBridge.getInstance(this).addToRequestQueue(toolBarTitleRequest);
    }

    public void PutChartData()
    {
        String chartUrl = "https://financialmodelingprep.com/api/v3/historical-price-full/"+ this.getIntent().getExtras().getString("STOCKTICKER") + "?from=0000-00-00&to=" + GetCurrentDate();

        Log.w("StockInfoActivity", chartUrl);

        JsonObjectRequest chartDataRequest = new JsonObjectRequest(Request.Method.GET, chartUrl, null, new Response.Listener<JSONObject>() {

            ArrayList<CandleEntry> candleData = new ArrayList<CandleEntry>();

            @Override
            public void onResponse(JSONObject response) {
                try {
                    JSONArray historicalArray = response.getJSONArray("historical");

                    for(int i = 0; i  < historicalArray.length(); i++)
                    {
                        candleData.add(new CandleEntry(i, historicalArray.getJSONObject(i).getInt("high"), historicalArray.getJSONObject(i).getInt("low"), historicalArray.getJSONObject(i).getInt("open"), historicalArray.getJSONObject(i).getInt("close")));
                    }

                    bundle.putParcelableArrayList("ChartRawData" ,candleData);

                } catch (JSONException e) {
                    e.printStackTrace();
                }

            }
        }, new Response.ErrorListener() {

            @Override
            public void onErrorResponse(VolleyError error) {

            }
        });

        NetworkBridge.getInstance(this).addToRequestQueue(chartDataRequest);
    }

    public String GetCurrentDate()
    {
        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
        return dateFormat.format(calendar.getTime());
    }

}

Here is my code where I try to pull the ArrayList:

package com.example.bullfinance.ui.home;

import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ScrollView;
import android.widget.TextView;

import androidx.annotation.Nullable;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;

import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.example.bullfinance.NetworkBridge;
import com.example.bullfinance.R;
import com.example.bullfinance.stockinfo;
import com.github.mikephil.charting.animation.Easing;
import com.github.mikephil.charting.charts.CandleStickChart;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.CandleData;
import com.github.mikephil.charting.data.CandleDataSet;
import com.github.mikephil.charting.data.CandleEntry;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.highlight.ChartHighlighter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.dataprovider.BarLineScatterCandleBubbleDataProvider;
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;


import android.os.Handler;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.Set;

public class HomeFragment extends Fragment {


    public TextView thePrice;

    public Bundle bundle;

    public String tickerSymbol;

    public String url;

    public String chartUrl;

    static public CandleStickChart theChart;

    Handler handler = new Handler();

    public Button todayBTN, fiveDayBTN, twoWeeksBTN, monthBTN, sixMonthBTN, lstQtrBTN, oneYearBTN, ytdBtn, allTimeBTN;

    public Button intOneDayBTN, intFiveDayBTN, intMonthBTN, intSixMonthBTN, intOneYearBTN;

    public Button selectedTimeFrameBTN;

    public Button selectedIntervalBTN;

    public ScrollView intervalScrollView;

    public ArrayList<CandleEntry> candleEntries = new ArrayList<CandleEntry>();


    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View root = inflater.inflate(R.layout.fragment_home, container, false);

        thePrice = (TextView) root.findViewById(R.id.priceText);

        theChart = root.findViewById(R.id.chart);

        bundle = getActivity().getIntent().getExtras();

        tickerSymbol = bundle.getString("STOCKTICKER");

        url = "https://financialmodelingprep.com/api/v3/stock/real-time-price/" + tickerSymbol;

        candleEntries = bundle.getParcelableArrayList("ChartRawData");


        todayBTN = root.findViewById(R.id.todaybtn);
        fiveDayBTN = root.findViewById(R.id.fivedaybtn);
        twoWeeksBTN = root.findViewById(R.id.monthbtn);
        monthBTN = root.findViewById(R.id.monthbtn);
        sixMonthBTN = root.findViewById(R.id.sixmonthbtn);
        lstQtrBTN = root.findViewById(R.id.lstqtrBtn);
        oneYearBTN = root.findViewById(R.id.oneyearbtn);
        ytdBtn = root.findViewById(R.id.ytdbtn);
        allTimeBTN = root.findViewById(R.id.alltimebtn);


        intOneDayBTN = root.findViewById(R.id.intonedaybtn);
        intFiveDayBTN = root.findViewById(R.id.intfivedaybtn);
        intMonthBTN = root.findViewById(R.id.intmonthbtn);
        intSixMonthBTN = root.findViewById(R.id.intsixmonthbtn);
        intOneYearBTN = root.findViewById(R.id.intoneyearbtn);

        //intervalScrollView = root.findViewById(R.id.intervalScrollView);

        SetStockPrice();
        handler.postDelayed(periodicUpdate, 5 * 1000);

        theChart.setTouchEnabled(true);
        theChart.setDragEnabled(true);
        theChart.setScaleEnabled(true);
        theChart.setPinchZoom(true);
        theChart.setDoubleTapToZoomEnabled(true);
        theChart.getDescription().setEnabled(false);
        theChart.setHighlightPerDragEnabled(true);

        theChart.animateXY(3000, 3000);

        MakeCandleStockChart();

        return root;

    }


    public void SetStockPrice() {


        JsonObjectRequest getStockPriceRequest = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {

            Double thePriceObt;

            @Override
            public void onResponse(JSONObject response) {
                try {
                    thePriceObt = response.getDouble("price");

                    thePrice.setText(thePriceObt.toString());

                } catch (JSONException e) {
                    e.printStackTrace();
                }

            }
        }, new Response.ErrorListener() {

            @Override
            public void onErrorResponse(VolleyError error) {

            }
        });

        NetworkBridge.getInstance(getContext()).addToRequestQueue(getStockPriceRequest);
    }

    Runnable periodicUpdate = new Runnable() {
        @Override
        public void run() {
            handler.postDelayed(periodicUpdate, 4 * 1000);

            SetStockPrice();
        }
    };

    public void MakeCandleStockChart() {

        CandleDataSet chartSet = new CandleDataSet(candleEntries, tickerSymbol);

        chartSet.setDrawIcons(false);
        chartSet.setAxisDependency(YAxis.AxisDependency.LEFT);
        chartSet.setShadowColor(Color.BLACK);
        chartSet.setShadowWidth(0.7f);
        chartSet.setDecreasingColor(Color.RED);
        chartSet.setDecreasingPaintStyle(Paint.Style.FILL);
        chartSet.setIncreasingColor(Color.rgb(122, 242, 84));
        chartSet.setIncreasingPaintStyle(Paint.Style.FILL);
        chartSet.setNeutralColor(Color.BLUE);
        chartSet.setHighlightEnabled(true);
        chartSet.setHighLightColor(Color.BLACK);

        CandleData data = new CandleData(chartSet);

        theChart.setData(data);

        theChart.invalidate();

    }

}
Wojciech Januszek :

The problem is most probably not how you are trying to put the data into the Bundle but in when you're trying to read it.

The code snippet which you've posted doesn't show how you add the HomeFragment to the Activity but my guess is that it is done in the .xml layout.

It means that the Fragment is added to the Activity in its onCreate() callback. Then, the Fragment's onCreateView() is called trying to get the ParcelableArray which is null at this time. After those operations, the HTTP call in your Activity finishes and the onResponse() is called and the data is added to the bundle.


If you want to check my theory, place a debugger breakpoint in the onResponse() in PutChartData() and in Fragment's onCreateView(). I bet that onCreateView() is called first.


The way to fix this, is realising that the HTTP requests made with the Volley library (and majority of other Android network libraries) are asynchronous - they don't block the main thread but are executed in a separate one and after performing the long-running tasks they return the result to the main thread via onResponse() callback.

You should use this callback to "inform" the interested parts of the application about the results of your network call. In your case, the simplest solution should probably be:

1) Removing the MakeCandleStokChart() call from the onCreateView()

2) In the PutChartData's onResponse(), you should find your Fragment using FragmentManager (check this thread) and set the candleEntries in it and then invoke MakeCandleStokChart(). It will be something like:

HomeFragment fragment = (HomeFragment) supportFragmentManager.findFragmentById(R.id.replaceWithYourFragmentId);
fragment.candleEntries = candleData;
fragment.MakeCandleStokChart();

Keep in mind that the solution above is not the best pattern overall but it should help you understand how some things work.

You could read more about making the asynchronous requests in the docs (there are Lessons at the bottom). About the Fragment<->Activity communication check this documentation page.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=34634&siteId=1