web-dev-qa-db-fra.com

Le démarrage d'une activité à partir d'un fragment provoque une exception NullPointerException

Je suis coincé ici avec un problème de démarrage d'une activité à partir d'un bouton à l'intérieur d'un fragment. Voici mon code:

ViewPagerAdapter.Java

import Java.util.List;

import Android.support.v4.app.Fragment;
import Android.support.v4.app.FragmentManager;
import Android.support.v4.app.FragmentPagerAdapter;

public class ViewPagerAdapter extends FragmentPagerAdapter {

    private List<Fragment> fragments;

    public ViewPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
        super(fm);
        this.fragments = fragments;
    }

    @Override
    public int getCount() {
        return this.fragments.size();
    }

    @Override
    public Fragment getItem(int position) {
        return this.fragments.get(position);
    }

}

ViewPagerActivity.Java

import Java.util.List;
import Java.util.Vector;

import Android.os.Bundle;
import Android.support.v4.app.Fragment;
import Android.support.v4.app.FragmentActivity;
import Android.support.v4.view.ViewPager;
import Android.util.Log;
import com.package.here.Class1Overview;
import com.package.here.Class1Overview;
import com.package.here.Class1Overview;

public class ViewPagerActivity extends FragmentActivity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        super.setContentView(R.layout.viewpager);

        ViewPager pager = (ViewPager)super.findViewById(R.id.my_viewpager);
        pager.setAdapter(initialisePaging());
    }

    private ViewPagerAdapter initialisePaging() {

        List<Fragment> fragments = new Vector<Fragment>();
        fragments.add(Fragment.instantiate(this, Class1Overview.class.getName()));
        fragments.add(Fragment.instantiate(this, Class2Overview.class.getName()));
        fragments.add(Fragment.instantiate(this, Class3Overview.class.getName()));
        return new ViewPagerAdapter(super.getSupportFragmentManager(), fragments);          
    }

}

Class1Overview.Java (Voici le bouton)

import Android.content.Intent;
import Android.os.Bundle;
import Android.support.v4.app.Fragment;
import Android.view.LayoutInflater;
import Android.view.View;
import Android.view.View.OnClickListener;
import Android.view.ViewGroup;
import Android.widget.Button;
import Android.widget.LinearLayout;
import com.package.here.R;

public class FuelOverview extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        if (container == null) {
            return null;
        }
        View v = (LinearLayout)inflater.inflate(R.layout.class_one_layout, container, false);
        View AddBtn = v.findViewById(R.id.btn_add);
        ((Button) AddBtn).setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setClass(getActivity(), ActivityToStart.class);
                startActivity(intent);
            }
        });

        return v;
    }
}

Et voici mon LogCat :

01-05 19:39:00.913: E/AndroidRuntime(10557): Uncaught handler: thread main exiting due to uncaught exception
01-05 19:39:01.034: E/AndroidRuntime(10557): Java.lang.RuntimeException: Unable to pause activity {com.package.here/com.package.here.ViewPagerActivity}: Java.lang.NullPointerException
01-05 19:39:01.034: E/AndroidRuntime(10557):    at Android.app.ActivityThread.performPauseActivity(ActivityThread.Java:3162)
01-05 19:39:01.034: E/AndroidRuntime(10557):    at Android.app.ActivityThread.performPauseActivity(ActivityThread.Java:3119)
01-05 19:39:01.034: E/AndroidRuntime(10557):    at Android.app.ActivityThread.handlePauseActivity(ActivityThread.Java:3102)
01-05 19:39:01.034: E/AndroidRuntime(10557):    at Android.app.ActivityThread.access$2400(ActivityThread.Java:119)
01-05 19:39:01.034: E/AndroidRuntime(10557):    at Android.app.ActivityThread$H.handleMessage(ActivityThread.Java:1870)
01-05 19:39:01.034: E/AndroidRuntime(10557):    at Android.os.Handler.dispatchMessage(Handler.Java:99)
01-05 19:39:01.034: E/AndroidRuntime(10557):    at Android.os.Looper.loop(Looper.Java:123)
01-05 19:39:01.034: E/AndroidRuntime(10557):    at Android.app.ActivityThread.main(ActivityThread.Java:4363)
01-05 19:39:01.034: E/AndroidRuntime(10557):    at Java.lang.reflect.Method.invokeNative(Native Method)
01-05 19:39:01.034: E/AndroidRuntime(10557):    at Java.lang.reflect.Method.invoke(Method.Java:521)
01-05 19:39:01.034: E/AndroidRuntime(10557):    at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:860)
01-05 19:39:01.034: E/AndroidRuntime(10557):    at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:618)
01-05 19:39:01.034: E/AndroidRuntime(10557):    at dalvik.system.NativeStart.main(Native Method)
01-05 19:39:01.034: E/AndroidRuntime(10557): Caused by: Java.lang.NullPointerException
01-05 19:39:01.034: E/AndroidRuntime(10557):    at Android.support.v4.app.FragmentManagerImpl.saveFragmentBasicState(FragmentManager.Java:1576)
01-05 19:39:01.034: E/AndroidRuntime(10557):    at Android.support.v4.app.FragmentManagerImpl.saveAllState(FragmentManager.Java:1617)
01-05 19:39:01.034: E/AndroidRuntime(10557):    at Android.support.v4.app.FragmentActivity.onSaveInstanceState(FragmentActivity.Java:481)
01-05 19:39:01.034: E/AndroidRuntime(10557):    at Android.app.Activity.performSaveInstanceState(Activity.Java:1022)
01-05 19:39:01.034: E/AndroidRuntime(10557):    at Android.app.Instrumentation.callActivityOnSaveInstanceState(Instrumentation.Java:1180)
01-05 19:39:01.034: E/AndroidRuntime(10557):    at Android.app.ActivityThread.performPauseActivity(ActivityThread.Java:3144)
01-05 19:39:01.034: E/AndroidRuntime(10557):    ... 12 more
01-05 19:39:01.423: I/dalvikvm(10557): threadid=7: reacting to signal 3

