mungaih pk mungaih pk - 3 months ago 29
Android Question

Send data from one DialogFragment to another in Android

I have three fragments namely the

AudioRecorderFragment
which is a
Fragment
,
UploadFragment
which is a
DialogFragment
and another
DialogFragment
known as
UploadPhotoDialog
.

A user should record audio from the
AudioRecorderFragment
and then on hitting an upload button, the
UploadFragment
shows. In the
UploadFragment
, the user will enter the details of the recorded audio clip and may include an image. When selecting the image, the
UploadPhotoDialog
fragment shows up and the user can select whether to take a photo using the camera or pick one from gallery. My problem is how to get the selection from the
UploadPhotoDialog
back to the
UploadFragment
. I am not getting a result. Also when I try to call a camera intent from the
UploadFragment
, I get a null pointer exception in the

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

// get the file url
fileUri = savedInstanceState.getParcelable("file_uri");
}


on the fileUri ... line whenever i want to show the fragment from my AudioRecorderFragment. How can I solve this?
Here is my
UploadFragment
code:

public class UploadFragment extends DialogFragment implements AdapterView.OnItemSelectedListener, View.OnClickListener {
Spinner genres;
ImageView photo;
TextView submit;
String fileName="";

private static final String KEY="choice";

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Get the layout inflater
LayoutInflater inflater = getActivity().getLayoutInflater();
View v = inflater.inflate(R.layout.fragment_upload, null);
builder.setView(v);

submit = (TextView)v.findViewById(R.id.upload_textView_submit);
genres = (Spinner) v.findViewById(R.id.upload_spinner_genre);
photo = (ImageView) v.findViewById(R.id.upload_imageView_photo);

ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(getActivity(),
R.layout.ngoma_spinner, getResources().getStringArray(R.array.genres));
dataAdapter
.setDropDownViewResource(android.R.layout.simple_dropdown_item_1line);
genres.setAdapter(dataAdapter);


Bundle bundle = this.getArguments();
if(bundle != null){
fileName = bundle.getString("arg_fileName");
}

genres.setOnItemSelectedListener(this);
submit.setOnClickListener(this);
photo.setOnClickListener(this);
return builder.create();
}

@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

}

@Override
public void onNothingSelected(AdapterView<?> parent) {

}

private static final int INT_CODE=1;
@Override
public void onClick(View v) {
switch(v.getId()){
case R.id.upload_textView_submit:
getDialog().dismiss();
break;
case R.id.upload_imageView_photo:
UploadPhotoDialog uploadDialog = new UploadPhotoDialog();
uploadDialog.setTargetFragment(this, INT_CODE);
uploadDialog.show(getActivity().getSupportFragmentManager(), "uploadPhoto");
break;
}
}


/******************************************************************************************************/

private static final int CAMERA_CAPTURE_IMAGE_REQUEST_CODE = 100;
public static final int MEDIA_TYPE_IMAGE = 1;
private static int RESULT_LOAD_IMAGE = 1;


/**
* Select image from gallery
*/
private void selectFromGallery() {
Intent i = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);

startActivityForResult(i, RESULT_LOAD_IMAGE);
}

/**
* Capturing Camera Image will lauch camera app requrest image capture
*/
private void captureImage() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);

intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);

// start the image capture Intent
startActivityForResult(intent, CAMERA_CAPTURE_IMAGE_REQUEST_CODE);
}

/**
* Here we store the file url as it will be null after returning from camera
* app
*/

// directory name to store captured images and videos
private static final String IMAGE_DIRECTORY_NAME = "ngoma";

private Uri fileUri; // file url to store image/video

@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);

// save file url in bundle as it will be null on screen orientation
// changes
outState.putParcelable("file_uri", fileUri);
}

/*
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);

// get the file url
fileUri = savedInstanceState.getParcelable("file_uri");
}*/

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

// get the file url
// fileUri = savedInstanceState.getParcelable("file_uri");
}

/**
* Receiving activity result method will be called after closing the camera
* */
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode,resultCode, data);
// if the result is capturing Image
if (requestCode == CAMERA_CAPTURE_IMAGE_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
// successfully captured the image
// display it in image view
previewCapturedImage();
} else if (resultCode == Activity.RESULT_CANCELED) {
// user cancelled Image capture
Toast.makeText(getActivity().getApplicationContext(),
"User cancelled image capture", Toast.LENGTH_SHORT)
.show();
} else {
// failed to capture image
Toast.makeText(getActivity().getApplicationContext(),
"Sorry! Failed to capture image", Toast.LENGTH_SHORT)
.show();
}
} else if (requestCode == RESULT_LOAD_IMAGE && resultCode == Activity.RESULT_OK
&& null != data) {
Uri selectedImage = data.getData();
String[] filePathColumn = { MediaStore.Images.Media.DATA };

Cursor cursor = getActivity().getContentResolver().query(selectedImage,
filePathColumn, null, null, null);
cursor.moveToFirst();

int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();

// String picturePath contains the path of selected Image
previewFromGallery(picturePath);
}

