0

I have an android application that display data from my external Database so from several tables. Everything work fine while internet connection is available (all data come from URL link and they are been parsed with volley). But how can I save and load lastest data when internet is not available.

What is the best way to do that. Im new in android....

Please help.

DaveDBar
  • 15
  • 8

2 Answers2

1

Normally Volley and also HttpStack it uses allows you to seamlessly cache responses. This however depends on your responses and requests. Those cache strategies obeys http cache definition. If You want to have different behavior for Volley you can just override this part. basically when you create a request you can override

protected Response<String> parseNetworkResponse(NetworkResponse response) {

and instead of

return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));

you do

long now = System.currentTimeMillis();
Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
        entry.ttl = now + 30l * 24 * 60 * 60 * 1000;  //kepps cache for 30 days 
//entry.softTtl = now + 30l * 24 * 60 * 60 * 1000;  //will not refresh for 30 days     
        return Response.success(parsed, entry);

Which basically will refresh the cache every time the server specifies so but will always return the cache for 30 days unless changes .

Note that here you may receive 2 callbacks in response or in one response and 1 error(in case of no network). the first one will be the cache.

UPDATE:

if you add (which is commented in the example above):

entry.softTtl = now + 30l * 24 * 60 * 60 * 1000;  //will not refresh for 30 days 

this will affect the refresh of the cache. in this case it wont event try to refresh the cache for 30 days. In that case you will return 1 response.

Note that I never would recommend solution like this because cache needs to be updated, especially if you want to fake cache on POST requests as in your case.

Receiving 2 callbacks is not really an issue as you can handle this seamlesly for the user and update UI when needed. also if you want to have more control you can know which one is from the cache and which one form the network by implementing your

ResponseDelivery

or extend

ExecutorDelivery

and then check for the param

mResponse.intermediate

and decide what to do then. ResponseDelivery is the one which calls the callbacks.

Update

similar question and examples here

Community
  • 1
  • 1
kalin
  • 3,546
  • 2
  • 25
  • 31
  • I try your solution with this [link](http://stackoverflow.com/questions/31897189/android-setup-volley-to-use-from-cache), and it work fine, but what about cache when there is a activity o fragment that display information which depend of parameters (GET or POST). – DaveDBar Apr 06 '16 at 16:33
  • caches uses a cache key which by default is the url with all the params so for get you will have differenet caches for different params. for post you can customise it as u want or even override the cache key – kalin Apr 06 '16 at 18:59
  • Ok djojo. But according to the [link] (http://stackoverflow.com/questions/31897189/android-setup-volley-to-use-from-cache) a gave I got a problem. The data display twice in listview. It seem like when the connection is available the data from url display and also the Entry cach data display. So how can't resolve that. Thanks – DaveDBar Apr 08 '16 at 18:23
  • 1) this solution form the link is the same as mine only that mine is simplified and reusing the default parsing of cache headers just adjusting whats important for you later. 2) i updated the answer, however in 2 words you can use softTtl to supress the second callback but I recommend just to handle in you logic that 1 callback update single element but do not add another one. – kalin Apr 08 '16 at 20:42
  • Please according to the link solution and your soution can you give me a complete code or a clear example, because i get always two data (cache and url) in the listview. how call the cache data if no internet , and display only url data when internet is OK. – DaveDBar Apr 11 '16 at 21:27
  • Hello somebody help me when i use "cacheEntry.lastModified" i got an error on "lastModified". – DaveDBar Apr 18 '16 at 12:05
  • and what eaxctly is the issue – kalin Apr 18 '16 at 12:23
  • The data in listview display always twice data (cache + internet) when internet is available. So how i got an error on "lastModified", perhaps is the problem. – DaveDBar Apr 18 '16 at 13:47
  • i meant what is this error on lastModified exactly? – kalin Apr 18 '16 at 14:40
  • when I put this : headerValue = response.headers.get("Last-Modified"); if (headerValue != null) { cacheEntry.lastModified = HttpHeaderParser.parseDateAsEpoch(headerValue); } I got this error : "Error:(314, 39) error: cannot find symbol variable lastModified" – DaveDBar Apr 18 '16 at 17:28
  • u dont need to do that i havent wrote that – kalin Apr 19 '16 at 05:14
  • Ok djojo thanks. But please give me a real example from your code like the link a gave. Im newbie so please. – DaveDBar Apr 19 '16 at 09:01
  • please check the examples in my response here http://stackoverflow.com/questions/36452186/volley-json-cache-image-doesnt-work-offline/36453455?noredirect=1#comment60904222_36453455 – kalin Apr 19 '16 at 13:01
0

if you have to store only small chunk of data then use SharedPreferences If you have large data then use SQLite

Use below code to create and update SQLite DB

