5

I have parsed the JSON Data in a listview and now I want to make it available offline. Is there a way to save the JSON data at the phone so that you can see the data if your phone is offline?

Does someone knows an example?

EDIT works now:

 public class MainActivity extends ListActivity {


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        new TheTask().execute();
    }

    class TheTask extends AsyncTask<Void, Void, JSONArray> {
        InputStream is = null;
        String result = "";
        JSONArray jArray = null;

        ProgressDialog pd;

        @Override
        protected void onPostExecute(JSONArray result) {
            super.onPostExecute(result);
            pd.dismiss();
            ArrayList<String> list= new ArrayList<String>();
            try {
                for(int i=0;i<result.length();i++) {

                    JSONObject jb = result.getJSONObject(i) ;
                    String name = jb.getString("name")+" "+jb.getString("Art");
                    list.add(name);
                }
            } catch(Exception e) {
                e.printStackTrace();
            }
            setListAdapter(new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, list));
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            pd = ProgressDialog.show(MainActivity.this, "State",
                    "Loading...", true);
        }

        @Override
        protected JSONArray doInBackground(Void... arg0) {
            ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

                try {
                    HttpClient httpclient = new DefaultHttpClient();
                    HttpPost httppost = new HttpPost("***");
                    HttpResponse response = httpclient.execute(httppost);
                    HttpEntity entity = response.getEntity();
                    is = entity.getContent();
                } catch (Exception e) {
                    Log.e("log_tag", "Error in http connection " + e.toString());
                }

                // Convert response to string
                try {
                    BufferedReader reader = new BufferedReader(new InputStreamReader(
                            is, "iso-8859-1"), 8);
                    StringBuilder sb = new StringBuilder();
                    String line = null;
                    while ((line = reader.readLine()) != null) {
                        sb.append(line + "\n");
                    }
                    is.close();
                    result = sb.toString();
                    writeToFile(result);
                } catch (Exception e) {
                    Log.e("log_tag", "Error converting result " + e.toString());
                }

                try {
                    jArray = new JSONArray(result);
                } catch (JSONException e) {
                    Log.e("log_tag", "Error parsing data " + e.toString());
                }

                try {
                    jArray = new JSONArray(readFromFile());
                } catch (JSONException e) {
                    Log.e("log_tag", "Error parsing data " + e.toString());
                }

            return jArray;
        }
    }

    private void writeToFile(String data) {
        try {
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(openFileOutput("config.txt", Context.MODE_PRIVATE));
            outputStreamWriter.write(data);
            outputStreamWriter.close();
        }
        catch (IOException e) {
            Log.e("Exception", "File write failed: " + e.toString());
        }
    }

    private String readFromFile() {

        String ret = "";

        try {
            InputStream inputStream = openFileInput("config.txt");

            if ( inputStream != null ) {
                InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
                BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
                String receiveString = "";
                StringBuilder stringBuilder = new StringBuilder();

                while ( (receiveString = bufferedReader.readLine()) != null ) {
                    stringBuilder.append(receiveString);
                }

                inputStream.close();
                ret = stringBuilder.toString();
            }
        } catch (FileNotFoundException e) {
            Log.e("login activity", "File not found: " + e.toString());
        } catch (IOException e) {
            Log.e("login activity", "Can not read file: " + e.toString());
        }

        return ret;
    }
}
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
user3241084
  • 87
  • 1
  • 1
  • 11

7 Answers7

16

You have two ways. Either you create a database and save all of the data there and retrieve it back when you want to. Or if the data you have is not that much and you don't want to deal with databases, then you write the json string to a text file in the memory card and read it later when you are offline.

And for the second case, every time you go online, you can retrieve the same json from your web service and over write it to the old one. This way you can be sure that you have the latest json saved to the device.

