1

I am working on a articles application like techcrunch I am parsing data from json. I am parsing title,author and image from json. Articles are displayed in list-view. I want to do offline caching means when there is no internet user can read the articles.

Here is my code-

public class OneFragment extends Fragment {

public OneFragment(){}
private static final String TAG = OneFragment.class.getSimpleName();

// Movies json url
private static String URL = "http://url";
private ProgressDialog pDialog;
private List<Movie> movieList = new ArrayList<Movie>();
private ListView listView;
private CustomListAdapter adapter;
int current_page = 0;
int mPreLast;
SwipeRefreshLayout swipeView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {

    final View rootView = inflater.inflate(R.layout.swip, container, false);
    swipeView = (SwipeRefreshLayout) rootView.findViewById(R.id.swipe);
    swipeView.setColorScheme(android.R.color.holo_blue_dark, android.R.color.holo_blue_light, android.R.color.holo_green_light, android.R.color.holo_green_dark);
    pDialog = new ProgressDialog(getActivity());
    pDialog.setMessage("Loading...");
    pDialog.show();
    pDialog.setCancelable(false);

    swipeView.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {

        @Override
        public void onRefresh() {
            // TODO Auto-generated method stub
            swipeView.setRefreshing(true);
            Log.d("Swipe", "Refreshing Number");
            ( new Handler()).postDelayed(new Runnable() {

                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    swipeView.setRefreshing(false);
                    onStart();
                }
            }, 3000);
        }
    });

    listView = (ListView) rootView.findViewById(R.id.list49);
    listView.setOnScrollListener(new AbsListView.OnScrollListener()
    {
        @Override
        public void onScrollStateChanged(AbsListView absListView, int i)
        {

        }

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
        {
            int lastItem = firstVisibleItem + visibleItemCount;
               if(lastItem == totalItemCount){
                   if (mPreLast != lastItem)
                   {
                        mPreLast = lastItem;                           
                        pDialog = new ProgressDialog(getActivity());
                        pDialog.setMessage("Loading more articles...");
                        pDialog.show();
                        //pDialog.setCancelable(false);
                        onStart(); 
                   }
            }
        }
    });

    listView.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?>  adapterView, View view, int Position,
                long offset)  { 
            // TODO Auto-generated method stub
            Movie item = (Movie) adapter.getItem(Position);             
            Intent intent = new Intent(rootView.getContext(), SingleArticle.class);
            single.title = item.getTitle();
            single.author = item.getAuthor();

            startActivity(intent);


            }        
        });
    //pDialog = new ProgressDialog(this);
    // Showing progress dialog before making http request

    return rootView;
}

@Override
public void onStart(){
    super.onStart();
    // calling adapter changes here, just
    // to avoid getactivity()null
    // increment current page
     current_page += 1;
    // Next page request
    URL = "http://url" + current_page;
    //adapter = new CustomListAdapter(this, movieList);
    int currentPosition = listView.getFirstVisiblePosition();
    adapter = new CustomListAdapter(getActivity(), movieList);
    listView.setAdapter(adapter);
    listView.setSelectionFromTop(currentPosition + 1, 0);
    // changing action bar color
    //getActivity().getActionBar().setBackground(
            //new ColorDrawable(Color.parseColor("#1b1b1b")));

    // Creating volley request obj
    JsonArrayRequest movieReq = new JsonArrayRequest(URL,
            new Response.Listener<JSONArray>() {

                @Override
                public void onResponse(JSONArray response) {

                    Log.d(TAG, response.toString());
                    hidePDialog();

                    // Parsing json
                    for (int i = 0; i < response.length(); i++) {
                        try {

                            JSONObject obj = response.getJSONObject(i);
                            Movie movie = new Movie();
                            movie.setTitle(obj.getString("title"));
                            movie.setAuthor(obj.getString("author"));
                            // adding movie to movies array
                            movieList.add(movie);




                            adapter.notifyDataSetChanged();

                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }                       
                }
            },new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    VolleyLog.d(TAG, "Error: " + error.getMessage());
                    new AlertDialog.Builder(getActivity())
                    .setTitle("No Connectivity ")
                    .setMessage("Please check your internet connectivity!")
                    .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) { 
                            // continue with delete
                        }
                     })
                    //.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
                        //public void onClick(DialogInterface dialog, int which) { 
                            // do nothing
                        //}
                     //})
                    .setIcon(android.R.drawable.ic_dialog_alert)
                     .show();
                    hidePDialog();

                }
            });
    AppController.getInstance().addToRequestQueue(movieReq);    
    //listView.setAdapter(adapter);

}

private View getActionBar() {
    // TODO Auto-generated method stub
    return null;
}

@Override
public void onDestroy() {
super.onDestroy();
hidePDialog();
}

