Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Android

Member Variable not initializing in MainActivity.java due to not waiting to finish a method. Help

I have almost completed the Android Dev, track so I decided to make a simple sports app in a similar method as the weather app. However in my MainActivity.java it seems like my member variable is not initializing.

    public class MainActivity extends AppCompatActivity {

    private List<Game> gameList;
    private NBA mNBA= new NBA();
    public static final String TAG = MainActivity.class.getSimpleName();
    public static final String mScoreboardUrl = "http://data.nba.com/5s/json/cms/noseason/scoreboard/20160116/games.json";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.content_main);
        RecyclerView recList = (RecyclerView) findViewById(R.id.cardList);
        recList.setHasFixedSize(true);
        LinearLayoutManager llm = new LinearLayoutManager(this);
        llm.setOrientation(LinearLayoutManager.VERTICAL);
        recList.setLayoutManager(llm);
        setUpGames();
        Log.i(TAG, "is it empty main thread " + mNBA.getGameList().size());

        GameAdapter ca = new GameAdapter(mNBA.getGameList());
        recList.setAdapter(ca);
    }



    private void setUpGames() {
        if (isNetworkAvailable()) {
            OkHttpClient client = new OkHttpClient();
            Request request = new Request.Builder().url(mScoreboardUrl).build();
            Call call = client.newCall(request);
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Request request, IOException e) {
                    alertUserAboutError();
                }

                @Override
                public void onResponse(Response response) throws IOException {
                    try {
                        String jsonData = response.body().string();
                        if (response.isSuccessful()) {
                            mNBA = parseNBADetails(jsonData);
                            Log.i(TAG, "is it empty 3 " + mNBA.getGameList().size());
                        } else {
                            alertUserAboutError();
                        }
                    } catch (IOException e) {
                    } catch (JSONException j) {
                    }
                }
            });
        } else {
            Toast.makeText(this, getString(R.string.network_unavailable_message),
                    Toast.LENGTH_LONG).show();
        }
    }


    private void alertUserAboutError() {
        AlertDialogFragment dialog = new AlertDialogFragment();
        dialog.show(getFragmentManager(), "error_dialog");
    }

    private boolean isNetworkAvailable() {
        ConnectivityManager manager = (ConnectivityManager)
                getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = manager.getActiveNetworkInfo();
        boolean isAvailable = false;
        if (networkInfo != null && networkInfo.isConnected()) {
            isAvailable = true;
        }

        return isAvailable;

    }

    private NBA parseNBADetails(String jsonData) throws JSONException {

        NBA nba = new NBA();
        nba.setGameList(parseGames(jsonData));

        Log.i(TAG, "is it empty 2 " + nba.getGameList().size());
        return nba;
    }

    private List<Game> parseGames(String jsonData) throws JSONException {
        JSONObject sports_content = new JSONObject(jsonData);
        JSONObject schedule = sports_content.getJSONObject("sports_content");
        JSONObject gameArray = schedule.getJSONObject("games");
        JSONArray data = gameArray.getJSONArray("game");

        List<Game> gameList = new ArrayList<Game>();
        for (int i = 0; i < data.length(); i++) {
            Game game = new Game();
            JSONObject jsonGame = data.getJSONObject(i);

            JSONObject jsonVisitor = jsonGame.getJSONObject("visitor");
            game.setVisitorTeamName(jsonVisitor.getString("nickname"));
            game.setVisitorScore(jsonVisitor.getInt("score"));
            game.setVisitorTeamLocation(jsonVisitor.getString("city"));

            JSONObject jsonHome = jsonGame.getJSONObject("home");
            game.setHomeTeamLocation(jsonHome.getString("city"));
            game.setHomeTeamName(jsonHome.getString("nickname"));
            game.setHomeScore(jsonHome.getInt("score"));

            Log.i(TAG, game.getHomeScore() + "");

            gameList.add(game);
        }
        return gameList;
    }
    }

By examining the Logs

01-17 14:48:56.479 17906-17906/com.brokenbroadcast.nba_project I/MainActivity: is it empty main thread 0
        01-17 14:48:56.927 17906-17936/com.brokenbroadcast.nba_project I/MainActivity: 92
        01-17 14:48:56.927 17906-17936/com.brokenbroadcast.nba_project I/MainActivity: 114
        01-17 14:48:56.927 17906-17936/com.brokenbroadcast.nba_project I/MainActivity: 117
        01-17 14:48:56.927 17906-17936/com.brokenbroadcast.nba_project I/MainActivity: 113
        01-17 14:48:56.927 17906-17936/com.brokenbroadcast.nba_project I/MainActivity: 114
        01-17 14:48:56.927 17906-17936/com.brokenbroadcast.nba_project I/MainActivity: 103
        01-17 14:48:56.927 17906-17936/com.brokenbroadcast.nba_project I/MainActivity: 109
        01-17 14:48:56.927 17906-17936/com.brokenbroadcast.nba_project I/MainActivity: 103
        01-17 14:48:56.930 17906-17936/com.brokenbroadcast.nba_project I/MainActivity: is it empty 2 8
        01-17 14:48:56.930 17906-17936/com.brokenbroadcast.nba_project I/MainActivity: is it empty 3 8

It seems like the Logs are running in a different order. The first Log should not appear until the end. It seems like my program is not waiting until it finish setUpGames() to retrieve the GameList to mNBA before running on to GameAdapter. Does anyone know how I can fix this? I've never encountered this problem before and I have no idea how I should approach this. Thank you

  • I was able to get this to work if I hardcode a List<Game>, so I am pretty sure there is no problem with my adapters and recyclerView. Any will be appreciated, thank you.

3 Answers

Ben Deitch
STAFF
Ben Deitch
Treehouse Teacher

Move everything after 'setupGames' into 'onResponse'; the network call happens on a separate thread and isn't finished until 'onResponse'.

Would this be a good example of using asynctask? Also, should setUpGames then take recyclerView as a parameter?

Ben Deitch
Ben Deitch
Treehouse Teacher

Would this be a good example of using asynctask?

Basically. Okhttp is definitely doing the network stuff on a separate thread. Though, they could achieve this without using an asynctask.

Should setUpGames then take recyclerView as a parameter?

Sure, why not? :) There's a bunch of ways you could refactor this and there's not always a clear best choice, but that sounds fine to me.

What else can I do so that I can ensure that my UI thread and OkHttp thread is in sync? I would prefer my setUpGames() to not take in any parameters so that when I'm writing codes to refresh I would not have to constantly pass recyclerview as a parameter.

Ben Deitch
Ben Deitch
Treehouse Teacher

Make the RecyclerView a field.

would it be possible to wait until callback to finish before setting the adapter in my Oncreate() method? That would be ideal for me. Also why was this not a problem with the weather app we had?

Ben Deitch
Ben Deitch
Treehouse Teacher

It might be possible, but it's not a good idea. We use a separate thread for network operations so that we don't block the main thread. Waiting until the callback finishes inside onCreate would be taking a step backwards (because it would block the main thread).

Without digging more into it, I'm not sure why this wasn't a problem with the weather app.