public class SqlMangaeMenu 
{
SQLiteDatabase db1 = null;
private static String DBNAME = "YourLocal.db";
Context gcntxt;


public SqlMangaeMenu(Context cntxt) 
{
    // TODO Auto-generated constructor stub     

    gcntxt=cntxt;
    db1 = cntxt.openOrCreateDatabase(DBNAME, Context.MODE_PRIVATE,null);

    db1.execSQL("CREATE TABLE IF NOT EXISTS mytbl(appid varchar PRIMARY KEY,appname varchar,iconcode varchar,msgidentfier varchar,scode varchar,image blob,imagehdr blobhdr); ");

}//EOF Constructor



public void insertContent(String appid,String appname,String iconcode,String msgidentifier,String scode,Bitmap bmp,Bitmap bmphdr)
{
    ContentValues contentValues = new ContentValues();

    contentValues.put("appid", appid);
    contentValues.put("appname", appname);
    contentValues.put("iconcode", iconcode);
    contentValues.put("msgidentfier", msgidentifier);
    contentValues.put("scode", scode);  

    byte[] blob = null,blobhdr=null;
    if(bmp!=null)
    {
    ByteArrayOutputStream outStr = new ByteArrayOutputStream();
    bmp.compress(CompressFormat.PNG, 100, outStr);
    blob = outStr.toByteArray();        
    }
    contentValues.put("image", blob);

    if(bmphdr!=null)
    {
    ByteArrayOutputStream outStr1 = new ByteArrayOutputStream();
    bmphdr.compress(CompressFormat.PNG, 100, outStr1);
    blobhdr = outStr1.toByteArray();

    }
    contentValues.put("imagehdr", blobhdr);

    Log.d("db", "SQL Writing"+appid+appname+iconcode+msgidentifier+scode);

    try {
        // db1.insert("mytbl",null,contentValues);
        db1.insertWithOnConflict("mytbl", null, contentValues,SQLiteDatabase.CONFLICT_IGNORE);
    } catch (Exception e) 
    {
        // TODO: handle exception

    }


    db1.close();

}//EOF insertContent

// Deleting single contact
public void Delete_appid(String id) 
{
   db1.delete("mytbl", "appid" + "=" + id, null);

    db1.close();
}//EOF Delete_appid


public void readAppId()
{

    MyApplication.dbappid=new ArrayList<String>();      

    String appid;
    try
    {          

        Cursor c = db1.rawQuery("SELECT * FROM mytbl", null);
        //Cursor c = db1.rawQuery("SELECT MAX(ID) FROM mytbl", null);


        if(c!= null)
        {
         if (c.moveToFirst()) 
              {
                do {
                    appid=c.getString(c.getColumnIndex("appid"));


                    MyApplication.dbappid.add(appid);


                   }while(c.moveToNext());
               }


          }
        Log.d("db", "SQL Reading");
        db1.close();
        } 
     catch(Exception e)
     {
          System.out.println(e);

     }

}//EOF readAppId


public void readDataandImage()
{
    Bitmap image=null,imagehdr = null;
    //Bitmap images
    MyApplication.dbimg=new ArrayList<Bitmap>();
    MyApplication.dbhdrimage=new ArrayList<Bitmap>();

    //String
    MyApplication.dbappname=new ArrayList<String>();
    MyApplication.dbappid=new ArrayList<String>();
    MyApplication.dbiconcode=new ArrayList<String>();


    String appname,appid,iconcode;
    try
    {
        Cursor c = db1.rawQuery("SELECT * FROM mytbl", null);

        if(c!= null)
        {
         if (c.moveToFirst()) 
              {
                do {

                    image=null;imagehdr=null;
                    byte[] blob = c.getBlob(c.getColumnIndex("image"));
                    byte[] blobhdr = c.getBlob(c.getColumnIndex("imagehdr"));
                    appid=c.getString(c.getColumnIndex("appid"));
                    appname=c.getString(c.getColumnIndex("appname"));
                    iconcode=c.getString(c.getColumnIndex("iconcode"));

                    if(blob!=null)
                    {
                    image = BitmapFactory.decodeByteArray(blob, 0, blob.length);
                    }
                    if(blobhdr!=null)
                    {
                    imagehdr = BitmapFactory.decodeByteArray(blobhdr, 0, blobhdr.length);
                    }

                    //Images
                    MyApplication.dbimg.add(image);
                    MyApplication.dbappid.add(appid);

                    //String
                    MyApplication.dbappname.add(appname);
                    MyApplication.dbiconcode.add(iconcode);
                    MyApplication.dbhdrimage.add(imagehdr);



                   }while(c.moveToNext());
               }


          }
        Log.d("db", "SQL Reading");
        db1.close();
        } 
     catch(Exception e)
     {
          System.out.println(e);

     }


}//EOF readDataandImage


public int dbRowCount()
{
    int rowcnt=0;
    String countQuery = "SELECT * FROM mytbl";
    //SQLiteDatabase db = this.getReadableDatabase();
    Cursor cursor = db1.rawQuery(countQuery, null);
    rowcnt = cursor.getCount();
    cursor.close();
    db1.close();
    Log.d("db", "Numrecs"+rowcnt);
    return rowcnt;
}//EOFdbRowCount 

}

where MyApplication is a static class to hold the read values.

Raghavendra B
  • 441
  • 3
  • 10