Uso de archivos JSON en recursos de aplicaciones de Android

87

Supongamos que tengo un archivo con contenido JSON en la carpeta de recursos sin procesar en mi aplicación. ¿Cómo puedo leer esto en la aplicación para poder analizar el JSON?

yydl
fuente

Respuestas:

143

Consulte openRawResource . Algo como esto debería funcionar:

InputStream is = getResources().openRawResource(R.raw.json_file);
Writer writer = new StringWriter();
char[] buffer = new char[1024];
try {
    Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
    int n;
    while ((n = reader.read(buffer)) != -1) {
        writer.write(buffer, 0, n);
    }
} finally {
    is.close();
}

String jsonString = writer.toString();
kabuko
fuente
1
¿Qué pasa si quiero poner la cadena en un recurso String en Android y usarla dinámicamente usando getResources (). GetString (R.String.name)?
Ankur Gautam
Para mí no funciona por las citas, que se ignoran al leer y que también parecen no poder escapar
Marian Klühspies
1
¿Hay alguna forma de hacer que ButterKnife se una al recurso crudo? Escribir más de 10 líneas de código solo para leer una cadena parece un poco exagerado.
Jezor
¿Cómo se almacena el json dentro de los recursos? ¿Simplemente dentro de la \res\json_file.jsoncarpeta o dentro \res\raw\json_file.json?
Cliff Burton
Esta respuesta carece de información crítica. ¿Dónde se getResources()puede llamar? ¿Dónde debe ir el archivo de recursos sin procesar? ¿Qué convención debe seguir para asegurarse de que se crean las herramientas de compilación R.raw.json_file?
NobodyMan
112

Kotlin ahora es el idioma oficial de Android, así que creo que esto sería útil para alguien.

val text = resources.openRawResource(R.raw.your_text_file)
                                 .bufferedReader().use { it.readText() }
Dima Rostopira
fuente
Esta es una operación potencialmente de larga duración, ¡así que asegúrese de que se llame fuera del hilo principal!
Andrew Orobator
@AndrewOrobator Dudo que alguien ponga un gran json dentro de los recursos de la aplicación, pero sí, buen punto
Dima Rostopira
24

Usé la respuesta de @ kabuko para crear un objeto que se carga desde un archivo JSON, usando Gson , desde los Recursos:

package com.jingit.mobile.testsupport;

import java.io.*;

import android.content.res.Resources;
import android.util.Log;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;


/**
 * An object for reading from a JSON resource file and constructing an object from that resource file using Gson.
 */
public class JSONResourceReader {

    // === [ Private Data Members ] ============================================

    // Our JSON, in string form.
    private String jsonString;
    private static final String LOGTAG = JSONResourceReader.class.getSimpleName();

    // === [ Public API ] ======================================================

    /**
     * Read from a resources file and create a {@link JSONResourceReader} object that will allow the creation of other
     * objects from this resource.
     *
     * @param resources An application {@link Resources} object.
     * @param id The id for the resource to load, typically held in the raw/ folder.
     */
    public JSONResourceReader(Resources resources, int id) {
        InputStream resourceReader = resources.openRawResource(id);
        Writer writer = new StringWriter();
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(resourceReader, "UTF-8"));
            String line = reader.readLine();
            while (line != null) {
                writer.write(line);
                line = reader.readLine();
            }
        } catch (Exception e) {
            Log.e(LOGTAG, "Unhandled exception while using JSONResourceReader", e);
        } finally {
            try {
                resourceReader.close();
            } catch (Exception e) {
                Log.e(LOGTAG, "Unhandled exception while using JSONResourceReader", e);
            }
        }

        jsonString = writer.toString();
    }

    /**
     * Build an object from the specified JSON resource using Gson.
     *
     * @param type The type of the object to build.
     *
     * @return An object of type T, with member fields populated using Gson.
     */
    public <T> T constructUsingGson(Class<T> type) {
        Gson gson = new GsonBuilder().create();
        return gson.fromJson(jsonString, type);
    }
}

