Страницы

Поиск по вопросам

четверг, 26 декабря 2019 г.

Ошибка фрагмента при смене ориентации

#java #android #android_fragment


Всем доброго времени суток. Есть активити с двумя фрагментами ListFragment. У меня
проблема со сменой ориентации. Если я, не выбирая элементов списка из первого фрагмента,
меняю ориентацию, она меняется нормально. Но если я выбираю элемент списка, а затем
меняю ориентацию, то программа выкидывает ошибку. Приведу код

MainActivity.java

public class MainActivity extends AppCompatActivity implements SurahListFragment.Callbacks,
FavoriteListFragment.Callbacks{

// Declaring Your View and Variables
// Migration
private boolean mTwoPane;

Toolbar toolbar;
ViewPager pager;
ViewPagerAdapter adapter;
SlidingTabLayout tabs;
CharSequence Titles[]={"Коран","Избранное"};
int Numboftabs =2;
//ActionBar
private MenuItem mSearchAction;
private boolean isSearchOpened = false;
private EditText edtSeach;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    if (findViewById(R.id.surah_detail_container) != null) {
        mTwoPane = true;
    }
    //Creating The Toolbar and setting it as the Toolbar for the activity
    toolbar = (Toolbar) findViewById(R.id.tool_bar);
    setSupportActionBar(toolbar);
    // Creating The ViewPagerAdapter and Passing Fragment Manager, Titles fot the
Tabs and Number Of Tabs.
    adapter =  new ViewPagerAdapter(getSupportFragmentManager(),Titles, Numboftabs);
    // Assigning ViewPager View and setting the adapter
    pager = (ViewPager) findViewById(R.id.pager);
    pager.setAdapter(adapter);
    // Assiging the Sliding Tab Layout View
    tabs = (SlidingTabLayout) findViewById(R.id.tabs);
    tabs.setDistributeEvenly(true); // To make the Tabs Fixed set this true, This
makes the tabs Space Evenly in Available width
    // Setting Custom Color for the Scroll bar indicator of the Tab View
    tabs.setCustomTabColorizer(new SlidingTabLayout.TabColorizer() {
        @Override
        public int getIndicatorColor(int position) {
            return getResources().getColor(R.color.ColorPrimary);
        }
    });
    // Setting the ViewPager For the SlidingTabsLayout
    tabs.setViewPager(pager);

}





@Override
public void onItemSelected(String id) {
    Log.d("TAG", ""+ mTwoPane);
    if (mTwoPane) {
        // In two-pane mode, show the detail view in this activity by
        // adding or replacing the detail fragment using a
        // fragment transaction.
        Bundle arguments = new Bundle();
        arguments.putString(SurahDetailFragment.ARG_ITEM_ID, id);
        SurahDetailFragment fragment = new SurahDetailFragment();
        fragment.setArguments(arguments);
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.surah_detail_container, fragment)
                .commit();

    } else {
        // In single-pane mode, simply start the detail activity
        // for the selected surah_list_item ID.
        Intent detailIntent = new Intent(this, SurahDetailActivity.class);
        detailIntent.putExtra("item_id", id);
        startActivity(detailIntent);
    }
}


SurahListFragment.java

public class SurahListFragment extends ListFragment {

/**
 * The serialization (saved instance state) Bundle key representing the
 * activated surah_list_item position. Only used on tablets.
 */
private static final String STATE_ACTIVATED_POSITION = "activated_position";

/**
 * The fragment's current callback object, which is notified of list surah_list_item
 * clicks.
 */
private Callbacks mCallbacks = sDummyCallbacks;

/**
 * The current activated surah_list_item position. Only used on tablets.
 */
private int mActivatedPosition = ListView.INVALID_POSITION;

/**
 * A callback interface that all activities containing this fragment must
 * implement. This mechanism allows activities to be notified of surah_list_item
 * selections.
 */
public interface Callbacks {
    /**
     * Callback for when an surah_list_item has been selected.
     */
    public void onItemSelected(String id);
}

/**
 * A dummy implementation of the {@link Callbacks} interface that does
 * nothing. Used only when this fragment is not attached to an activity.
 */
private static Callbacks sDummyCallbacks = new Callbacks() {
    @Override
    public void onItemSelected(String id) {
    }
};

/**
 * Mandatory empty constructor for the fragment manager to instantiate the
 * fragment (e.g. upon screen orientation changes).
 */
public SurahListFragment() {
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    ArrayList surahArrayList = new ArrayList();
    for (int i = 1; i < 115; i++){
        Surah surah = new Surah();
        try {
            JSONObject obj = new JSONObject(loadJSONFromAsset());
            JSONArray jsonArr = obj.getJSONArray("surahs");
            JSONObject j = jsonArr.getJSONObject(i-1);
            surah.title = j.getString("surah");
            surah.location = j.getString("location");
            surah.count = j.getInt("count");
        } catch (JSONException e) {
            e.printStackTrace();
        }

        surahArrayList.add(surah);
    }

    SurahAdapter adapter = new SurahAdapter(getActivity(), R.layout.surah_list_item,
surahArrayList);
    setListAdapter(adapter);

}

public String loadJSONFromAsset() {
    String json = null;
    try {
        InputStream is = getActivity().getAssets().open("surah.json");
        int size = is.available();
        byte[] buffer = new byte[size];
        is.read(buffer);
        is.close();
        json = new String(buffer, "UTF-8");
    } catch (IOException ex) {
        ex.printStackTrace();
        return null;
    }
    return json;
}

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    getListView().setDivider(null);
    getListView().setBackgroundColor(Color.WHITE);
    // Restore the previously serialized activated surah_list_item position.
    if (savedInstanceState != null
            && savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) {
        setActivatedPosition(savedInstanceState.getInt(STATE_ACTIVATED_POSITION));
    }
}

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);

    // Activities containing this fragment must implement its callbacks.
    if (!(activity instanceof Callbacks)) {
        throw new IllegalStateException("Activity must implement fragment's callbacks.");
    }

    mCallbacks = (Callbacks) activity;
}

