I am trying to save all the content of a screen in image format, for this I layout
have a LinearLayout
where all the other elements are added.
<LinearLayout
android:id="@+id/creado"
android:layout_width="match_parent"
android:layout_height="match_parent">
Then, this one is created:
private LinearLayout contenido;
And called in the method onCreate()
:
contenido = (LinearLayout)findViewById(R.id.creado);
To store the entire content of the Layout
, I use the eventsetOnLongClickListener
contenido.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if(permissionHelper.hasPermission()){
GuardarLayout(VistaPrevia.this);
}else{
ejecutar();
}
return true;
}
});
To save it I do the following methods:
private void GuardarLayout(Context context){
contenido.setDrawingCacheEnabled(true);
contenido.buildDrawingCache();
Bitmap bmap = contenido.getDrawingCache();
try {
guardarImagen(bmap);
} catch (Exception e) {
Toast.makeText(context, "Error: " + e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
contenido.destroyDrawingCache();
}
}
private void guardarImagen(Bitmap bitmap) {
if (android.os.Build.VERSION.SDK_INT >= 29) {
ContentValues values = contentValues();
String filePath = "Pictures/" + "Genshin Impact Mis Builds";
values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
values.put(MediaStore.MediaColumns.DATA, filePath);
Uri uri = this.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
if (uri != null) {
try {
guardarImagenParaStream(bitmap, this.getContentResolver().openOutputStream(uri));
values.put(MediaStore.Images.Media.IS_PENDING, false);
Log.d("TRYURINONULL", "guardarImagen: " + uri);
Toast.makeText(this, "¡Se ha guardado tu build de manera exitosa!", Toast.LENGTH_SHORT).show();
} catch (FileNotFoundException e) {
e.printStackTrace();
Log.d("CATCHURINONULL", "guardarImagen: " + uri);
}
}else{
Log.d("URINULA", "guardarImagen: " + uri);
}
} else {
File directorioRuta = new File(Environment.getExternalStorageDirectory().toString() + '/' + getString(R.string.app_name));
if (!directorioRuta.exists()) {
directorioRuta.mkdirs();
}
String nombreDelArchivo = nombrePersonaje + ".jpg";
File archivoFinal = new File(directorioRuta, nombreDelArchivo);
try {
guardarImagenParaStream(bitmap, new FileOutputStream(archivoFinal));
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DATA, archivoFinal.getAbsolutePath());
this.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
private ContentValues contentValues() {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, nombrePersonaje + ".jpg");
values.put(MediaStore.Images.Media.MIME_TYPE, "image/*");
values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis() / 1000);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
}
return values;
}
private void guardarImagenParaStream(Bitmap bitmap, OutputStream outputStream) {
if (outputStream != null) {
try {
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
I have installed the application and noticed the following, first it lets me store the Layout
n times as long as I don't delete the image file from its respective folder. That is, delete your file by going to the path manually and delete it. When doing that, (deleting the image file manually and saving it again), I tried debugging and got this:
First we save the file:
This gives us the following logd:
We verify that it has been stored in the folder:
Then we delete the file:
We return to the App and try to save it again:
He logd
gives us this (uri null):
And, clearly, nothing has been saved:
Why does the Uri
becomes null after manually deleting the file? What am I writing wrong in the code? How can I solve that? From already thank you very much
DESCRIPTION
El problema radica en la siguiente acción. Cuando guardo el archivo por primera vez, puedo guardarlo reiteradas veces (esto va generando algo como archivo1.jpg, archivo2.jpg) pero cuando me dirijo a su respectiva carpeta (actualmente Pictures/Genshin Impact Mis Builds
) y borro dichos archivos, al momento de querer guardar el archivo otra vez es cuando la uri
adquiere el valor null
. ¿Cómo puedo solucionar eso?
El problema es que el path es incorrecto al ver tu còdigo la imagen se tratarìa de guardar en la siguiente ruta que es incorrecta:
Se puede ver en los valores definidos para el guardado de la imagen
Debes realizarlo de esta forma:
Aquì si obtendràs un valor al obtener la Uri:
Actualizaciòn:
Pensaba que el problema se debería a el sistema operativo pero no hay ningún problema, el problema se debe en realidad a las rutas que usas para guardar los archivos, comentas que el problema radica en que cuando eliminas el archivo no puedes volver a guardarlo.
Revisando a detalle encontré el problema, creas un archivo y verificas si este existe mediante:
pero posteriormente usas como ruta donde se crearía el archivo:
No debes definir el path mediante "/sdcard/Pictures/" ya que la ruta puede ser diferente en los dispositivos, seguramente tu aplicación guardo una imagen en otra ubicación y al validar ya no permite crear una nueva aunque no exista en la ubicación que deseas, esto sucede en este método:
de hecho usando
Environment.getExternalStorageDirectory() + "/Pictures"
se obtiene la ruta :pero usando
/sdcard/Pictures/
se obtiene otra ruta de archivo diferente:Debes usar solo una clase para almacenar y verificar la existencía de tu archivo, en el caso de tu aplicación usa
Environment.getExternalStorageDirectory() + "/Pictures"
Es
null
porque estás usando unMediaStore.DownloadColumns.RELATIVE_PATH
sin checar elBuild.VERSION.SDK_INT
. Encontré este gist que funciona ala perfección.Tu
GuardarLayout
sería:Tal como indica la documentacion de ContentProvider cuando haces un
insert
:Intenta llamar al método
notifyChange(uri, null)
luego de la inserción de los archivos. Para evitar temas deContext
y/o fallos con el ciclo de vida, usaApplicationContext
en vez deContext
de tu actividad para ejecutar la acción de guardar la imagen. Puede ser que el problema este relacionado al contexto y un problema de sincronización. Puedes verificar esto, corriendo la siguiente secuencia:null
, entonces procede con el paso 4.null
, the problem may be related to the Context, so try usingApplicationContext
to get the instance of theContentProvider
.You can review the official documentation to verify that everything is in order. I leave you an example gist that I create, let me know if it works for you.