如何在手机方向上保存数据?

时间:2017-09-20 18:32:56

标签: android android-fragments transactions fragment onsaveinstancestate

我在让我的应用程序持久化方面遇到了困难。当我旋转手机时,屏幕上的数据不会改变。但是在我点击按钮检索新片段后,我收到一条错误,上面写着“在onSaveInstanceState之后无法执行此操作”。我用Google搜索并看到了类似的问题,但我仍然不知道如何处理和解决这个问题。

我有一个活动类,一个控制器类和两个片段类。 活动类有一个导航查看器,其中包含2个触发片段事务的按钮。也就是说,在每个按钮上单击它将使用按钮侦听器中的一个替换当前片段。我的控制器类使系统初始化,片段只是UI。

我的活动类

public class LoggedInActivity extends AppCompatActivity {
    private final String TAG = "LoggedInActivity: ";
    private Controller controller;
    private TextView navName;
    private NavigationView navigationView;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.v(TAG, "onCreate");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_logged_in);
        if(savedInstanceState == null) {
            Log.v(TAG, "savedInstanceState == null");
            initComponents();
            setNavName();
            initListener();
            initializeSystem();
        } else {
            Log.v(TAG, "savedInstanceState != null");
            initComponents();
            setNavName();
            initListener();
            this.controller = (Controller)savedInstanceState.getSerializable("controller");
        }
    }


    private void initComponents() {
        navigationView = (NavigationView) findViewById(R.id.navigation_view);
        View headerView = navigationView.getHeaderView(0);
        navName = (TextView) headerView.findViewById(R.id.tv_name_surname);

    }

    private void initListener() {
        navigationView.setNavigationItemSelectedListener(new MyNavigationItemListener());
    }

    private void initializeSystem() {
        Log.v(TAG, "new controller");
        controller = new Controller(this, null);
    }

    public void setFragment(Fragment fragment) {
            FragmentManager fragmentManager = getFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            fragmentTransaction.replace(R.id.fragment_container_logged_in, fragment).commit();
    }



    private class MyNavigationItemListener implements NavigationView.OnNavigationItemSelectedListener {
        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            switch(item.getItemId()) {

                case R.id.drawer_summary:
                    controller.setFragmentSummary();
                    break;

                case R.id.drawer_income:
                    controller.setFragmentIncome();
                    break;
            }
            return false;
        }
    }


    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putSerializable("controller", controller);
        super.onSaveInstanceState(outState);
        Log.v(TAG, "onSaveInstanceState, saving the controller");
    }

}

我的控制器类

public class Controller implements Serializable {
    private final String TAG = "Controller: ";

    /********************** Fragments ***********************/
    private Fragment_Income fragment_income;
    private Fragment_Summary fragment_summary;
    /********************************************************/

    /********************** Activities **********************/
    private LoggedInActivity logged_in_activity;
    /********************************************************/


    public Controller(LoggedInActivity logged_in_activity) {
        this.logged_in_activity = logged_in_activity;
        initLoggedInFragments();
        setFragmentSummary();

        }
    }



    /* Initializes fragments that are connected to LoggedInActivity */
    private void initLoggedInFragments() {
        fragment_income = new Fragment_Income();
        fragment_income.setController(this);
        fragment_summary = new Fragment_Summary();
        fragment_summary.setController(this);
    }



    /* use to replace current fragment with the given one */
    private void replaceFragmentWith(Fragment fragment) {
        logged_in_activity.setFragment(fragment);
    }



    /***********************************************************
     *          METHODS REGARDING FRAGMENT INCOME              *
     **********************************************************/

    public void setFragmentIncome() {
        replaceFragmentWith(fragment_income);
    }


    /* Summary fragment is started at first */
    public void setFragmentSummary() {
        replaceFragmentWith(fragment_summary);
    }

}

Fragment_Income

public class Fragment_Income extends Fragment implements Serializable{
    private final String TAG = "Fragment_Income: ";
    private Controller controller;
    private FloatingActionButton fab_income;
    private ListView lv_income;
    private ArrayList<LvData> incomeData;
    private LvAdapterIncome lvAdapterIncome;

    public Fragment_Income() {

    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.v(TAG, "onCreateView");
        View view = inflater.inflate(R.layout.fragment_income, container, false); // Inflate the layout for this fragment
        if(savedInstanceState != null) {
            this.controller = (Controller) savedInstanceState.getSerializable("controller");
        }
        initComponents(view);
        initListener();
        setupListView();
        return view;
    }