private void hidePDialog() {
if (pDialog != null) {
    pDialog.dismiss();
    pDialog = null;
}
}
}
Daljeet
  • 1,573
  • 2
  • 20
  • 40
  • People generally use databases for that matter. Does that work for you? Then you may get a lot of examples. – Darpan Oct 01 '14 at 07:15

3 Answers3

3

This probably isn't the best way to do it, but it worked for me.

You might find this helpful: http://www.vogella.com/tutorials/JavaSerialization/article.html

I had to do the same in some project. This is what I did:

public final class cacheThis {
private cacheThis() {}

public static void writeObject(Context context, String fileName, Object object) throws IOException {
      FileOutputStream fos = context.openFileOutput(fileName, Context.MODE_PRIVATE);
      ObjectOutputStream oos = new ObjectOutputStream(fos);
      oos.writeObject(object);
      oos.flush();
      oos.close();

      fos.close();
   }

   public static Object readObject(Context context, String fileName) throws IOException,
         ClassNotFoundException {
      FileInputStream fis = context.openFileInput(fileName);
      ObjectInputStream ois = new ObjectInputStream(fis);
      Object object = ois.readObject();
      fis.close();
      return object;
   }
}

To write to file:

cacheThis.writeObject(YourActivity.this, fileName, movieList);

To read from file:

movieList.addAll((List<Movie>) cacheThis.readObject(
                VideoActivity.this, fileName));

You have to have your Movie class implements Serializable

SourApple
  • 46
  • 5
  • Where to write to file? I mean after the json parsing of data? can you please guide me with an example ? – Daljeet Oct 01 '14 at 08:19
  • I usually cache right after parsing the whole response. Like you could write to file at the end of `public void onResponse(JSONArray response)` like this: `public void onResponse(JSONArray response) { Log.d(TAG, response.toString()); hidePDialog(); // Parsing json for (int i = 0; i < response.length(); i++) { . . . } cacheThis.writeObject(YourActivity.this, fileName, movieList); }` – SourApple Oct 01 '14 at 08:37
  • thnxs the filename i have to create a local variable ?? – Daljeet Oct 01 '14 at 09:08
  • Yes, it's just a string that represents the name of the file you're saving to. You have to make sure that you're using the same fileName when reading from file and writing to file. – SourApple Oct 01 '14 at 09:13
  • ok thnxs when where to use that read code which you tell please help me a little more – Daljeet Oct 01 '14 at 09:24
  • Well that depends on where you want to use it. For example, you could check if the device is connected to the internet; if not, read the cached items. Or you could read the file anyway, but check for duplicates occurrences when parsing the JSON response. – SourApple Oct 01 '14 at 09:41
  • can i check that fill in my phone some where ? – Daljeet Oct 01 '14 at 09:43
  • No, it's creating a private file (Context.MODE_PRIVATE). You can access it via DDMS if you're using the emulator. – SourApple Oct 01 '14 at 10:10
  • I am placing that write code as you describe! but is force closing my application – Daljeet Oct 01 '14 at 10:14
  • More details? Either your list is null or the fileName you're using is null. Did you define a fileName? `String fileName = "TheNameYouWant";` – SourApple Oct 01 '14 at 10:33
  • Ok thnxs!! please can you tell me how to read cache when internet is off – Daljeet Oct 01 '14 at 10:39
  • See this: http://stackoverflow.com/questions/9570237/android-check-internet-connection – SourApple Oct 01 '14 at 10:41
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/62342/discussion-between-daljeet-and-sourapple). – Daljeet Oct 02 '14 at 13:54
1

You must save the json offline. It can be Db or file system. I will prefer to go with Db part.

The approach is ,every time you get data from server save first in you db then from db you can show it to your UI.

Inserting in Db can be slow but you can use beginTransaction and other methods which will make it lighting fast.

Now How can you save data in Db. You have two ways

  • You can parse json first and create the table structure for name,url and other fields then run the query

  • Or store the whole json in Db without parsing .By using GSON or other json parsers this approch will be quite helpful.

Suhail Mehta
  • 5,514
  • 2
  • 23
  • 37
  • thnxs!! i think file system is better then db because my data is not to much but the problem is that i don't know How to implement file system in my case. could you please help me resolve it! – Daljeet Oct 01 '14 at 07:23
1

I saw you are using Volley. Volley has built-in HTTP Cache mechanism.

  • So the easiest way is to support HTTP cache headers in your backend. It is very easy and it is transparent to the client side. Volley does the hard work. You can find information here

  • If you don't have access to the URL you use, you must use internal database to support your application. ContentProvider API is the best way to do that. And the following library is a great library to construct a database and write to it. https://github.com/TimotheeJeannin/ProviGen

Basically you need to write every item that you pull from the internet to the database and the ListView should show the items from the database using ContentProvider you have just created. When the user opens the app, show the data from the database and then immediately try to pull the new data from your backend.

tasomaniac
  • 10,234
  • 6
  • 52
  • 84