Ссылка на EditText в ViewPager создает исключение нулевого указателя

Что я пытаюсь сделать:

Пусть пользователи вводят данные в 3 разных фрагмента, затем в 4-м фрагменте пользователь просматривает все данные, введенные в первые 3 фрагмента, перед отправкой в ​​​​базу данных.

Проблема, с которой я столкнулся:

Каждый метод, который я пытался установить или получить из EditText, создает NullPointerException

Мой вопрос:

Для того, что я пытаюсь сделать, каков правильный метод для вызова текстового значения EditText из одного фрагмента и установки этого текста в EditText в другом фрагменте при каждом изменении страницы?

Примечания:

Я упростил код, чтобы отразить только один EditText в каждом фрагменте для простоты репликации и анализа кода.

Код:

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.widget.EditText;

public class SwipeEnterResults extends FragmentActivity {

ResultsPagerAdapter mResultsPagerAdapter;
ViewPager mViewPager;

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.swipe_enter_results);

    mResultsPagerAdapter = new ResultsPagerAdapter(getSupportFragmentManager());
    mViewPager = (ViewPager) findViewById(R.id.pager);      
    mViewPager.setAdapter(mResultsPagerAdapter); 
}

public void onResume() {
    super.onResume();
    //Declare EditText(s)

    final EditText txt1= (EditText) mViewPager.findViewById(R.id.txt1);
    final EditText txt2= (EditText) mViewPager.findViewById(R.id.txt2);
    final EditText txt3= (EditText) mViewPager.findViewById(R.id.txt3);

    final EditText rvw1= (EditText) mViewPager.findViewById(R.id.rvw1);
    final EditText rvw2= (EditText) mViewPager.findViewById(R.id.rvw2);
    final EditText rvw3= (EditText) mViewPager.findViewById(R.id.rvw3);


    mViewPager.setOnPageChangeListener(new OnPageChangeListener() {
        @Override
        public void onPageSelected(int position) {

            rvw1.setText(txt1.getText().toString());
            rvw2.setText(txt2.getText().toString());
            rvw3.setText(txt3.getText().toString());                
        }
        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) { }
        @Override
        public void onPageScrollStateChanged(int arg0) { }
    });
}

public class ResultsPagerAdapter extends FragmentPagerAdapter{

    public ResultsPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        Fragment f = new Fragment();

        switch (position) {
        case 0:
            f = new Swipe1();
            break;
        case 1:
            f = new Swipe2();
            break;
        case 2:
            f = new Swipe3();
            break;
        case 3:
            f = new SwipeReviewResults();
            break;
        }

        return f;
    }

    @Override
    public int getCount() {
        return 4;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        switch (position) {
        case 0:
            return getString(R.string.str1);
        case 1:
            return getString(R.string.str2);
        case 2:
            return getString(R.string.str3);
        case 3:
            return getString(R.string.strReview);
        default:
            return "Page " + (position + 1);
        }
    }
}
}



Ответы (4)


Несколько вещей:

  1. Возможно ли, что EditTexts в действии имеют значение null, потому что вы пытаетесь ссылаться на них (через их идентификаторы в представлении) до того, как все фрагменты и их представления будут созданы адаптером? Кроме того, может показаться, что каждый раз, когда вызывается метод getItem для ResultsPagerAdapter, создается новый фрагмент с собственным представлением... поэтому ваша активность может ссылаться на устаревшие представления EditText при создании новых представлений фрагментов.

  2. Ваша активность не должна быть связана с тем, какие представления присутствуют в каждом фрагменте, и с окружающей их логикой. Было бы лучше, если бы каждый фрагмент обрабатывал ссылку на свои представления и управлял окружающей их логикой. Что вы могли бы сделать, так это иметь центральный кеш, в котором значения EditTexts хранятся/извлекаются фрагментами. Например, в методе onPause() фрагмента Swipe вы можете сохранить его значение EditText в кеше, а в методе onResume() фрагмента SwipeReviewResults можно извлечь все обновленные значения EditText из кеша.

  3. В вашем операторе switch адаптера вы должны использовать блок default для возврата пустого new Fragment() вместо того, чтобы без необходимости создавать его заранее.

Я надеюсь, что это помогает вам.

person Stephen Asherson    schedule 16.05.2013
comment
Вот так: @Override public Fragment getItem(int position) { Fragment f; switch (position) { case 0: f = new SwipeChemicalsApplied(); break; case 1: f = new SwipeRaw(); break; case 2: f = new SwipeFinished(); break; case 3: f = new SwipeReviewResults(); break; default: f = new Fragment(); break; } return f; } - person Jim; 16.05.2013
comment
Как лучше всего добавить фрагменты в ViewPager до того, как все будет загружено? Кроме того, я не знаком с сохранением в кэш-памяти, но похоже, что это был бы хороший вариант, и сейчас я собираюсь его изучить. Я ценю вашу помощь и дам вам знать, какие результаты я получу. Надеюсь, это сработает для меня! - person Jim; 16.05.2013
comment
Улучшенный оператор переключения. Чтобы ответить на ваш другой вопрос, вам не нужно беспокоиться о добавлении ViewPager перед всем остальным; удалите ссылки на EditTexts в своей деятельности, добавьте ViewPager как есть, но разрешите каждому фрагменту управлять ссылкой на свой EditText в методе жизненного цикла onCreateView. Для кеширования вы всегда можете использовать класс Application в качестве кеша для хранения глобального состояния, но сначала прочитайте это: ссылка. Пожалуйста, отметьте мой ответ как правильный, если он вам помог :) Спасибо. - person Stephen Asherson; 17.05.2013
comment
В итоге я просто поместил код в оператор if с условием позиции 3. Это сработало, но я ценю ввод, потому что это может помочь мне в будущем в других проектах. - person Jim; 21.05.2013

