Usando arquivo JSON em recursos de aplicativos Android

87

Suponha que eu tenha um arquivo com conteúdo JSON na pasta de recursos brutos em meu aplicativo. Como posso ler isso no aplicativo, para poder analisar o JSON?

yydl
fonte

Respostas:

143

Veja openRawResource . Algo assim deve 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
fonte
1
E se eu quiser colocar a string em um recurso String no android e usá-la dinamicamente usando getResources (). GetString (R.String.name)?
Ankur Gautam
Para mim não funciona por causa das citações, que são ignoradas durante a leitura e que também parecem não podem ser escapadas
Marian Klühspies
1
Existe alguma maneira de fazer ButterKnife vincular o recurso bruto? Escrever mais de 10 linhas de código apenas para ler uma string parece um pouco exagero.
Jezor
Como o json é armazenado dentro dos recursos? Simplesmente dentro da \res\json_file.jsonpasta ou dentro \res\raw\json_file.json?
Cliff Burton
Esta resposta carece de informações críticas. Onde posso getResources()ser chamado? Para onde deve ir o arquivo de recurso bruto? Que convenção você deve seguir para garantir que as ferramentas de construção criem R.raw.json_file?
NobodyMan
112

Kotlin agora é a linguagem oficial do Android, então acho que isso seria útil para alguém

val text = resources.openRawResource(R.raw.your_text_file)
                                 .bufferedReader().use { it.readText() }
Dima Rostopira
fonte
Esta é uma operação potencialmente longa, portanto, certifique-se de que ela seja cancelada no thread principal!
Andrew Orobator
@AndrewOrobator Eu duvido que alguém colocaria big json dentro dos recursos do aplicativo, mas sim, bom ponto
Dima Rostopira
24

Usei a resposta de @kabuko para criar um objeto que carrega de um arquivo JSON, usando Gson , a partir de 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 usá-lo, você faria algo como o seguinte (o exemplo está em um 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
fonte
3
Não se esqueça de adicionar dependências {compile com.google.code.gson: gson: 2.8.2 '} ao seu arquivo
Gradle
a última versão do GSON éimplementation 'com.google.code.gson:gson:2.8.5'
Daniel,
12

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


Arquivos brutos / arbitrários para salvar em sua forma bruta. Para abrir esses recursos com um InputStream bruto, chame Resources.openRawResource () com o ID do recurso, que é R.raw.filename.

No entanto, se você precisar de acesso aos nomes de arquivos originais e à hierarquia de arquivos, pode considerar salvar alguns recursos no diretório assets / (em vez de res / raw /). Os arquivos em ativos / não recebem um ID de recurso, portanto, você pode lê-los apenas usando AssetManager.

mah
fonte
5
Se eu quiser incorporar um arquivo JSON em meu aplicativo, onde devo colocá-lo? na pasta de ativos ou pasta bruta? Obrigado!
Ricardo
12

Como os estados @mah, a documentação do Android ( https://developer.android.com/guide/topics/resources/providing-resources.html ) diz que os arquivos json podem ser salvos no diretório / raw sob / res (recursos) diretório em seu projeto, por exemplo:

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

Dentro de um Activity, o arquivo json pode ser acessado por meio da Rclasse (Recursos) e lido em uma String:

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

Isso usa a classe Java Scanner, levando a menos linhas de código do que alguns outros métodos de leitura de um arquivo texto / json simples. O padrão delimitador \Asignifica 'o início da entrada'. .next()lê o próximo token, que é o arquivo inteiro neste caso.

Existem várias maneiras de analisar a string json resultante:

ʕ ᵔᴥᵔ ʔ
fonte
1
esta deve ser a resposta aceita, apenas duas linhas e pronto
Obrigado
necessidadesimport 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
fonte
1

Usando:

String json_string = readRawResource(R.raw.json)

Funções:

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
fonte
0

Encontrado resposta esta Kotlin trecho muito útil ♥ ️

Embora a pergunta original fosse para obter uma String JSON, acho que alguns podem achar isso útil. Um passo adiante Gsonleva a esta pequena função com 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)
    }
}

Observe que você não quer usar TypeTokenapenas T::classisso, se ler um, List<YourType>você não perderá o tipo por tipo de apagamento.

Com a inferência de tipo, você pode usar desta forma:

fun pricingData(): List<PricingData> = readRawJson(R.raw.mock_pricing_data)
poderoso jon
fonte