0

I have an ArrayList which stores the JSON content and an ArrayAdapter that displays it. Now I am trying to get save this JSON content so that user can see it even when offline.

I followed this SO question to do so: How to Cache Parsed JSON for Offline usage The question above lets us save the ArrayList in a File on external storage Now I want to display the contents of this stored ArrayList i.e actorList in my arrayAdapter when the user starts the app when he is Offline.

This is my code so far which crashes the app when run offline with NullPointerException

    @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    final View rootView = inflater.inflate(R.layout.fragment_photos, container, false);
    if (isNetworkAvailable()) {

        actorsList = new ArrayList<Actors>();

        new JSONAsyncTask().execute(baseURL);
        listview = (ListView) rootView.findViewById(R.id.list);
        adapter = new ActorAdapter(getActivity(), R.layout.row, actorsList);
        listview.setAdapter(adapter);

    }
 else{

        Toast.makeText(getActivity(), "Network Unavailable. Please Try Again Later ", Toast.LENGTH_LONG).show();

        try {
            Toast.makeText(getActivity(), "Reached TRY ", Toast.LENGTH_LONG).show();
            actorsList = (ArrayList<Actors>)objectFromFile(dataPath);
            //   System.out.print(actorsList);
            for(int i=0;i<actorsList.size();i++)
            {
                Toast.makeText(getActivity(), "Reached FOR ", Toast.LENGTH_LONG).show();
                actor.setName(actorsList.get(i).getName());
                actor.setDescription(actorsList.get(i).getDescription());
                actor.setImage(actorsList.get(i).getImage());
            }

            listview = (ListView) rootView.findViewById(R.id.list);
            adapter = new ActorAdapter(getActivity(), R.layout.row, actorsList);
            listview.setAdapter(adapter);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    return rootView;
}
 class JSONAsyncTask extends AsyncTask<String, Void, Boolean> {


    @Override
    protected void onPreExecute() {

    }

    @Override
    protected Boolean doInBackground(String... urls) {
        try {

            //------------------>>
            HttpGet httppost = new HttpGet(urls[0]);

            HttpClient httpclient = new DefaultHttpClient();
            HttpResponse response = httpclient.execute(httppost);

            // StatusLine stat = response.getStatusLine();
            int status = response.getStatusLine().getStatusCode();

            if (status == 200) {
                HttpEntity entity = response.getEntity();
                String data = EntityUtils.toString(entity);


                JSONObject jsono = new JSONObject(data);
                jarray = jsono.getJSONArray("posts");


                for (int i = 0; i < jarray.length(); i++) {
                    JSONObject object = jarray.getJSONObject(i);

                   Actors actor = new Actors();

                    actor.setName(object.getString("title"));
                    actor.setDescription(object.getString("url")); 
                    actor.setImage(object.getString("thumbnail"));                                                        

                    actorsList.add(actor);

                }
                return true;
            }

        } catch (ParseException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return false;
    }

    protected void onPostExecute(Boolean result) {
        dialog.cancel();
        adapter.notifyDataSetChanged();
        if (result) {
            try {
                dataPath = objectToFile(actorsList);
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            Toast.makeText(getActivity().getApplicationContext(), "Unable to fetch data from server", Toast.LENGTH_LONG).show();
        }
    }
}

As you can see, i am trying to implement the same thing as asked in the question linked above but not able to figure out how to display the ArrayList when offline. Please help

UPDATE: logcat

04-21 14:23:33.161    4870-4870/info.androidhive.slidingmenu E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: info.androidhive.slidingmenu, PID: 4870
java.lang.RuntimeException: Unable to start activity ComponentInfo{info.androidhive.slidingmenu/info.androidhive.slidingmenu.MainActivity}: java.lang.NullPointerException
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2412)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2470)
        at android.app.ActivityThread.access$900(ActivityThread.java:174)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1307)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:146)
        at android.app.ActivityThread.main(ActivityThread.java:5593)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:515)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
        at dalvik.system.NativeStart.main(Native Method)
 Caused by: java.lang.NullPointerException
        at java.io.File.fixSlashes(File.java:185)
        at java.io.File.<init>(File.java:134)
        at info.androidhive.slidingmenu.ObjectToFileUtil.objectFromFile(ObjectToFileUtil.java:31)
        at info.androidhive.slidingmenu.PagesFragment.onCreateView(PagesFragment.java:176)
        at android.app.Fragment.performCreateView(Fragment.java:1700)
        at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:890)
        at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1062)
        at android.app.BackStackRecord.run(BackStackRecord.java:684)
        at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1453)
        at android.app.Activity.performStart(Activity.java:5467)
        at 