ViewPager lui-même fonctionne bien. Il semble que ce soit une erreur de pause de FragmentActivity, mais je ne peux pas le comprendre. La seule chose que j'ai trouvée était ce post sur google http://code.google.com/p/Android/issues/detail?id=19917

J'ai également parcouru l'exemple de code google pour m'assurer d'utiliser principalement la même technique ...

Edit: pour m'assurer que ClickListener fonctionne, j'ai essayé un Toast dans la méthode onClick - fonctionne parfaitement.

56
Juke

C'est un problème connu et je suis choqué de constater que personne n'a déposé de bug sur le tracker de bug public pour cela.

Votre problème vient de ceci:

if (f.mSavedViewState != null) {
    if (result == null) {
        result = new Bundle();
    }
    result.putSparseParcelableArray(
            FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState);
}
if (!f.mUserVisibleHint) {
    // Only add this if it's not the default value
    result.putBoolean(FragmentManagerImpl.USER_VISIBLE_HINT_TAG, f.mUserVisibleHint);
}

Vous devriez remarquer que si result est null entrant dans ce code et que le premier if n'est pas déclenché, vous obtiendrez un NullPointerException si nous entrons dans le second if.

Il devrait se lire:

if (f.mSavedViewState != null) {
    if (result == null) {
        result = new Bundle();
    }
    result.putSparseParcelableArray(
            FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState);
}
if (!f.mUserVisibleHint) {
    if (result == null) {
        result = new Bundle();
    }
    // Only add this if it's not the default value
    result.putBoolean(FragmentManagerImpl.USER_VISIBLE_HINT_TAG, f.mUserVisibleHint);
}

J'ai soumis un patch pour cela il y a une semaine ou deux: https://Android-review.googlesource.com/31261

48
Jake Wharton

La solution rapide est

class MyFragment extends Fragment {

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        setUserVisibleHint(true);
    }

Et attendez la mise à jour en mode sans échec :)

62
Vadim

Selon un article ici , vous devriez utiliser FragmentStatePagerAdapter plutôt que FragmentPagerAdapter. J'ai eu le même problème que vous avez décrit, et faire en sorte que ce changement fonctionne pour moi.

32
Harlo Holmes

J'ai juste eu le même problème - le problème pour moi a été causé lorsque j'ai ajouté un nouveau fragment à mon projet avec une mise en page vide. Il semble que si rien n'est enregistré dans le bundle pendant Fragment.onSaveInstanceState(Bundle outState) cela provoque une exception de pointeur nul dans FragmentManagerImpl.saveFragmentBasicState.

L'ajout de vues à mes mises en page a résolu le problème (après des heures passées à me cogner la tête contre un mur). Utilisation de Android support library v4 revision 10.

De plus, lorsque vous utilisez un ListView comme racine pour la disposition des fragments, si la liste ne contient aucun élément, vous obtiendrez également le plantage. Dans la classe fragment, remplacez onSaveInstanceState comme ceci pour mettre des données dans le bundle:

@Override
public void onSaveInstanceState(Bundle outState)
{
    super.onSaveInstanceState(outState);
    outState.putString("DO NOT CRASH", "OK");
}
4
Wayne Uroda