pola alper pola alper - 1 month ago 9
JSON Question

Caching JSON response to use when the device is offline

I am building a news app and I want to cache a JSON response to use when there is no network. I tried a lot of ways but it did not work for me.

My async task and my adapter are another side problem when the list loads new items it goes to the top of the screen and after that it adds the items. How can I fix this?

private class jsontask extends AsyncTask<String, String, List<newsmodel>> {
@Override
protected List<newsmodel> doInBackground(String... params) {
BufferedReader reader = null;
HttpURLConnection connection = null;
try {
URL url = new URL(params[0]);

connection = (HttpURLConnection) url.openConnection();

connection.connect();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null) {
buffer.append(line);

}


String finaljson = buffer.toString();
JSONObject parentobject = new JSONObject(finaljson);


JSONArray parentarray = parentobject.getJSONArray("articles");

for (int i = 0; i < parentarray.length(); i++) {
JSONObject finalobject = parentarray.getJSONObject(i);
newsmodel newsmodel = new newsmodel();
newsmodel.setAuthor(finalobject.getString("author"));
if (finalobject.isNull("author")) {

}
newsmodel.setDescription(finalobject.getString("description"));
newsmodel.setTitle(finalobject.getString("title"));
newsmodel.setImage(finalobject.getString("urlToImage"));
newsmodel.setUrl(finalobject.getString("url"));

newsmodel.setPublishedAt(finalobject.getString("publishedAt"));

moviemodelList.add(newsmodel);

}


return moviemodelList;

} catch (MalformedURLException e) {
e.printStackTrace();
return moviemodelList;
} catch (IOException e) {
e.printStackTrace();
return moviemodelList;
} catch (JSONException e) {

} finally {
if (connection != null) {
connection.disconnect();

}
try {
if (reader != null) {
reader.close();

}
} catch (IOException e) {
e.printStackTrace();
}

}


return null;
}


@Override
protected void onPostExecute(List<newsmodel> result) {


super.onPostExecute(result);
newsadapter adapter = new newsadapter(getApplicationContext(), R.layout.row, result);
lvnews.setAdapter(adapter);
}

}

public class newsadapter extends ArrayAdapter {
private List<newsmodel> moviemodelList;
private int resource;
private LayoutInflater inflater;

public newsadapter(Context context, int resource, List<newsmodel> objects) {
super(context, resource, objects);
moviemodelList = objects;
this.resource = resource;
inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);


}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
viewholder holder = null;
if (convertView == null) {
holder = new viewholder();
convertView = inflater.inflate(resource, null);
holder.newsimage = (ImageView) convertView.findViewById(R.id.imageView2);
holder.title = (TextView) convertView.findViewById(R.id.textView2);
holder.description = (TextView) convertView.findViewById(R.id.textView3);
holder.author = (TextView) convertView.findViewById(R.id.textView4);
holder.publishdate = (TextView) convertView.findViewById(R.id.textView5);
holder.dotsmenu = (ImageButton) convertView.findViewById(R.id.dots);
convertView.setTag(holder);
} else {
holder = (viewholder) convertView.getTag();
}

final ProgressBar progressBar;
progressBar = (ProgressBar) convertView.findViewById(R.id.progressBar);

ImageLoader.getInstance().displayImage(moviemodelList.get(position).getImage(), holder.newsimage, new ImageLoadingListener() {
@Override
public void onLoadingStarted(String imageUri, View view) {
progressBar.setVisibility(view.VISIBLE);
}

@Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
progressBar.setVisibility(view.GONE);
}

@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
progressBar.setVisibility(view.GONE);
}

@Override
public void onLoadingCancelled(String imageUri, View view) {
progressBar.setVisibility(view.GONE);
}
});
holder.title.setText(moviemodelList.get(position).getTitle());
holder.description.setText(moviemodelList.get(position).getDescription());
holder.author.setText(moviemodelList.get(position).getAuthor());
holder.publishdate.setText(moviemodelList.get(position).getPublishedAt());
final viewholder finalHolder = holder;
holder.dotsmenu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
PopupMenu popup = new PopupMenu(page.this, finalHolder.dotsmenu);
//Inflating the Popup using xml file
popup.getMenuInflater().inflate(R.menu.dots_menu, popup.getMenu());
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {

case R.id.share:
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, moviemodelList.get(position).getUrl());
sendIntent.setType("text/plain");
startActivity(sendIntent);
return true;
}
return false;
}

});
popup.show();
}
});
lvnews.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

Intent intent = new Intent(page.this, webview.class);
intent.putExtra("Link", moviemodelList.get(position).getUrl());
startActivity(intent);


}
});


return convertView;
}

Answer

Make a class for testing whether net connection is available or not .

ConnectionDetector.java

public class ConnectionDetector {
public  Context context;
public ConnectionDetector(Context context)
{
    this.context=context;
}
public boolean isConnecting() {
    ConnectivityManager check=(ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
    if (check!=null){
        NetworkInfo[] infos=check.getAllNetworkInfo();
        for (int i=0;i<infos.length;i++)
        {
            if (infos[i].getState()== NetworkInfo.State.CONNECTED)
                return true;
        }}

    return false;

}
}

Create an object ob of above class .

ConnectionDetector ob=new  ConnectionDetector(getApplicationContext());

Declare these variables as global variables :

  File httpCacheDir;
  long httpCacheSize = 5 * 1024 * 1024;// In place of 5 you can use size in mb
  HttpResponseCache cache;

Make a function cacher():

 public void cacher()
 {
    httpCacheDir = getExternalCacheDir();

    // Cache Size of 5MB


    try {
        // Install the custom Cache Implementation
        HttpResponseCache.install(httpCacheDir, httpCacheSize);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Just below the setContentView in onCreate ,add the following code :

   cacher();
   cache = HttpResponseCache.getInstalled();
    if(cache != null) {
        //   If cache is present, flush it to the filesystem.
        //   Will be used when activity starts again.
        cache.flush();
    }

And here comes the final thing , below the url.openConnection line put the following snippet:

 if (ob.isConnecting()){
            connection.addRequestProperty("Cache-Control", "max-age=0");}
            else{
            connection.addRequestProperty("Cache-Control", "max-stale=" +  60*60*36);//In place of 36 , you can put hours for which cache is available 
            connection.setUseCaches(true);
}