NappyXIII
NappyXIII

Reputation: 305

onCreateView not called before method of fragment runs

Not sure what I'm missing here, but I create a fragment and add it using FragmentManager. Soon after, I run a method from that fragment which is supposed to load information provided (a Tool object) into the layout.

In InfoActivity.java:

public class InfoActivity extends AppCompatActivity{

...

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mCatIndex = getIntent().getExtras().getInt("catIndex", 0);
    mToolIndex = getIntent().getExtras().getInt("toolIndex", 0);

    // If we are in two-pane layout mode, this activity is no longer necessary
    if (getResources().getBoolean(R.bool.has_two_panes)) {
        finish();
        return;
    }

    // Place an InfoFragment as our content pane
    InfoFragment f = new InfoFragment();
    getSupportFragmentManager().beginTransaction().add(android.R.id.content, f).commit();

    // Display the correct tool info on the fragment
    Tool tool = ToolsSource.getInstance(this).getCategory(mCatIndex).getTool(mToolIndex);
    f.displayTool(tool);
}
}

However, the layout objects are not initialized because somehow the method is running before the view is created.

package com.anothergamedesigner.listviewtest;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class InfoFragment extends Fragment {

private TextView mTitle;
private TextView mSubtitle;
private TextView mDescription;

//Tool to be displayed
Tool mTool = null;

//Parameterless constructor needed for framework
public InfoFragment(){
    super();
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.info_layout, container, false);

    mTitle = (TextView) view.findViewById(R.id.title);
    mSubtitle = (TextView) view.findViewById(R.id.subtitle);
    mDescription = (TextView) view.findViewById(R.id.description);

    loadView();
    return view;
}

public void displayTool(Tool t){
    mTool = t;
    loadView();
}

private void loadView(){
   if(mTool != null) {
       System.out.println(mTitle.getText()); <----- error here so it's for sure the TextView returning null.
       System.out.println(mTool.getTitleTxt());
       mTitle.setText(mTool.getTitleTxt());
       mSubtitle.setText(mTool.getSubtitleTxt());
       mDescription.setText(mTool.getDescriptionTxt());

   }
}
}

Upvotes: 0

Views: 5605

Answers (3)

Jaythaking
Jaythaking

Reputation: 2102

You call f.displayTool(tool) on your onCreate method of the activity after having done the fragment transaction...So your if(mTool != null) equals null... Try initializing the tool just after creating the fragment.

 public void initTool(Tool t){
    mTool = t;
}

In the Activity:

InfoFragment f = new InfoFragment();
// Display the correct tool info on the fragment
Tool tool = ToolsSource.getInstance(this).getCategory(mCatIndex).getTool(mToolIndex);
    f.initTool(tool);
    getSupportFragmentManager().beginTransaction().add(android.R.id.content, f).commit();

f.displayTool(tool);

Upvotes: 0

Karakuri
Karakuri

Reputation: 38585

The majority of UI-related things on Android are asynchronous, including fragment transactions. Basically UI changes happen periodically in a run loop. Here are some ways to handle this:

Option 1: Store the data when you call the public setter method. Then, if the view has been created, make the UI changes immediately; otherwise, wait until onViewCreated().

private Tool mTool;

@Override
public void onViewCreated(View view,Bundle savedInstanceState) {
    // obtain view references
    if (mTool != null) {
        updateDisplay();
    }
}

public void setTool(Tool tool) {
    mTool = tool;
    if (getView() != null) {
        updateDisplay();
    }
}

private void updateDisplay() {
    // change UI here
}

Option 2: Pass the Tool as an argument to your fragment. This requires you make the Tool Parcelable so that it can be placed inside a Bundle. If that's not possible, you could instead give some identifier of the Tool and make the fragment capable of retrieving the Tool based on this identifier (e.g. looking it up in a database).

This is typically done with the following pattern (assuming you can make the Tool Parcelable):

public static InfoFragment newInstance(Tool tool)  {
    InfoFragment fragment = new InfoFragment();
    Bundle args = new Bundle();
    args.putParcelable("arg_tool", tool);
    fragment.setArguments(args);
    return fragment;
}

private Tool mTool;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Bundle args = getArguments();
    mTool = args.getParcelable("arg_tool");
}

@Override
public void onViewCreated(View view,Bundle savedInstanceState) {
    // obtain view references
    if (mTool != null) {
        updateDisplay();
    }
}

Then in your activity you would call newInstance() passing the Tool instead of calling the constructor. The benefit of this second approach is you have the data whenever the views are ready, and the arguments Bundle is persisted by the system, so the data is not lost when you go through a configuration change (e.g. by rotating the device).

Upvotes: 1

Riyaz Ahamed
Riyaz Ahamed

Reputation: 802

Instead of asking fragment to show the data try this. Ask the activity to provide data. If its confusing please read ahead,

Define a callback in the fragment. And implement it in the activity. Now after onCreateView in fragment call the interface method to display. You have the activity reference inside fragment which can be casted to callback.

You can follow the following doc to create interface callbacks for fragment. https://developer.android.com/training/basics/fragments/communicating.html

Upvotes: 0

Related Questions