android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2385)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2470)
            at android.app.ActivityThread.access$900(ActivityThread.java:174)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1307)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:146)
            at android.app.ActivityThread.main(ActivityThread.java:5593)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
            at dalvik.system.NativeStart.main(Native Method)

This is the Class which converts ObjectToFile and ObjectFromFile

package info.androidhive.slidingmenu;

import android.os.Environment;

import java.io.*;

 public class ObjectToFileUtil {

public static String objectToFile(Object object) throws IOException {
    String path = Environment.getExternalStorageDirectory() + File.separator + "cache" + File.separator;
    File dir = new File(path);
    if (!dir.exists()) {
        dir.mkdirs();
    }
    path += "data";
    File data = new File(path);
    if (!data.createNewFile()) {
        data.delete();
        data.createNewFile();
    }
    ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(data));
    objectOutputStream.writeObject(object);
    objectOutputStream.close();
    return path;
}

public static Object objectFromFile(String path) throws IOException, ClassNotFoundException {
    Object object = null;
    File data = new File(path);
    if(data.exists()) {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(data));
        object = objectInputStream.readObject();
        objectInputStream.close();
    }
    return object;
}
}
Community
  • 1
  • 1
Swapna Lekshmanan
  • 514
  • 10
  • 30
  • you need internet connection to get the data first time after that you can store it in sharedprefrences or database and when the internet is not available you can get data from there and show to user – Pramod Yadav Apr 21 '15 at 07:21
  • Please show the error line. For your app concept you need to store your `JSONObject` or arraylist in to database or in `SharedPreference`. Also set your adapter in to `onPostExecute()` method instead of `onCreateView() `method. – Piyush Apr 21 '15 at 07:23
  • @PramodYadav yes thats what i do. First i run the app with internet, all the data is loaded properly. Then i turn Off the WiFi and start (not RUN) the app. But it crashes. The problem is certainly with displaying ArrayList in ArrayAdapter – Swapna Lekshmanan Apr 21 '15 at 07:25
  • are you getting actorsList = (ArrayList)objectFromFile(dataPath); properly from this statement? – Amit K. Saha Apr 21 '15 at 07:27
  • Are you getting `Reached TRY` toast??? – Pankaj Apr 21 '15 at 07:27
  • store the arraylist in sharedprefrences or database and get it from there when you do not have internet connection – Pramod Yadav Apr 21 '15 at 07:29
  • @PramodYadav can you please guide me on how to do that – Swapna Lekshmanan Apr 21 '15 at 08:51
  • @Clairvoyant yes i am able to get `Reached Try` – Swapna Lekshmanan Apr 21 '15 at 08:55

2 Answers2

0

Updated answer for updated code

change your ObjectToFileUtil class according to this-

public class ObjectToFileUtil {

private static baseFilePath = Environment.getExternalStorageDirectory() + File.separator + "cache" + File.separator+"data";

public static String objectToFile(Object object) throws IOException {
    String path = baseFilePath;
    File dir = new File(path);
    if (!dir.exists()) {
        dir.mkdirs();
    }
    File data = new File(path);
    if (!data.createNewFile()) {
        data.delete();
        data.createNewFile();
    }
    ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(data));
    objectOutputStream.writeObject(object);
    objectOutputStream.close();
    return path;
}

public static Object objectFromFile() throws IOException, ClassNotFoundException {
    String path = baseFilePath;
    Object object = null;
    File data = new File(path);
    if(data.exists()) {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(data));
        object = objectInputStream.readObject();
        objectInputStream.close();
    }
    return object;
}

Then change this following line -

