使用相同片段的两个活动 - 问题

Two activities using the same fragment - problem

两个活动使用同一个片段。该片段有一个文本视图。 Main activity 将“消息 1”写入文本视图并显示出来。

主 activity 中的一个按钮启动第二个 activity“结果”。

第二个 activity 将“消息 2”写入文本视图并显示。

第二个 activity 中的一个按钮确实会设置结果 Activity.RESULT_OK 然后完成 ()。

main activity 获取“onActivityResult”结果 OK 并将“消息 3”写入文本视图。 然而,“Message 3”并没有出现在文本视图中。而是显示“消息 1”。

public class MainActivity extends AppCompatActivity {
   private static Context  context;
   private static Button   btn_main;

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

       context = this;
       btn_main = findViewById(R.id.btn_main);

       FragmentDisplay.setMessage1("Message 1");

       btn_main.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               Intent intent = new Intent(MainActivity.this, SecondActivity.class);
               secondactivityLauncher.launch(intent);
           }
       });
   }
   
   ActivityResultLauncher<Intent> secondactivityLauncher = registerForActivityResult(
           new ActivityResultContracts.StartActivityForResult(),
           new ActivityResultCallback<ActivityResult>() {
               @Override
               public void onActivityResult(ActivityResult result) {
                   if (result.getResultCode() == Activity.RESULT_OK) {
                       FragmentDisplay.setMessage1("Message 3");
                   }

               }
           });

   public static Context getContext(){
       return context;
   }
}
public class SecondActivity extends AppCompatActivity {
    private static Button btn_second;

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

        btn_second = findViewById(R.id.btn_second);

        FragmentDisplay.setMessage1("Message 2");


        btn_second.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent intent = getIntent();
                setResult(Activity.RESULT_OK, intent);
                finish();
            }
        });
    }
}
public class FragmentDisplay extends androidx.fragment.app.Fragment {

    private static TextView textView1;


    public FragmentDisplay() {
        // Required empty public constructor
    }

    RecyclerView mRecyclerView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.display_fragment, null);

        textView1 = (TextView)view.findViewById(R.id.tv1);
        return view;
    }

    public static void setMessage1(String str){
        textView1.setText(str);
    }

}   // end of class
//activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".main.MainActivity">

<fragment
    android:id="@+id/display_fragment"
    android:name="ddi.pos.display.FragmentDisplay"
    android:layout_width="700dp"
    android:layout_height="180dp"
    android:background="#00CC00"
    android:layout_alignParentLeft="true"
    android:layout_alignParentTop="true"
    android:layout_marginTop="80dp" />

<Button
    android:id="@+id/btn_main"
    android:layout_below="@+id/display_fragment"
    android:layout_marginTop="100dp"
    android:layout_marginLeft="50dp"
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:background="#FFFFFF00"
    android:textSize="25sp"
    android:text="Start Second Activity"
/>
//second_activity.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".main.MainActivity">

<fragment
    android:id="@+id/display_fragment"
    android:name="ddi.pos.display.FragmentDisplay"
    android:layout_width="700dp"
    android:layout_height="180dp"
    android:background="#00CC00"
    android:layout_alignParentLeft="true"
    android:layout_alignParentTop="true"
    android:layout_marginTop="80dp" />

<Button
    android:id="@+id/btn_second"
    android:layout_below="@+id/display_fragment"
    android:layout_marginTop="100dp"
    android:layout_marginLeft="300dp"
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:background="#000000"
    android:textSize="25sp"
    android:text="Finish Second Activity"
/>
//display_fragment.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#CC5500"
>

<TextView android:id="@+id/tv1"
    android:background="#0055FF"
    android:layout_height="60dp"
    android:layout_width="600dp"
    android:text=""
    android:layout_marginLeft="30dp"
    android:layout_marginTop="30dp"
    android:textSize="20dp"
    android:textColor="#ff000000"
/>

警告: 我怀疑您发布的内容并不是您真正想要做的,而是某种解决方法,因此此答案可能会或可能不会真正解决您的使用问题-案件。但是,它确实会产生您在问题中要求的行为。您说您不打算在活动之间发送数据,但您希望第一个 activity 中的消息响应第二个 activity 中的操作而改变,这意味着可以共享信息。

主要答案: 下面的示例在 Activity 和 Fragment 之间使用共享 ViewModel 使用意图跨活动进行数据传输具有您在问题中描述的行为。

ViewModel 允许在 Activity 和 Fragment 之间共享数据,因为 Fragment 可以观察 LiveData 并在 activity 更改它时做出响应。由于问题调用 startActivityForResult 并处理结果,因此我使用它们来处理传回数据以更改消息。

MainActivity.java

public class MainActivity extends AppCompatActivity {

    ActivityResultLauncher<Intent> secondActivityLauncher = registerForActivityResult(
            new ActivityResultContracts.StartActivityForResult(),
            new ActivityResultCallback<ActivityResult>() {
                @Override
                public void onActivityResult(ActivityResult result) {
                    if (result.getResultCode() == Activity.RESULT_OK) {
                        // as you indicated:
                        //viewModel.setMessage("Message 3");

                        // or like this if you sent data
                        Intent data = result.getData();
                        if( data != null ) {
                            Bundle extras = data.getExtras();
                            if( extras != null ) {
                                String msg = extras.getString("response");
                                viewModel.setMessage(msg);
                            }
                        }
                    }

                }
            });

    private MainViewModel viewModel;

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

        viewModel = new ViewModelProvider(this).get(MainViewModel.class);

        // Always initialize the message to "Message 1"
        viewModel.setMessage("Message 1");

        Button btn = findViewById(R.id.btn_main);
        btn.setOnClickListener(view -> {
            Intent intent = new Intent(MainActivity.this, SecondActivity.class);
            intent.putExtra("message", "Message 2");
            secondActivityLauncher.launch(intent);
        });
    }
}

SecondActivity.java

public class SecondActivity extends AppCompatActivity {

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

        // This ViewModel instance is "not" the same instance as the one from MainActivity, it is
        // just to facilitate communication between the Activity and Fragment
        MainViewModel viewModel = new ViewModelProvider(this).get(MainViewModel.class);

        // as you had it with hard-coded message 2
        // viewModel.setMessage("Message 2");

        //  or like this if you sent the message
        Intent i = getIntent();
        Bundle b = i.getExtras();
        if( b != null ) {
            String msg = b.getString("message");
            viewModel.setMessage(msg);
        }

        Button btn = findViewById(R.id.btn_second);
        btn.setOnClickListener(view -> {
            Intent intent = new Intent();
            intent.putExtra("response", "Message 3");
            setResult(Activity.RESULT_OK, intent);
            finish();
        });
    }
}

MainViewModel.java

public class MainViewModel extends ViewModel {
    private final MutableLiveData<String> message_to_display = new MutableLiveData<>();
    LiveData<String> message() { return message_to_display; }

    void setMessage(String msg) {
        message_to_display.postValue(msg);
    }
}

DisplayFragment.java

public class DisplayFragment extends Fragment {

    public DisplayFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_display, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        TextView txt = view.findViewById(R.id.tv1);

        // Get the ViewModel from the hosting activity, could be
        // Main or Second, and observe its message. Update the
        // TextView if the message is changed.
        MainViewModel viewModel = new ViewModelProvider(requireActivity()).get(MainViewModel.class);
        viewModel.message().observe(getViewLifecycleOwner(), s -> {
            txt.setText(s);
        });
    }
}