osayilgan
  • 5,873
  • 7
  • 47
  • 68
  • Depending on the JSON (if it is couple of entries), @user3241084 can use [`SharedPreferences`](http://developer.android.com/reference/android/content/SharedPreferences.html). – Yordan Lyubenov Jan 30 '14 at 15:40
  • 1
    @YordanLyubenov considering that user wants to store JSON object programatically when it's offline, I don't think it's just a couple of entries. – osayilgan Jan 30 '14 at 16:11
  • how can I add this to my code? I just tried but nothin worked? – user3241084 Jan 30 '14 at 16:11
  • @user3241084 post your tries here – Raghunandan Jan 30 '14 at 16:16
  • @user3241084 it's easy to find it on internet. Just search "how to read/ write file in android". I found this link, it should work. http://stackoverflow.com/questions/14376807/how-to-read-write-string-from-a-file-in-android – osayilgan Jan 30 '14 at 16:30
  • my app quits but i dont know why – user3241084 Jan 30 '14 at 17:03
  • I edited the code now and added the logcat then u can see whats wrong? – user3241084 Jan 30 '14 at 17:10
  • Here is your answer. http://stackoverflow.com/questions/2850573/activity-has-leaked-window-that-was-originally-added – osayilgan Jan 30 '14 at 17:20
  • and where am I trying to show a Dialog after I have exited an Activity? – user3241084 Jan 30 '14 at 17:33
  • Activity might be exiting because of an exception occurs there in the thread. So you need to add dialog.dismiss() to onPause of your activity. That way you guarantee that the dialog will be dismissed when any thing goes wrong causing an exit of your activity. – osayilgan Jan 30 '14 at 17:36
3

this class will help you cache strings in files with a key to retrieve later on. the string can be a json string and key can be the url you requested and also an identifier for the url if you are using post method.

public class CacheHelper {

static int cacheLifeHour = 7 * 24;

public static String getCacheDirectory(Context context){

    return context.getCacheDir().getPath();
}

public static void save(Context context, String key, String value) {

    try {

        key = URLEncoder.encode(key, "UTF-8");

        File cache = new File(getCacheDirectory(context) + "/" + key + ".srl");

        ObjectOutput out = new ObjectOutputStream(new FileOutputStream(cache));
        out.writeUTF(value);
        out.close();
    } catch (Exception e) {

        e.printStackTrace();
    }
}

public static void save(Context context, String key, String value, String identifier) {

   save(context, key + identifier, value);
}

public static String retrieve(Context context, String key, String identifier) {

   return retrieve(context, key + identifier);
}


public static String retrieve(Context context, String key) {

    try {

        key = URLEncoder.encode(key, "UTF-8");

        File cache = new File(getCacheDirectory(context) + "/" + key + ".srl");

        if (cache.exists()) {

            Date lastModDate = new Date(cache.lastModified());
            Date now = new Date();

            long diffInMillisec = now.getTime() - lastModDate.getTime();
            long diffInSec = TimeUnit.MILLISECONDS.toSeconds(diffInMillisec);

            diffInSec /= 60;
            diffInSec /= 60;
            long hours = diffInSec % 24;

            if (hours > cacheLifeHour) {
                cache.delete();
                return "";
            }

            ObjectInputStream in = new ObjectInputStream(new FileInputStream(cache));
            String value = in.readUTF();
            in.close();

            return value;
        }

    } catch (Exception e) {

        e.printStackTrace();
    }

    return "";
}
}

how to use it :

String string = "cache me!";
String key = "cache1";
CacheHelper.save(context, key, string);
String getCache = CacheHelper.retrieve(context, key); // will return 'cache me!'
Ashkan Ghodrat
  • 3,162
  • 2
  • 32
  • 36
0

Once you download the data you could persist the data on the mobile, using a database or a system of your preference.

You can check the different options here: data-storage

Javier Salinas
  • 617
  • 6
  • 15
0

You can use those two methods two store you JSON file as a string in your SharedPreferences and retrieve it back:

public String getStringProperty(String key) {
    sharedPreferences = context.getSharedPreferences("preferences", Activity.MODE_PRIVATE);
    String res = null;
    if (sharedPreferences != null) {
        res = sharedPreferences.getString(key, null);
    }
    return res;
}

public void setStringProperty(String key, String value) {
    sharedPreferences = context.getSharedPreferences("preferences", Activity.MODE_PRIVATE);
    if (sharedPreferences != null) {
        SharedPreferences.Editor editor = sharedPreferences.edit();
        editor.putString(key, value);
        editor.commit();
        CupsLog.i(TAG, "Set " + key + " property = " + value);
    }
}

Just use setStringProperty("json", "yourJsonString") to save and getStringProperty("json") to retrieve.

shmakova
  • 6,076
  • 3
  • 28
  • 44
Emil Adz
  • 40,709
  • 36
  • 140
  • 187
0

using SharedPreferences should be prepared to sqlite (unless of course you have a database structure). For caching and storing data pulled from the internet, I recommend robospice: https://github.com/octo-online/robospice. It's a very well done library, easy to use, and should be used any time you download data from the internet or have a long-running task.

Mohamed ALOUANE
  • 5,349
  • 6
  • 29
  • 60
0

How to Cache Json data to be available offline?

You can use gson to parse JSON data more easily. In your build.gradle file add this dependency.

compile 'com.google.code.gson:gson:2.8.0'

Then create a POJO class to parse JSON data.

Example POJO class:

  public class AppGeneralSettings {
    @SerializedName("key1")
String data;


    public String getData() {
        return data;
    }

}
  • To parse a json string from internet use this snippet

    AppGeneralSettings data=new Gson().fromJson(jsonString, AppGeneralSettings.class);
    

Then add a helper class to store and retrieve JSON data to and from preferences.

Example: Helper class to store data

public class AppPreference {
    private static final String FILE_NAME = BuildConfig.APPLICATION_ID + ".apppreference";
    private static final String APP_GENERAL_SETTINGS = "app_general_settings";
    private final SharedPreferences preferences;

    public AppPreference(Context context) {
        preferences = context.getSharedPreferences(FILE_NAME, MODE_PRIVATE);
    }

    public SharedPreferences.Editor setGeneralSettings(AppGeneralSettings appGeneralSettings) {
        return preferences.edit().putString(APP_GENERAL_SETTINGS, new Gson().toJson(appGeneralSettings));
    }

    public AppGeneralSettings getGeneralSettings() {
        return new Gson().fromJson(preferences.getString(APP_GENERAL_SETTINGS, "{}"), AppGeneralSettings.class);
    }
}

To save data

new AppPreference().setGeneralSettings(appGeneralSettings).commit();

To retrieve data

 AppGeneralSettings appGeneralSettings = new AppPreference().getGeneralSettings();
Darish
  • 11,032
  • 5
  • 50
  • 70
  • using gson is a great idea, also sharedPreferences can work too, but if the json results are big they better each be saved in a different file. – Ashkan Ghodrat Oct 18 '17 at 11:59
0

You can cache your Retrofit responses, so when you make the same request second time, Retrofit will take it from it's cache: https://medium.com/@coreflodev/understand-offline-first-and-offline-last-in-android-71191e92b426, https://futurestud.io/tutorials/retrofit-2-activate-response-caching-etag-last-modified. After that you'l need to parse that json again

Evgenii Vorobei
  • 1,457
  • 18
  • 20