Android开发如何避免使用片段和选项菜单保存上下文

Android开发如何避免使用片段和选项菜单保存上下文,android,android-fragments,android-context,android-menu,Android,Android Fragments,Android Context,Android Menu,在android应用程序中,我有一个包含片段的活动 该片段具有一个“updateScore”函数,该函数使用当前分数更新UI 此函数从片段中调用,也应从活动中的选项菜单中调用 如果我将上下文保存为片段中的静态变量,这是可以实现的,但这是一种糟糕的做法。那么我应该怎么做呢 主要活动: public class MainActivity extends AppCompatActivity { public static int totalCorrect; @Override

在android应用程序中,我有一个包含片段的活动

该片段具有一个“updateScore”函数,该函数使用当前分数更新UI

此函数从片段中调用,也应从活动中的选项菜单中调用

如果我将上下文保存为片段中的静态变量,这是可以实现的,但这是一种糟糕的做法。那么我应该怎么做呢

主要活动:

public class MainActivity extends AppCompatActivity {

    public static int totalCorrect;

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

         FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
         ExerciseFragment exerciseFragment = new ExerciseFragment();
         fragmentTransaction.add(R.id.fragment_container, exerciseFragment);
         fragmentTransaction.commit();
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        super.onOptionsItemSelected(item);

        int id = item.getItemId();
        if (id == R.id.option_reset_score) {
            totalCorrect = 0;
            ExerciseFragment.updateScore(); 
        }
    }
}
练习片段:

public class ExerciseFragment extends Fragment {

    private static View view; //bad practice

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_exercises, container, false);
        ExerciseFragment.view = view;
        updateScore(); 
        return view;
    }

    public static void updateScore() {
        TextView totalCorrectTextView = (TextView) view.findViewById(R.id.total_correct);
        totalCorrectTextView.setText(MyApp.getAppContext().getString(R.string.correct) + ": " + String.valueOf(MainActivity.totalCorrect));

    }
}

按以下方式更改您的练习片段:

public class ExerciseFragment extends Fragment {

    private View mView;

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        mView = inflater.inflate(R.layout.fragment_exercises, container, false);
        updateScore(); 
        return mView;
    }

    public void updateScore() {
        TextView totalCorrectTextView = (TextView) mView.findViewById(R.id.total_correct);
        totalCorrectTextView.setText(getActivity().getString(R.string.correct) + ": " + String.valueOf(MainActivity.totalCorrect));

    }
}
在活动中,您可以通过其容器的ID找到当前片段:

ExerciseFragment exerciseFragment  = (ExerciseFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_container);
然后你可以使用他的方法:

exerciseFragment.updateScore();

我认为视图或方法不需要是静态的

public class ExerciseFragment extends Fragment {

    private View view;

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_exercises, container, false);
        ExerciseFragment.view = view;
        updateScore(); 
        return view;
    }

    public void updateScore() {
        TextView totalCorrectTextView = (TextView) view.findViewById(R.id.total_correct);
        totalCorrectTextView.setText(MyApp.getAppContext().getString(R.string.correct) + ": " + String.valueOf(MainActivity.totalCorrect));

    }
}
你一定是在什么地方启动了碎片

public class MainActivity extends AppCompatActivity {

    public static int totalCorrect;

    public ExerciseFragment exerciseFragment;

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

        exerciseFragment= new ExerciseFragment();

        FragmentManager fragmentManager = getFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        if (getFragmentManager().findFragmentById(R.id.fragment_container) != null)
            fragmentManager.popBackStack();
        fragmentTransaction.replace(R.id.fragment_container, currentFragment);
        fragmentTransaction.addToBackStack(null);
        fragmentTransaction.commit();

    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        super.onOptionsItemSelected(item);

        int id = item.getItemId();
        if (id == R.id.option_reset_score) {
            totalCorrect = 0;
            exerciseFragment.updateScore();
            return true;
        }

        return false;
    }
}

这不是最好的做法。我建议你做的是:

  • 创建一个接口,比如“ScoreUpdater”,方法是“updateScore”

  • 使您的活动扩展此接口
  • 将“updateScore”方法的逻辑从片段移动到活动中的此重写方法
  • 在片段的“onAttach”方法上,检查片段所附加到的上下文是否是此ScoreUpdater接口的实例,并保存指向它的链接

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof ScoreUpdater)
            scoreUpdater = (ScoreUpdater)context;
        ...
    }
    
  • 每当需要从片段中更新分数时,只需从片段中调用scoreUpdater.updateScore(),从活动中调用updateScore()
这种编程方法更为正确,并且也遵循一些规则

从驻留在“活动”中的选项菜单调用


这是你的问题。您的片段可以提供自己的选项菜单项。您需要覆盖片段中的
onCreateOptionsMenu
onOptionsItemSelected
,并在片段的一个设置生命周期方法中调用
setHasOptionsMenu(true)
。请参阅。

您是否正在MainActivity中加载练习片段???您是否知道使用
接口
?您可以通过创建片段的静态实例来调用该方法。请发布您的代码片段,说明如何在活动中加载片段??我添加了onCreate函数,在其中加载片段,但如果我不想静态保存视图,我需要将updateScore()改为updateScore(视图视图)。我编辑了答案。您的视图不需要是静态的。谢谢。静态exerciseFragment变量也不是一个好的实践,但它不必是静态的。
@Override
public void onAttach(Context context) {
    super.onAttach(context);
    if (context instanceof ScoreUpdater)
        scoreUpdater = (ScoreUpdater)context;
    ...
}