@Override
public void onDetach() {
    super.onDetach();

    // Reset the active callbacks interface to the dummy implementation.
    mCallbacks = sDummyCallbacks;
}

@Override
public void onListItemClick(ListView listView, View view, int position, long id) {
    super.onListItemClick(listView, view, position, id);

    // Notify the active callbacks interface (the activity, if the
    // fragment is attached to one) that an surah_list_item has been selected.
    mCallbacks.onItemSelected(String.valueOf(position));
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    if (mActivatedPosition != ListView.INVALID_POSITION) {
        // Serialize and persist the activated surah_list_item position.
        outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition);
    }
}

/**
 * Turns on activate-on-click mode. When this mode is on, list items will be
 * given the 'activated' state when touched.
 */
public void setActivateOnItemClick(boolean activateOnItemClick) {
    // When setting CHOICE_MODE_SINGLE, ListView will automatically
    // give items the 'activated' state when touched.
    getListView().setChoiceMode(activateOnItemClick
            ? ListView.CHOICE_MODE_SINGLE
            : ListView.CHOICE_MODE_NONE);
}

private void setActivatedPosition(int position) {
    if (position == ListView.INVALID_POSITION) {
        getListView().setItemChecked(mActivatedPosition, false);
    } else {
        getListView().setItemChecked(position, true);
    }

    mActivatedPosition = position;
}


Проблема решается если закоментировать эту строку - mCallbacks.onItemSelected(String.valueOf(position));

@Override
public void onListItemClick(ListView listView, View view, int position, long id) {
    super.onListItemClick(listView, view, position, id);

    // Notify the active callbacks interface (the activity, if the
    // fragment is attached to one) that an surah_list_item has been selected.
    mCallbacks.onItemSelected(String.valueOf(position));
}


Код ошибки:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.gatafan.myquran/com.gatafan.myquran.Slides.MainActivity}:
android.view.InflateException: Binary XML file line #53: Error inflating class fragment
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2298)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
    at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3912)
    at android.app.ActivityThread.access$900(ActivityThread.java:144)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1284)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5221)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
    Caused by: android.view.InflateException: Binary XML file line #53: Error inflating
class fragment
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:763)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:806)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:809)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:809)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:504)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:414)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:365)
    at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:257)
    at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:109)
    at com.gatafan.myquran.Slides.MainActivity.onCreate(MainActivity.java:51)
    at android.app.Activity.performCreate(Activity.java:5933)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2251)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
    at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3912)
    at android.app.ActivityThread.access$900(ActivityThread.java:144)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1284)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5221)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
    Caused by: java.lang.IllegalStateException: Fragment com.gatafan.myquran.SurahDetailFragment
did not create a view.
    at android.support.v4.app.FragmentManagerImpl.onCreateView(FragmentManager.java:2262)
    at android.support.v4.app.FragmentController.onCreateView(FragmentController.java:111)
    at android.support.v4.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:278)
    at android.support.v4.app.BaseFragmentActivityHoneycomb.onCreateView(BaseFragmentActivityHoneycomb.java:31)
    at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:78)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:733)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:806)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:809)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:809)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:504)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:414)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:365)
    at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:257)
    at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:109)
    at com.gatafan.myquran.Slides.MainActivity.onCreate(MainActivity.java:51)
    at android.app.Activity.performCreate(Activity.java:5933)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2251)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
    at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3912)
    at android.app.ActivityThread.access$900(ActivityThread.java:144)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1284)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5221)
    at java.lang.reflect.Method.invoke(Native Method)


надеюсь на вашу помощь!
    


Ответы

Ответ 1



В метод onCreate() каждого фрагмента, добавьте следующую строчку: setRetainInstance(true); Этой строкой Вы даете понять что при поворотах экрана не следует пересоздавать фрагмент.

Ответ 2



Аналогичный вопрос присутствует на enSO Проблема в том, что вы вызываете метод getActivity() до того, как содержимое активити создано, из за этого ссылка на компоненты активити не валидная. Перенесите ваш код из onCreate() в onActivityCreated() или другие методы жизненного цикла фрагмента, которые вызываются уже после создания компонентов хостящей его активити.

Комментариев нет:

Отправить комментарий