Search code examples
androidandroid-fragmentsandroid-dialogfragmentandroid-camera-intentdialogfragment

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.


Solution

  • 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.