Para usarlo, haría algo como lo siguiente (el ejemplo está en una InstrumentationTestCase):

   @Override
    public void setUp() {
        // Load our JSON file.
        JSONResourceReader reader = new JSONResourceReader(getInstrumentation().getContext().getResources(), R.raw.jsonfile);
        MyJsonObject jsonObj = reader.constructUsingGson(MyJsonObject.class);
   }
jwir3
fuente
3
No olvide agregar las dependencias {compile com.google.code.gson: gson: 2.8.2 '} a su archivo gradle
patrics
La última versión de GSON esimplementation 'com.google.code.gson:gson:2.8.5'
Daniel
12

De http://developer.android.com/guide/topics/resources/pro provide - resources.html :

crudo/
Archivos sin arbitrarios para guardar en su forma sin procesar. Para abrir estos recursos con un InputStream sin procesar, llame a Resources.openRawResource () con el ID del recurso, que es R.raw.filename.

Sin embargo, si necesita acceder a los nombres de archivo originales y la jerarquía de archivos, podría considerar guardar algunos recursos en el directorio assets / (en lugar de res / raw /). Los archivos en assets / no reciben una ID de recurso, por lo que solo puede leerlos usando AssetManager.

mah
fuente
5
Si quiero incrustar un archivo JSON en mi aplicación, ¿dónde debería colocarlo? en la carpeta de activos o en la carpeta sin formato? ¡Gracias!
Ricardo
12

Como afirma @mah, la documentación de Android ( https://developer.android.com/guide/topics/resources/pro provide-resources.html ) dice que los archivos json se pueden guardar en el directorio / raw bajo / res (recursos) directorio en su proyecto, por ejemplo:

MyProject/
  src/ 
    MyActivity.java
  res/
    drawable/ 
        graphic.png
    layout/ 
        main.xml
        info.xml
    mipmap/ 
        icon.png
    values/ 
        strings.xml
    raw/
        myjsonfile.json

Dentro de un Activity, se puede acceder al archivo json a través de la Rclase (Resources) y leerlo en un String:

Context context = this;
Inputstream inputStream = context.getResources().openRawResource(R.raw.myjsonfile);
String jsonString = new Scanner(inputStream).useDelimiter("\\A").next();

Esto usa la clase Java Scanner, lo que lleva a menos líneas de código que algunos otros métodos para leer un archivo simple de texto / json. El patrón delimitador \Asignifica 'el comienzo de la entrada'. .next()lee el siguiente token, que es el archivo completo en este caso.

Hay varias formas de analizar la cadena json resultante:

ʕ ᵔᴥᵔ ʔ
fuente
1
esta debería ser la respuesta aceptada, solo dos líneas y listo.Gracias
Ashana.Jackol
necesidadesimport java.util.Scanner; import java.io.InputStream; import android.content.Context;
AndrewHarvey
4
InputStream is = mContext.getResources().openRawResource(R.raw.json_regions);
                            int size = is.available();
                            byte[] buffer = new byte[size];
                            is.read(buffer);
                            is.close();
                           String json = new String(buffer, "UTF-8");
NickUnuchek
fuente
1

Utilizando:

String json_string = readRawResource(R.raw.json)

Funciones:

public String readRawResource(@RawRes int res) {
    return readStream(context.getResources().openRawResource(res));
}

private String readStream(InputStream is) {
    Scanner s = new Scanner(is).useDelimiter("\\A");
    return s.hasNext() ? s.next() : "";
}
Mahdi Astanei
fuente
0

Encontré esta respuesta de fragmento de Kotlin muy útil ♥ ️

Si bien la pregunta original pedía obtener una cadena JSON, creo que algunos podrían encontrar esto útil. Un paso más allá Gsonconduce a esta pequeña función con tipo reificado:

private inline fun <reified T> readRawJson(@RawRes rawResId: Int): T {
    resources.openRawResource(rawResId).bufferedReader().use {
        return gson.fromJson<T>(it, object: TypeToken<T>() {}.type)
    }
}

Tenga en cuenta que desea utilizar TypeTokenno solo T::classsi lee unList<YourType> no perderá el borrado tipo por tipo.

Con la inferencia de tipo, puede usar así:

fun pricingData(): List<PricingData> = readRawJson(R.raw.mock_pricing_data)
theightyjon
fuente