2014-11-18 2 views
0

Я работаю над добавлением Shared Preferences к моей заметке с Android-приложением, и я столкнулся с особым исключением null-указателя. В настоящее время я тестирую настройки размера шрифта и шрифта в своем приложении и смог успешно сохранить общие настройки для обоих, но у меня возникают проблемы с частью поиска. Когда настройки изменены, они успешно изменяют шрифт и размер шрифта на фрагменте в течение оставшегося времени, когда приложение открыто, но я не могу восстановить их, если приложение перезапустится.Общие предпочтения Исключение Null Pointer

Первый странный нулевой указатель находится в onCreate.

OnCreate:

//create a new note fragment if one has not been created yet 
    mNoteFragment = (NoteFragment) getFragmentManager().findFragmentById(R.id.container); 
    if (mNoteFragment == null) { 
     mNoteFragment = new NoteFragment(); 
     getFragmentManager().beginTransaction() 
       .replace(R.id.container, mNoteFragment).commit(); 
    } 

    //restore SharedPreferences 
    SharedPreferences sharedPrefs = getPreferences(0); 
    int stylePref = sharedPrefs.getInt(SharedPreferanceConstants.PREF_FONT_SIZE, 2); 
    String fontPref = sharedPrefs.getString(SharedPreferanceConstants.PREF_TYPEFACE, ""); 
    Log.e("STYLEID", String.valueOf(stylePref)); 
    Log.e("FONTTYPE", fontPref); 
    onStyleChange(null , stylePref); //NULL POINTER EXCEPTION HERE 
    onFontChange(null, fontPref); 

Бревна выход «3» и «Impact», которые являются правильные значения для размера и шрифта, который указывает, что stylePref и fontPref не равны нулю.

Следующий Null Pointer ниже .:

@Override 
    public void onStyleChange(CustomStyleDialogFragment dialog, int styleId) { 
     Log.d("NOTEFRAGMENT", String.valueOf(mNoteFragment)); 
     mNoteFragment.setCustomStyle(styleId); //NULL POINTER EXCEPTION HERE 
    } 

    @Override 
    public void onFontChange(CustomStyleDialogFragment dialog, String fontName) { 
     mNoteFragment.setCustomFont(fontName); 
    } 

Я испытал протоколирование значение styleId и получил «3», так что, кажется, не будет проблемой. mNoteFragment не равно null на основе журнала.

Ниже приведено третье исключение NP в NoteFragment.java. Именно здесь я в конечном итоге настроил вид EditText на нужные настройки. У меня не было проблем с изменением шрифта и размера без общих настроек, поэтому я не уверен, что проблема здесь.

public void setCustomFont(String fontName) { 
     if(fontName.equals("Helvetica")) { 
      mEditText.setTypeface(mHelvetica); 
     } 
     else if(fontName.equals("Helvetica-Neue")) { 
      mEditText.setTypeface(mHelveticaNeue); 
     } 
     else if(fontName.equals("Impact")) { 
      mEditText.setTypeface(mImpact); 
     } 
     else { 
      mEditText.setTypeface(Typeface.DEFAULT); 
     } 
    } 

    public void setCustomStyle(int styleId) { 
     if(styleId == 1) { 
      mEditText.setTextAppearance(getActivity(), android.R.style.TextAppearance_Small); 
     } 
     else if(styleId == 2) { 
      mEditText.setTextAppearance(getActivity(), android.R.style.TextAppearance_Medium); 
     } 
     else if(styleId == 3) { 
      //NULL POINTER EXCEPTION HERE 
      mEditText.setTextAppearance(getActivity(), android.R.style.TextAppearance_Large); 
     } 
} 

И, конечно же, здесь находится лодка. Заранее спасибо!