Не делайте EditTexts окончательным. Попробуйте использовать следующий код вместо текущего onResume:

EditText txt1= (EditText) mViewPager.findViewById(R.id.txt1);
EditText txt2= (EditText) mViewPager.findViewById(R.id.txt2);
EditText txt3= (EditText) mViewPager.findViewById(R.id.txt3);

EditText rvw1= (EditText) mViewPager.findViewById(R.id.rvw1);
EditText rvw2= (EditText) mViewPager.findViewById(R.id.rvw2);
EditText rvw3= (EditText) mViewPager.findViewById(R.id.rvw3);
person TronicZomB    schedule 15.05.2013
comment
Это дает мне ошибку, когда я пытаюсь сослаться на EditText, чтобы внести изменения. - person Jim; 16.05.2013

Вероятно, ваш ViewPager не имеет EditTexts с идентификаторами R.id.txt1, R.id.rvw1,...

Убедитесь, что вы определили все EditTexts в файле swipe_enter_results.xml. В противном случае некоторые объекты (возможно, все) будут равны нулю, и вы получите исключение NullPointerException.

person Dmitry Guselnikov    schedule 15.05.2013
comment
Есть 4 отдельных макета xml с разными идентификаторами. Это не проблема. С моим полным дизайном это около 60 EditText, и каждый из них заканчивается нулевым значением. - person Jim; 16.05.2013

В итоге я попробовал пару вещей. Я добавил mViewPager.setOffscreenPageLimit(3);, а затем просто поместил свой код в оператор if с условием position == 3, и это, кажется, решило все мои проблемы с исключением нулевого указателя. Спасибо всем за помощь!

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.widget.CheckBox;
import android.widget.EditText;

public class SwipeEnterResults extends FragmentActivity {

ResultsPagerAdapter mResultsPagerAdapter;
ViewPager mViewPager;

//Declare EditText for reviewing data on Fragment SwipeReviewResults
EditText txt1;
EditText rvw1;
EditText txt2;
EditText rvw2;
EditText txt3;
EditText rvw3;

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.swipe_enter_results);

    //Set up ViewPager and allow app to hold prior pages when off screen
    mResultsPagerAdapter = new ResultsPagerAdapter(getSupportFragmentManager());
    mViewPager = (ViewPager) findViewById(R.id.pager);      
    mViewPager.setAdapter(mResultsPagerAdapter);
    mViewPager.setOffscreenPageLimit(3);

    //When SwipeReviewResults is displayed, fill EditText's with data from other fragments
    mViewPager.setOnPageChangeListener(new OnPageChangeListener() {
        @Override
        public void onPageSelected(int position) {

            if (position == 3) {
                //set values to EditTexts to pull data from 3 entry fragments and display in SwipeReviewResults
                EditText txt1 = (EditText) mViewPager.findViewById(R.id.txt1);
                EditText rvw1 = (EditText) mViewPager.findViewById(R.id.rvw1);
                EditText txt2 = (EditText) mViewPager.findViewById(R.id.txt2);
                EditText rvw2 = (EditText) mViewPager.findViewById(R.id.rvw2);
                EditText txt3 = (EditText) mViewPager.findViewById(R.id.txt3);
                EditText rvw3 = (EditText) mViewPager.findViewById(R.id.rvw3);


                //Set EditText's on SwipeReviewResults
                rvw1.setText(txt1.getText().toString());
                rvw2.setText(txt2.getText().toString());
                rvw3.setText(txt3.getText().toString());

            }   
        }
        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) { }
        @Override
        public void onPageScrollStateChanged(int arg0) { }
    });
}

public class ResultsPagerAdapter extends FragmentPagerAdapter{

    public ResultsPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        Fragment f;

        switch (position) {
        case 0:
            f = new Swipe1();
            break;
        case 1:
            f = new Swipe2();
            break;
        case 2:
            f = new Swipe3();
            break;
        case 3:
            f = new SwipeReviewResults();
            break;
        default:
            f = new Fragment();
            break;
        }

        return f;
    }

    @Override
    public int getCount() {
        return 4;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        switch (position) {
        case 0:
            return getString(R.string.str1);
        case 1:
            return getString(R.string.str2);
        case 2:
            return getString(R.string.str3);
        case 3:
            return getString(R.string.strReview);
        default:
            return "Page " + (position + 1);
        }
    }
}
}
person Jim    schedule 21.05.2013