if (requestCode == INT_CODE) { //make sure fragment codes match up {
String choice = data.getStringExtra(KEY);

if(choice.equalsIgnoreCase("camera")){
captureImage();
}

else if(choice.equalsIgnoreCase("gallery")){
selectFromGallery();
}

}
}

/**
* Display image from a path to ImageView
*/
private void previewCapturedImage() {
try {

// bimatp factory
BitmapFactory.Options options = new BitmapFactory.Options();

// downsizing image as it throws OutOfMemory Exception for larger
// images
options.inSampleSize = 8;

final Bitmap bitmap = BitmapFactory.decodeFile(fileUri.getPath(),
options);

photo.setImageBitmap(bitmap);
} catch (NullPointerException e) {
e.printStackTrace();
}
}

private void previewFromGallery(String picturePath) {
photo.setImageBitmap(BitmapFactory.decodeFile(picturePath));
}

/**
* ------------ Helper Methods ----------------------
* */

/**
* Creating file uri to store image/video
*/
public Uri getOutputMediaFileUri(int type) {
return Uri.fromFile(getOutputMediaFile(type));
}

/**
* returning image / video
*/
private static File getOutputMediaFile(int type) {

// External sdcard location
File mediaStorageDir = new File(
Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
IMAGE_DIRECTORY_NAME);

// Create the storage directory if it does not exist
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.d(IMAGE_DIRECTORY_NAME, "Oops! Error creating "
+ IMAGE_DIRECTORY_NAME + " directory.");
return null;
}
}

// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",
Locale.getDefault()).format(new Date());
File mediaFile;
if (type == MEDIA_TYPE_IMAGE) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator
+ "IMG_" + timeStamp + ".jpg");
} else {
return null;
}

return mediaFile;
}

}


And the UploadPhotoDialog fragment code

public class UploadPhotoDialog extends DialogFragment implements View.OnClickListener {
LinearLayout fromgallery, fromcamera;
String choice;

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Get the layout inflater
LayoutInflater inflater = getActivity().getLayoutInflater();
View v = inflater.inflate(R.layout.fragment_uploadphoto_dialog, null);
// Inflate and set the layout for the dialog
// Pass null as the parent view because its going in the dialog layout
choice = "";
builder.setView(v);

fromgallery = (LinearLayout) v
.findViewById(R.id.uploadphoto_gallery_layout);
fromcamera = (LinearLayout) v
.findViewById(R.id.uploadphoto_camera_layout);

fromcamera.setOnClickListener(this);
fromgallery.setOnClickListener(this);
return builder.create();
}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.uploadphoto_gallery_layout:
// Intent intent = new Intent(getActivity(), AudioRecorder.class);
//startActivity(intent);

//AudioRecorderFragment audioRecorder= new AudioRecorderFragment();
//getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.content_frame,audioRecorder).commit();

choice ="gallery";
getDialog().dismiss();
break;
case R.id.uploadphoto_camera_layout:
//Intent intentVideo = new Intent(getActivity(), VideoRecorderActivity.class);
//startActivity(intentVideo);
choice ="camera";
getDialog().dismiss();
break;
}

}

private static final String KEY="choice";
private static final int INT_CODE=1;

private void sendResult(int INT_CODE) {
Intent i = new Intent();
i.putExtra(KEY, choice);
getTargetFragment().onActivityResult(getTargetRequestCode(), INT_CODE, i);
}
}


Sorry, I know thats a lot of code but it's my best way of expressing my problem.
Help will be highly appreciated.

Thanks in advance.

Answer

When you show your fragment you can also pass data through the setArguments function of the fragment or by establishing an Interface between the two fragments, something along the lines:

public Interface IReceiveChoice {
   void Selected(int choice);
}

then in the class you want to choose you implement IReceiveChoice;

public class UploadPhotoDialog extends DialogFragment implements View.OnClickListener, IReceiveChoice {
  @Override 
  public void Selected(int choice) {
     //do stuff
  }
  ....

And when you choose in the first activity you find the other activity, cast it to an IReceiveChoice and call the method Selected with your choice.

Fragment f = getTargetFragment(); 
if(f != null && f instanceof IReceiveChoice) {
  f.Selected(choice);
}

There you have to ensure that the fragment exists but it is an alternative to sending a whole lot of bundles everywhere if your data is small and simple.