11-18 10:31:53.030 18966-18966/com.richluick.blocnotes I/Process﹕ Sending signal. PID: 18966 SIG: 9 
11-18 10:35:32.838 19248-19248/com.richluick.blocnotes D/STYLEID﹕ 3 
11-18 10:35:32.838 19248-19248/com.richluick.blocnotes D/FONTTYPE﹕ Impact 
11-18 10:35:32.839 19248-19248/com.richluick.blocnotes D/ERROR﹕ NoteFragment{422972f8 id=0x7f090001} 
11-18 10:35:32.840 19248-19248/com.richluick.blocnotes D/AndroidRuntime﹕ Shutting down VM 
11-18 10:35:32.840 19248-19248/com.richluick.blocnotes W/dalvikvm﹕ threadid=1: thread exiting with uncaught exception (group=0x4197dd40) 
11-18 10:35:32.842 19248-19248/com.richluick.blocnotes E/AndroidRuntime﹕ FATAL EXCEPTION: main 
    Process: com.richluick.blocnotes, PID: 19248 
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.richluick.blocnotes/com.richluick.blocnotes.BlocNotes}: java.lang.NullPointerException 
      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2198) 
      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2257) 
      at android.app.ActivityThread.access$800(ActivityThread.java:139) 
      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210) 
      at android.os.Handler.dispatchMessage(Handler.java:102) 
      at android.os.Looper.loop(Looper.java:136) 
      at android.app.ActivityThread.main(ActivityThread.java:5097) 
      at java.lang.reflect.Method.invokeNative(Native Method) 
      at java.lang.reflect.Method.invoke(Method.java:515) 
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785) 
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601) 
      at dalvik.system.NativeStart.main(Native Method) 
    Caused by: java.lang.NullPointerException 
      at com.richluick.blocnotes.NoteFragment.setCustomStyle(NoteFragment.java:86) 
      at com.richluick.blocnotes.BlocNotes.onStyleChange(BlocNotes.java:139) 
      at com.richluick.blocnotes.BlocNotes.onCreate(BlocNotes.java:61) 
      at android.app.Activity.performCreate(Activity.java:5248) 
      at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1110) 
      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2162) 
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2257) 
            at android.app.ActivityThread.access$800(ActivityThread.java:139) 
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210) 
            at android.os.Handler.dispatchMessage(Handler.java:102) 
            at android.os.Looper.loop(Looper.java:136) 
            at android.app.ActivityThread.main(ActivityThread.java:5097) 
            at java.lang.reflect.Method.invokeNative(Native Method) 
            at java.lang.reflect.Method.invoke(Method.java:515) 
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785) 
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601) 
            at dalvik.system.NativeStart.main(Native Method) 

NoteFragment.java

public class NoteFragment extends Fragment { 

    public EditText mEditText; 
    private Typeface mHelvetica; 
    private Typeface mHelveticaNeue; 
    private Typeface mImpact; 

    private static final String TEXT = "text"; 

    @Override 
    public void onSaveInstanceState(Bundle savedInstanceState) { 
     super.onSaveInstanceState(savedInstanceState); 
     savedInstanceState.putString(TEXT, mEditText.getText().toString()); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     View rootView = inflater.inflate(R.layout.fragment_note, container, false); 
     setHasOptionsMenu(true); 

     //restore state of app when activity is destroyed and restarted 
     mEditText = (EditText) rootView.findViewById(R.id.editText); 
     if (savedInstanceState != null) { 
      mEditText.setText(savedInstanceState.getString(TEXT)); 
     } 

     //Store the font assets as variables 
     mHelvetica = Typeface.createFromAsset(getActivity().getAssets(), "fonts/Helvetica_Reg.ttf"); 
     mHelveticaNeue = Typeface.createFromAsset(getActivity().getAssets(), "fonts/HelveticaNeue_Lt.ttf"); 
     mImpact = Typeface.createFromAsset(getActivity().getAssets(), "fonts/impact.ttf"); 

     return rootView; 
    } 

    /** 
    * This is a setter method for setting the font the user has selected from the spinner 
    * 
    * param fontName the name of the font the user selected 
    * @return void 
    * */ 
    public void setCustomFont(String fontName) { 
     if(fontName.equals("Helvetica")) { 
      mEditText.setTypeface(mHelvetica); 
     } 
     else if(fontName.equals("Helvetica-Neue")) { 
      mEditText.setTypeface(mHelveticaNeue); 
     } 
     else if(fontName.equals("Impact")) { 
      mEditText.setTypeface(mImpact); 
     } 
     else { 
      mEditText.setTypeface(Typeface.DEFAULT); 
     } 
    } 

