Solution 1 :
You are using ViewModel so I think the easiest way is to use the same ViewModel for both fragments. In android docs, You can find an example Share data between fragments
It’s very common that two or more fragments in an activity need to communicate with each other. Imagine a common case of split-view (master-detail) fragments, where you have a fragment in which the user selects an item from a list and another fragment that displays the contents of the selected item.
public class SharedViewModel extends ViewModel {
private final MutableLiveData<Item> selected = new MutableLiveData<Item>();
public void select(Item item) {
selected.setValue(item);
}
public LiveData<Item> getSelected() {
return selected;
}
}
public class MasterFragment extends Fragment {
private SharedViewModel model;
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item);
});
}
}
public class DetailFragment extends Fragment {
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
SharedViewModel model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
model.getSelected().observe(getViewLifecycleOwner(), { item ->
// Update the UI.
});
}
}
Notice that both fragments retrieve the activity that contains them. That way, when the fragments each get the
ViewModelProvider
, they receive the sameSharedViewModel
instance, which is scoped to this activity.
Problem :
The title says it all. I am attempting to send an ArrayList that has data inside from one fragment to another and then switch and show the second fragment (the one that just received the ArrayList).
here is my MainActivity.java:
package;
import android.os.Bundle;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import android.view.View;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
import com.google.android.material.navigation.NavigationView;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.view.Menu;
public class MainActivity extends AppCompatActivity {
private AppBarConfiguration mAppBarConfiguration;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
DrawerLayout drawer = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each menu should be considered as top level destinations.
mAppBarConfiguration = new AppBarConfiguration.Builder(
R.id.nav_home, R.id.nav_display)
.setDrawerLayout(drawer)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onSupportNavigateUp() {
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
return NavigationUI.navigateUp(navController, mAppBarConfiguration) || super.onSupportNavigateUp();
}
}
here is my HomeFragment.java (the sending fragment):
package;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.navigation.Navigation;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.ml.vision.FirebaseVision;
import com.google.firebase.ml.vision.common.FirebaseVisionImage;
import com.google.firebase.ml.vision.text.FirebaseVisionText;
import com.google.firebase.ml.vision.text.FirebaseVisionTextDetector;
import com.mvsolutions.snap.R;
import com.mvsolutions.snap.ui.display.DisplayFragment;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.Inflater;
import static android.app.Activity.RESULT_OK;
public class HomeFragment extends Fragment {
private HomeViewModel homeViewModel;
private ImageView imageView;
private Button captureImageButton, detectButton, pickButton;
private Bitmap imageBitmap;
private TextView capturedTextView;
static final int REQUEST_IMAGE_CAPTURE = 1;
private static final int RESULT_LOAD_IMAGE = 101;
public View onCreateView(@NonNull final LayoutInflater inflater,
final ViewGroup container, Bundle savedInstanceState) {
//View view = inflater.inflate(R.layout.fragment_home, container, false);
View root = inflater.inflate(R.layout.fragment_home, container, false);
detectButton = root.findViewById(R.id.action_homeFragment_to_displayFragment2);
//detectButton.setOnClickListener((View.OnClickListener) this);
//return view;
homeViewModel = ViewModelProviders.of(this).get(HomeViewModel.class);
//View v = inflater.inflate(R.layout.fragment_display, container, false);
imageView = root.findViewById(R.id.home_image_view_img);
capturedTextView = root.findViewById(R.id.home_text_view_txt);
captureImageButton = root.findViewById(R.id.capture_image_btn);
detectButton = root.findViewById(R.id.detect_text_btn);
//pickButton = root.findViewById(R.id.pick_image_btn);
captureImageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
captureImage();
}
});
// pickButton.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// pickImage();
// }
// });
detectButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Navigation.findNavController(v).navigate(R.id.action_homeFragment_to_displayFragment2);
// DisplayFragment displayFragment = new DisplayFragment();
// FragmentManager fragmentManager = getFragmentManager();
// fragmentManager.beginTransaction()
// .replace(R.id.DisplayFragment, displayFragment, displayFragment.getTag())
// .commit();
//detectTextFromImage();
}
});
return root;
}
private void detectTextFromImage() {
capturedTextView.setText("");
FirebaseVisionImage firebaseVisionImage = FirebaseVisionImage.fromBitmap(imageBitmap);
FirebaseVisionTextDetector visionTextDetector = FirebaseVision.getInstance().getVisionTextDetector();
visionTextDetector.detectInImage(firebaseVisionImage).addOnSuccessListener(new OnSuccessListener<FirebaseVisionText>() {
@Override
public void onSuccess(FirebaseVisionText firebaseVisionText) {
List<FirebaseVisionText.Block> textBlocks = firebaseVisionText.getBlocks();
if (textBlocks.size() == 0) {
Toast.makeText(getContext(), "No Text Found", Toast.LENGTH_SHORT).show();
} else {
for (FirebaseVisionText.Block block : textBlocks) {
String text = block.getText();
ArrayList textBlobs = new ArrayList();
textBlobs.add(text);
for(int i = 0; i < textBlobs.size(); i++) {
capturedTextView.setText(capturedTextView.getText() + ", " + textBlobs.get(i));
}
// capturedTextView.setText(capturedTextView.getText() + " " + text);
}
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Toast.makeText(getContext(), "Something went wrong", Toast.LENGTH_SHORT).show();
Log.d("Error", e.getMessage());
}
});
}
private void pickImage() {
Intent i = new Intent(
Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(i, RESULT_LOAD_IMAGE);
}
private void captureImage() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getActivity().getPackageManager()) != null) {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
Bundle extras = data.getExtras();
imageBitmap = (Bitmap) extras.get("data");
imageView.setImageBitmap(imageBitmap);
}
// else if (requestCode == RESULT_LOAD_IMAGE && resultCode == RESULT_OK && null != data) {
// Uri imageUri = data.getData();
// imageBitmap = MediaStore.Images.Media.decodeBitmap(this.);
// imageView.setImageBitmap(imageBitmap);
// }
}
}
here is my DisplayFragment.java (the receiving fragment):
package com.mvsolutions.snap.ui.display;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import com.mvsolutions.snap.R;
public class DisplayFragment extends Fragment {
private DisplayViewModel DisplayViewModel;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
DisplayViewModel =
ViewModelProviders.of(this).get(DisplayViewModel.class);
View root = inflater.inflate(R.layout.fragment_display, container, false);
// final TextView textView = root.findViewById(R.id.text_gallery);
DisplayViewModel.getText().observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
}
});
return root;
}
}
I am currently using a navigation fragment xml file to make the button switch from the first fragment to the second, but I want it to send the data to the second fragment as well.
My two questions are:
- Is it possible to both send the data to the second fragment and switch to the second fragment with one button press? or do I have to split it into two?
- How do I send the data from the first fragment to the second?
Comments
Comment posted by Manuel Mato
There are many options… for example, you could to create a cache repository to persist yout data. Another option is share your viewmodel between fragments… and another option too is to pass your data through arguments (Bundle).
Comment posted by AGoraya0710
@ManuelMato How would I pass my data through the use of arguments and bundling?
Comment posted by developer.android.com/reference/android/app/Fragment
Using bundle: creating a static method in your fragment that returns a bundle with your arguments passing by param. You can see this approach in the official android doc
Comment posted by AGoraya0710
Thank you very much, I just dont understand where to put this, and how to properly use this and access the viewmodelprovider
Comment posted by iknow
You have to connect Your both ViewModels to one and then when You have one ViewModel You just init them in fragment the way like in the example from docs using