    private void initComponents(View view) {
        fab_income = (FloatingActionButton) view.findViewById(R.id.fab_income);
        lv_income = (ListView) view.findViewById(R.id.lv_income);
    }


    private void initListener() {
        ButtonListener buttonListener = new ButtonListener();
        fab_income.setOnClickListener(buttonListener);
    }

    private void setupListView() {
        if (incomeData == null) { // checks if incomeData have been initalized before, if so do not change array to defualt
            incomeData = new ArrayList<>();
            lvAdapterIncome = new LvAdapterIncome(getContext(), incomeData);
        }
        lv_income.setAdapter(lvAdapterIncome);

    }


    public void setController(Controller controller) {
        this.controller = controller;
    }


    @Override
    public void onSaveInstanceState(Bundle outState) {
        Log.v(TAG, "onSaveInstanceState, saving the controller");
        outState.putSerializable("controller", this.controller);
        super.onSaveInstanceState(outState);
    }

}

Fragment_Summary

public class Fragment_Summary extends Fragment implements Serializable {
    private static final String TAG = "Fragment_Summary: ";
    private Controller controller;
    private TextView tv_user;
    private TextView tv_total_revenue;
    private TextView tv_total_expenditure;
    private TextView tv_balance;
    private float totalRevenue;
    private float totalExpenditure;
    private float balance;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_summary, container, false);// Inflate the layout for this fragment
        initComponents(view);
        setUserName();
        if(savedInstanceState == null) {
            //DO SOMETHING
        }
        return view;
    }

    private void addData() {
        totalRevenue = controller.getTotalRevenue();
        totalExpenditure = controller.getTotalExpenditure();
        balance = totalRevenue - totalExpenditure;

        tv_total_revenue.setText(String.valueOf(totalRevenue));
        tv_total_expenditure.setText(String.valueOf(totalExpenditure));
        tv_balance.setText(String.valueOf(balance));
    }

    private void initComponents(View view) {
        tv_user = (TextView)view.findViewById(R.id.tv_user);
        tv_total_revenue = (TextView)view.findViewById(R.id.tv_revenue);
        tv_total_expenditure = (TextView)view.findViewById(R.id.tv_sum_exp);
        tv_balance = (TextView)view.findViewById(R.id.tv_balance);
    }


    @Override
    public void onSaveInstanceState(Bundle outState) {
        outState.putString("revenue", String.valueOf(balance));
        outState.putString("totalExpenditure", String.valueOf(balance));
        outState.putString("balance", String.valueOf(balance));
        super.onSaveInstanceState(outState);
    }


    public void setController(Controller controller) {
        this.controller = controller;
    }

}

我删除了所有的头文件以及我的类中的一些方法,因为我认为它们与此问题无关。

以下是错误日志

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
    at android.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1434)
    at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1452)
    at android.app.BackStackRecord.commitInternal(BackStackRecord.java:708)
    at android.app.BackStackRecord.commit(BackStackRecord.java:672)
    at com.example.user.my_app.LoggedInActivity.setFragment(LoggedInActivity.java:85)
    at com.example.user.my_app.Controller.replaceFragmentWith(Controller.java:89)
    at com.example.user.my_app.Controller.setFragmentIncome(Controller.java:99)
    at com.example.user.my_app.LoggedInActivity$MyNavigationItemListener.onNavigationItemSelected(LoggedInActivity.java:127)
    at android.support.design.widget.NavigationView$1.onMenuItemSelected(NavigationView.java:156)
    at android.support.v7.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:822)
    at android.support.v7.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:156)
    at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:969)
    at android.support.design.internal.NavigationMenuPresenter$1.onClick(NavigationMenuPresenter.java:342)
    at android.view.View.performClick(View.java:5637)
    at android.view.View$PerformClick.run(View.java:22429)
    at android.os.Handler.handleCallback(Handler.java:751)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6119)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

1 个答案:

答案 0 :(得分:1)

这看起来像一个活动状态损失。请参阅Alex Lockwood撰写的题为documentation的优秀文章。我一次又一次地提到它。

引用帖子的介绍:

  

自Honeycomb首次发布以来,以下堆栈跟踪和异常消息一直困扰着StackOverflow:

StreamReader
  

这篇文章将解释为什么以及何时抛出此异常,最后会提出一些有助于确保它不会再次崩溃您的应用程序的建议。