actorsList = (ArrayList<Actors>)objectFromFile(dataPath);

To-

actorsList = (ArrayList<Actors>)objectFromFile();

Cause of your problem

you saved the file when network was available and stored the file path in dataPath member. Now when you are starting the app when no network is available, you are trying to open the file assuming that file is already having the json. every thing is fine till this point. But there is a logical mistake. See when you are relaunching your app, there is no value in dataPath though file may exist cause dataPath is only assigned when you just wrote to the file. So your path is null and the file object is not creating in objectFromFile()

Also make sure your Actors class is implementing Serializable interface. cause to save an object in File & then retrieve it properly , the object needs to be Serializable.

Amit K. Saha
  • 5,871
  • 2
  • 27
  • 35
  • can you please share your log cat? actorsList = (ArrayList)objectFromFile(dataPath); what do you at actorsList here? – Amit K. Saha Apr 21 '15 at 09:08
  • after doing a more research, i think we first need to save the `ArrayList` in SharedPreferences..i m looking for how to do that.. anyways, added my logcat in question – Swapna Lekshmanan Apr 21 '15 at 09:19
  • I have updated my `Reached Try` code, and now the app does not crash. But nothing is displayed except the toast. – Swapna Lekshmanan Apr 21 '15 at 09:52
  • @SwapnaLekshmanan, see saving into SharedPreferences is just an alternative option. from your logcat it is clear that NPE is occurring in objectFromFile(). You should share your objectFromFile() and objectToFile() code. because the problem is there. – Amit K. Saha Apr 21 '15 at 09:56
  • thanks Amit.. I have a separate Java class `ObjectToFileUtil` which implements `ObjectToFile` and `ObjectFromFile`. Updated them in question – Swapna Lekshmanan Apr 21 '15 at 10:13
  • @SwapnaLekshmanan, what is the value of dataPath in actorsList = (ArrayList)objectFromFile(dataPath); according to your logcat, your File obj is being failed to created due to file path. java.lang.NullPointerException at java.io.File.fixSlashes(File.java:185) at java.io.File.(File.java:134) probably, your dataPath is getting null value – Amit K. Saha Apr 21 '15 at 10:33
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/75794/discussion-between-amit-k-saha-and-swapna-lekshmanan). – Amit K. Saha Apr 21 '15 at 10:39
0

You can convert your arraylist of object to string and store it in sharedprefrences like this:-

 Gson gson = new Gson();
 SharedPreferences sharedPreferences= PreferenceManager.getDefaultSharedPreferences(getActivity());
 SharedPreferences.Editor editor = sharedPreferences.edit();
 editor.putString("list",gson.toJson(actorsList));
 editor.commit();

then you can retrieve this list when the else block where connection is not available,like this:-

SharedPreferences sharedPreferences= PreferenceManager.getDefaultSharedPreferences(getActivity());
String string=sharedPreferences.sharedPreferences.getString("list",null);
List<Actors> list=new List<Actors>();
Type listType = new TypeToken<ArrayList<Actors>>() {
    }.getType();
list= new Gson().fromJson(string, listType);

i have used gson here to serialize and deserialize the objects and don't forgot to include gson in your gradle file

Pramod Yadav
  • 2,316
  • 2
  • 23
  • 36
  • first of all no offense mate. But I can't understand why did you asking her to save in shared preference (I understand it should be more easier). But isn't it also possible that, her business logic is forcing her to save in the file? Couldn't be a large text response in the json? instead of proposing different solution, shouldn't we fix OP's problem first? – Amit K. Saha Apr 21 '15 at 10:00
  • i am not forcing her to do it the way i have suggested i think this is the way suitable its totally upto her if she want to do it via this method or not,i have no clue how much big this list you never know that if its too big than reading from a file is not an ideal solution either then she has to store it in database.I just answered the question after getting the little knowledge i got from reading the question she posted – Pramod Yadav Apr 21 '15 at 10:08
  • @PramodYadav should i replace `objectString` in your code with `string`? and also where shd i arrange the list contents in the adapter? – Swapna Lekshmanan Apr 21 '15 at 10:38