J'ai une BlankFragment
package com.hfad.addingafragmenttoframelayout;
import Android.os.Bundle;
import Android.support.v4.app.Fragment;
import Android.util.Log;
import Android.view.LayoutInflater;
import Android.view.View;
import Android.view.ViewGroup;
import Android.widget.TextView;
import org.w3c.dom.Text;
/**
* A simple {@link Fragment} subclass.
*/
public class BlankFragment extends Fragment {
public BlankFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d("message","onCreateView() of BlankFragment");
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_blank, container, false);
}
public void setText(String textToBeSet){
TextView tv = (TextView)this.getView().findViewById(R.id.fragmentText);
tv.setText(textToBeSet);
}
}
et sa mise en page est:
<FrameLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:tools="http://schemas.Android.com/tools"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
tools:context="com.hfad.addingafragmenttoframelayout.BlankFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:text="@string/hello_blank_fragment"
Android:id="@+id/fragmentText"/>
</FrameLayout>
Voici la MainActivity
package com.hfad.addingafragmenttoframelayout;
import Android.support.v7.app.AppCompatActivity;
import Android.os.Bundle;
import Android.view.View;
import Android.widget.TextView;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//BlankFragment bf = new BlankFragment();
//getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, bf).commit();
BlankFragment bf = new BlankFragment();
bf.setText("hello world");
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, bf).commit();
}
}
et voici la mise en page de MainActivity
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:tools="http://schemas.Android.com/tools"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:paddingBottom="@dimen/activity_vertical_margin"
Android:paddingLeft="@dimen/activity_horizontal_margin"
Android:paddingRight="@dimen/activity_horizontal_margin"
Android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.hfad.addingafragmenttoframelayout.MainActivity"
Android:orientation="vertical">
<FrameLayout
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:id="@+id/fragment_container"
/>
</LinearLayout>
Dans la méthode d'activité onCreate, j'ajoute fragment à la mise en page. Cela fonctionne correctement sauf si j'essaie de modifier le texte à l'aide de la méthode setText.
Et je reçois cette erreur:
Caused by: Java.lang.NullPointerException: Attempt to invoke virtual method 'Android.view.View Android.view.View.findViewById(int)' on a null object reference
at com.hfad.addingafragmenttoframelayout.BlankFragment.setText(BlankFragment.Java:35)
at com.hfad.addingafragmenttoframelayout.MainActivity.onStart(MainActivity.Java:29)
se référant à cette ligne
TextView tv = (TextView)this.getView().findViewById(R.id.fragmentText);
Quelqu'un peut-il expliquer ce qui cause cette exception?
Ne pas
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d("message","onCreateView() of BlankFragment");
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_blank, container, false);
}
public void setText(String textToBeSet){
TextView tv = (TextView)this.getView().findViewById(R.id.fragmentText);
tv.setText(textToBeSet);
}
Faire
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View RootView = inflater.inflate(R.layout.fragment_blank, container, false);
TextView tv = (TextView)RootView.findViewById(R.id.fragmentText);
tv.setText("HI");
return RootView;
}
Ici:
bf.setText("hello world");
problème provoquant une ligne, appelez la méthode setText
de Fragment avant d’ajouter Fragment
dans FragmentManager
.
Appelez la méthode setText
après avoir ajouté bf
Fragment:
getSupportFragmentManager().beginTransaction().
add(R.id.fragment_container, bf).commit();
bf.setText("hello world"); // call here
Le problème est que FragmentTransaction est asynchrone par défaut
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.fragment_container, BlankFragment.newInstance);
ft.disallowBackStack();
ft.commitNowAllowingStateLoss();
Ensuite, vous ne pouvez toujours pas obtenir le fragment, vous devez le récupérer à partir de FragmentTransaction
BlankFragment bf = (BlankFragment) getSupportFragmentManager().getFragmentById(R.id.fragment_container);
bf.setText("hello world");
Cet article m'a aidé à mieux comprendre ce problème
Vous pouvez utiliser une variable temporaire pouvant contenir la variable String
tant que la vue n'est pas encore créée.
private TextView tv;
private String holder = "";
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_blank, container,false);
tv = (TextView)v.findViewById(R.id.fragmentText);
return v;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
tv.setText(holder);
}
public void setText(String textToBeSet){
if(tv != null){
tv.setText(textToBeSet);
}else{
holder = textToBeSet;
}
}
Mon hypothèse est que vous souhaitez instancier votre BlankFragment
avec du texte initial et permettre de le définir ultérieurement à partir de votre MainActivity
.
Dans ce cas, je modifierais d’abord le fragment pour accepter un texte initial comme suit:
public class BlankFragment extends Fragment {
private static final String ARG_INITIAL_TEXT = "arg_initial_text";
public static BlankFragment newInstance(CharSequence initialText) {
final BlankFragment fragment = new BlankFragment();
final Bundle args = new Bundle();
args.putCharSequence(ARG_INITIAL_TEXT, initialText);
fragment.setArguments(args);
return fragment;
}
public BlankFragment() {
// Required empty public constructor
}
private CharSequence mInitialText;
private TextView mText;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mInitialText = getArguments().getCharSequence(ARG_INITIAL_TEXT);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d("message", "onCreateView() of BlankFragment");
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_blank, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mText = view.findViewById(R.id.fragmentText);
mText.setText(mInitialText);
}
public void setText(CharSequence textToBeSet) {
mText.setText(textToBeSet);
}
}
Le code d'activité ressemblerait alors à ceci:
public class MainActivity extends AppCompatActivity {
private BlankFragment mBlankFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
final Fragment bf = BlankFragment.newInstance("hello world");
getSupportFragmentManager()
.beginTransaction()
.add(R.id.fragment_container, bf, BlankFragment.class.getName())
.commit();
}
mBlankFragment = (BlankFragment) getSupportFragmentManager()
.findFragmentByTag(BlankFragment.class.getName());
}
private void someTimeLaterWhenWantingToSetNewTextToFragmentFromActivity(CharSequence newText) {
if (mBlankFragment != null) {
mBlankFragment.setText(newText);
}
}
}
Notez que la vérification null de savedInstanceState
a pour but de protéger Activity-recreation par exemple en raison de changements de configuration.
TextView tv = (TextView)this.getView().findViewById(R.id.fragmentText);
faites-le dans onCreateView ();