    /** 
    * This is a setter method for setting the font style the user has selected from custom menu 
    * 
    * param styleId the integer id of the font stlye selected (SMALL, MEDIUM, LARGE) 
    * @return void 
    * */ 
    public void setCustomStyle(int styleId) { 
     if(styleId == 1) { 
      mEditText.setTextAppearance(getActivity(), android.R.style.TextAppearance_Small); 
     } 
     else if(styleId == 2) { 
      mEditText.setTextAppearance(getActivity(), android.R.style.TextAppearance_Medium); 
     } 
     else if(styleId == 3) { 
      Log.d("EDITTEXT", String.valueOf(mEditText)); 
      mEditText.setTextAppearance(getActivity(), android.R.style.TextAppearance_Large); 
     } 
    } 

    @Override 
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
     // Inflate the menu; this adds items to the action bar if it is present. 
     super.onCreateOptionsMenu(menu, inflater); 

     inflater = getActivity().getMenuInflater(); 
     inflater.inflate(R.menu.bloc_notes, menu); 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
     int id = item.getItemId(); 
     if (id == R.id.action_erase) { 
      mEditText.setText(""); 
     } 
     return super.onOptionsItemSelected(item); 
    } 
} 
+0

Когда вы сохранили свои настройки, вы их совершили? – Nanis

+0

Да, я их совершил –

+0

'com.richluick.blocnotes.NoteFragment.setCustomStyle (NoteFragment.java:86)', что означает, что 'mEditText' ... – Selvin

ответ

0

Ладно, так что я не знаю, почему это работает, но я был в состоянии выяснить Anwer основе этого вопроса:

onCreateView() in Fragment is not called immediately, even after FragmentManager.executePendingTransactions()

Я добавил следующую строку:

getFragmentManager().executePendingTransactions(); 

, а затем перешел Everthing методу OnStart

@Override 
    protected void onStart() { 
     super.onStart(); 

     //create a new note fragment if one has not been created yet 
     mNoteFragment = (NoteFragment) getFragmentManager().findFragmentById(R.id.container); 
     if (mNoteFragment == null) { 
      mNoteFragment = new NoteFragment(); 
      getFragmentManager().beginTransaction().replace(R.id.container, mNoteFragment).commit(); 
      getFragmentManager().executePendingTransactions(); 
     } 

     //restore SharedPreferences 
     SharedPreferences sharedPrefs = getPreferences(0); 
     int stylePref = sharedPrefs.getInt(SharedPreferanceConstants.PREF_FONT_SIZE, 2); 
     String fontPref = sharedPrefs.getString(SharedPreferanceConstants.PREF_TYPEFACE, ""); 
     Log.d("STYLEID", String.valueOf(stylePref)); 
     Log.d("FONTTYPE", fontPref); 
     onStyleChange(null , stylePref); 
     onFontChange(null, fontPref); 
    } 

и по какой-то причине он теперь работает отлично. Если бы кто-нибудь мог объяснить, почему это было бы здорово

+0

о каких-либо изменениях в NoteFragment: https://gist.github.com/SelvinPL/e9549885632669c7a37f (без выполненияPendingTransactions()) – Selvin

+0

Im не уверен, что я полностью следую? Стиль по умолчанию установлен в MainActivity, и любые изменения фактически обрабатываются в отдельном фрагменте настроек. –

+0

нет ... весь код из NoteFragment ... если mEditText не является нулевым, он работает обычным способом ... if onCreateView wasn ' t называется mEditText == null, поэтому setCustomFont вызывается снова на onCreateView (полностью зафиксированный фрагмент) и SOMEDEFAULTSTYLE = 1 или 2 или 3 – Selvin

-1

Try использование 'применить' вместо 'совершить', оправдание здесь ->What's the difference between commit() and apply() in Shared Preference Лукаса Кнута.

Но в принципе, apply() немедленно выполнит свои изменения в операциях SharedPreferences в памяти.

Настоятельно рекомендуется использовать класс для управления вашими предпочтениями, например «MyPreferencesManager».

