简体   繁体   中英

How to take images in android and save it on gallery as well as in the app-specific storage ? (java, android studio)

I want to call the camera through intent, capture images, and save it locally in the gallery and in the app-specific storage how can I achieve that?

I went through this question also but the code is not working I don't know why.

I'm assuming the app-specific storage is some sort of cache, in your onActivityResult() wouldn't you save the picture first to app-specific storage and then copy it to Environment.DIRECTORY_PICTURES ?

Whenever you take a photo from the device, you the image uri in the onActivityResult . Now to save it to another location, you can use the code given below

void savefile(Uri sourceuri){
    String sourceFilename= sourceuri.getPath();
    String destinationFilename = android.os.Environment.getExternalStorageDirectory().getPath()+File.separatorChar+"abc.mp3";

    BufferedInputStream bis = null;
    BufferedOutputStream bos = null;

    try {
      bis = new BufferedInputStream(new FileInputStream(sourceFilename));
      bos = new BufferedOutputStream(new FileOutputStream(destinationFilename, false));
      byte[] buf = new byte[1024];
      bis.read(buf);
      do {
         bos.write(buf);
      } while(bis.read(buf) != -1);
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      try {
        if (bis != null) bis.close();
        if (bos != null) bos.close();
      } catch (IOException e) {
            e.printStackTrace();
      }
   }
}

And in the onActivityResult , you can call it like this

saveFile(data.getData());

I have done something like this Before, I Share my code with you and others that may help.
in this scenario if you want to save captured image, you have to check which api level that device is running with. for api level 28 and below you have to use specific method and for api level 28 above you have specific way. so first step, start from:
AndroidManifest.xml

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    android:maxSdkVersion="28" tools:ignore="ScopedStorage"/>

and add this line in to your AndroidManifest.xml application tag:

android:requestLegacyExternalStorage="true"

if your project targetSdkVersion is 28 and above, you have to use ActivityResultLauncher otherwise you have to override onRequestPermissionResult in your fragment or activity.
if you use fragment you have to register your ActivityResultLauncher in onAttach method, if not register it in onCreate of your Activity, so do this:

public class YourFragment extends Fragment {
   private Bitmap bitmap;
   private ActivityResultLauncher<String> storageResultActivity;


    @Override
    public void onAttach(@NonNull @NotNull Context context) {
       super.onAttach(context);
       registerWriteExternalStoragePermission();
    }

registerWriteExternalStoragePermission has this codes:

    private void registerWriteExternalStoragePermission() {
    storageResultActivity = registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
        if (isGranted) {
            checkStoragePermissionAndSaveImage(bitmap);
        }
    });
}

so next step is to get back result of captured image from intent and change it to Bitmap for this section we need another activityResultLauncher so do this in onAttach of your fragment or onCreate of your activity:

ActivityResultLauncher<Intent> activityResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
    if (result.getResultCode() == RESULT_OK) {
       Intent data = result.getData();
       if (data == null || data.getData() == null) {
          //showError
       }
       Uri uri = data.getData();
        if (Build.VERSION.SDK_INT < 29) {
            bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), uri);
        } else {
            ImageDecoder.Source source = ImageDecoder.createSource(context.getContentResolver(), uri);
            bitmap = ImageDecoder.decodeBitmap(source);
        }
    }

so next step is to check your app has storage permission or not:

    if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
        saveImageInAndroidApi28AndBelow(bitmap);
    } else if (ActivityCompat.shouldShowRequestPermissionRationale(requireActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
        //show user app can't save image for storage permission denied
    } else {
        storageResultActivity.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE);
    }

ok as we near the end of this answer:) you have to implement saveImageInAndroidApi28AndBelow method, se lets go to do it:

    private boolean saveImageInAndroidApi28AndBelow(Bitmap bitmap) {
    OutputStream fos;
    String imagesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString();
    File image = new File(imagesDir, "IMG_" + System.currentTimeMillis() + ".png");
    try {
        fos = new FileOutputStream(image);
        bitmap.compress(Bitmap.CompressFormat.PNG, 95, fos);
        Objects.requireNonNull(fos).close();
    } catch (IOException e) {
        e.printStackTrace();
        //isSuccess = false;
        return false;
    }
    //isSuccess = true;
    return true;
}

and the final step is to implement saveImageInAndroidApi29AndAbove method do it like this:

@NonNull
public Uri saveImageInAndroidApi29AndAbove(@NonNull final Bitmap bitmap) throws IOException {
    final ContentValues values = new ContentValues();
    values.put(MediaStore.MediaColumns.DISPLAY_NAME, "IMG_" + System.currentTimeMillis());
    values.put(MediaStore.MediaColumns.MIME_TYPE, "image/png");
    if (SDK_INT >= Build.VERSION_CODES.Q) {
        values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM);
    }
    final ContentResolver resolver = requireContext().getContentResolver();
    Uri uri = null;
    try {
        final Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        uri = resolver.insert(contentUri, values);
        if (uri == null) {
            //isSuccess = false;
            throw new IOException("Failed to create new MediaStore record.");
        }
        try (final OutputStream stream = resolver.openOutputStream(uri)) {
            if (stream == null) {
                //isSuccess = false;
                throw new IOException("Failed to open output stream.");
            }
            if (!bitmap.compress(Bitmap.CompressFormat.PNG, 95, stream)) {
                //isSuccess = false;
                throw new IOException("Failed to save bitmap.");
            }
        }
        //isSuccess = true;
        return uri;
    } catch (IOException e) {
        if (uri != null) {
            resolver.delete(uri, null, null);
        }
        throw e;
    }
}

so you have to check which API Level that device is running and with with little code handle what you want:

            if (SDK_INT >= Build.VERSION_CODES.Q) {
            try {
                saveImageInAndroidApi29AndAbove(bitmap);
            } catch (Exception e) {
               //show error to user that operatoin failed
            }
        } else {
            saveImageInAndroidApi28AndBelow(bitmap);
        }

Don't FORGET TO call.launch ON YOUR ActivityResultLauncher

have a good time with the codes:)

Simple, make a Launcher attach the camera and gallery and you have everything in one place, here I send you 2 links to make a launcher

https://code.tutsplus.com/es/tutorials/build-a-custom-launcher-on-android--cms-21358

https://steemit.com/utopian-io/@ideba/how-to-build-a-custom-android-launcher-and-home-screen-application-part-1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM