How can implement offline caching of json in Andro

2019-03-10 22:02发布

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;
}
}
}

3条回答
甜甜的少女心
2楼-- · 2019-03-10 22:19

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.

查看更多
在下西门庆
3楼-- · 2019-03-10 22:26

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.

查看更多
贪生不怕死
4楼-- · 2019-03-10 22:35

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

查看更多
登录 后发表回答