+0

, это должен быть комментарий, так как нет никакого соединения без вашего ответа и NPE в вопросе ... – Selvin

+0

Я слышал, что создание класса - это путь, поэтому я буду использовать его, идущий по дороге , Это мой первый набег на SharedPreferences, поэтому я пытаюсь заставить его работать так, как в первую очередь. Спасибо за совет! –

+0

связан с менеджером SP без фрагментов ... взгляните на Flo ответ .. может быть, вы thoght о FM не SP ... – Selvin

1

Ваш mEditText в вашем NoteFragment равен null в настоящее время, следовательно, NPE.

Просто введите свой член mEditText в onCreate() или onActivityCreated() фрагмента, а не onCreateView(). Это должно гарантировать, что mEditText не является нулевым, когда вы вызываете ваши сеттеры.

Что бы ни случилось, вы должны защищать от нулевого mEditText в своих сеттерных функциях.

EDIT это то, что я имел в виду:

public void setCustomFont(String fontName) { 
     if(mEditText != null){ 
     if(fontName.equals("Helvetica")) { 
      mEditText.setTypeface(mHelvetica); 
     } 
     else if(fontName.equals("Helvetica-Neue")) { 
      mEditText.setTypeface(mHelveticaNeue); 
     } 
     else if(fontName.equals("Impact")) { 
      mEditText.setTypeface(mImpact); 
     } 
     else { 
      mEditText.setTypeface(Typeface.DEFAULT); 
     } 
     } 
    } 

EDIT 2: OnCreate не будет хорошим местом. В принципе, вы хотите вызвать своего сеттера после того, как оператор-фрагмент зафиксировал ваше изменение, так что mEditText был инициализирован.

EDIT 3 - Попробуйте это с вашим исходным кодом:

getFragmentManager().beginTransaction().replace(R.id.container, mNoteFragment).commit(); 
    getFragmentManager().executePendingTransactions(); 
+0

'onCreateView' довольно хорошее место :) и' onCreate' не :) – Selvin

+0

I Я не уверен, что согласен. OnCreate может быть опасным, но onActivityCreated - это правильное место, не так ли? Наверное, OnCreateView еще не был вызван. Можете ли вы быть более сложными в своем ответе? Кажется, что вы пошли вокруг downvoting, не имея веской причины ... –

+0

Я все еще получаю нулевой указатель в onCreate. Что было бы примером защиты его в функции setter? –

1

В вашей SomeActivity.onCreate() вы создаете экземпляр NoteFragment, но даже если вы фиксируете его с помощью транзакции, она не будет завышена и создан немедленно. Что в основном означает, что NoteFragment.onCreateView() не был выполнен, и пользовательский интерфейс фрагментов еще не создан. Однако ваш Activity.onCreate() предполагает, что уже установлен mFragment.mEditText, что не так, поэтому вы натыкаетесь на NullPointerException.

Посмотрите на FragmentTransation.commit метод: http://developer.android.com/reference/android/support/v4/app/FragmentTransaction.html#commit()

Schedules a commit of this transaction. The commit does not happen immediately; it will 
be scheduled as work on the main thread to be done the next time that thread is ready. 
+0

интересно ... так что решение может быть: 'if (mEditText равно null) {отложить настройку в onCreateView} else {выполнить настройки сейчас}' – Selvin

+0

Хорошо, я подумал, что onCreateView никогда не исполнялся, поэтому спасибо за разъяснение того, , Однако я не понимаю, почему. Я немного смущен тем, что вы подразумеваете под «совершить транзакцию» и методом FragmentTransation.commit в целом. Не могли бы вы привести мне пример этого в действии? Я довольно потерян в противном случае –

+1

Это означает, что в основном вы попросите диспетчер фрагментов заменить фрагмент, а менеджер фрагментов сделает это асинхронно. Это означает, что он «помнит, что он должен заменить ваш фрагмент», и будет делать это, когда процессор сможет справиться с ним (не слишком много нагрузки). Это означает, что все, что вы вызываете после строки commit(), не гарантирует выполнения операции, выполняемой commit(). –