Actually, I followed this YouTube tutorial and got an idea of delivering articles from a WordPress blog using the JSON API.
Here is the GITHUB link.
The above tutorial has a good example, but it only shows data from database only when there is no internet connection available. But I want the following:
Fetch data when the app is first started.
Store the data in the database
Set the adapter and show the data in the recyclerview
When the app is loaded for the second time check if internet is available and then check for new data, download if available, and then save the data into database and show the data in the recycler view.
Now, I've developed most of the logic for it, but the tutorial has used some advanced OOPs principles of JAVA which I am unable to fully comprehend.
Can anyone please help me and tell me how I can change the given code and display the data from database even if internet is available or not?
on MainActivity, line 91
if (getNetworkAvailability()) {
getFeed();
} else {
getFeedFromDatabase();
}
Above code will check network, and if network available, getFeed() which load feed from internet will be called. Just remove that case. I mean, remove above code, just keep the line
getFeedFromDatabase();
There is nothing complex, by the way. The idea is that you define your own interface which describe how to save data and implement it for database and for communication with Rest Api (Retrofit). There may be some differences between format of stored data (one form in database and the other on a server), so you have to convert it to format of your app.
For that you create another interface (see Repository pattern), which is also implemented by you db and web stuff.
When your have implementations for both sources you can choose which one to use.
Related
About Single Sources of Truth Google document said:
Using this model, the database serves as the single source of truth, and other parts of the app access it using our UserRepository. Regardless of whether you use a disk cache, we recommend that your repository designate a data source as the single source of truth for the rest of your app
https://developer.android.com/jetpack/guide?gclid=CjwKCAjwo4mIBhBsEiwAKgzXOH1Pq--Ws1PLzUiSP4RmDE6ByKfEi6mdXu5g86btqveIdJvvrgYuxBoCz8wQAvD_BwE&gclsrc=aw.ds#connect-viewmodel-repository
According to the document I save all data when I fected data from remote server and I only get data from room When I need to use in acitivty(In fact I collect flow which is defined in viewmodel).
It seems so good! It avoids the different data sources mix up together! But actually I found some strange question gradually:
In my App, I have a list that the server may change it(Because we have data manager website that admin can update or delete data). So in order to get the newest list data from server, I must clear all data stored in room and fect data again from remote server. This operation seems redundant: "why could I get data directly from remote server", I mean, I only get data from remote source is also a single sources truth. And also it cause a promble: my app will flash a moment because clear data make list empty and fect data from server make list full!
The most important thing is that it seems like the local data is not necessary because I must stay the newest list from remote server.
Some people may say that save data into room can make us app available offlice. I agree that, But in this place, my item of list is represent a image url, and after click the item, the app will jump to a new activity and display a ImageView base on the url we get from the list. If app offlice, the ImageView couldn't load the url also.
I am so confused I couldn't load all image url(use base64-url to avoid load invalid) in a moment also, because the data is so much. And if I say I need a search function in this list and I need load so much unbelievable data into my room, It seems so unreal and event fantasy!
In brief:
Room is a nessary? Couldnt just fect data from remote?
If room is nessary, how to solve problem I met, do my incorrect useage cause the problem?
Hi #psycongroo as I Understood your problem, and I want to share my experience:
You can handle any error with loading URL with placeholder I mean if you got an error with no Internet connection user will see placeholder, but in general libs like Picasso or Glide can cache images when it`s load one time, so the user will see the Image.
The question about why we need to use room instead of fetch data from remote directly. So from your question I don`t understand why you need to drop your local changes even they are completely new, user can have a low internet connection so he will see an empty list instead of previous data with for example progress indicator. And also if the user doesn't have the internet at all you can show some dialog to explain what the problem but old data is still present. If you are using, for example, RecyclerView you can update data with Paging 3 from google, and they update the only necessary items from your list.
P.S. let me know if that help, or you have another question.
Context
I have a news activity which contains a ListView . Each item in the list contains some text and one image. Now every time the user opens the activity, the application makes a request to the server for getting data. Unfortunately if the user doesn't have an active internet connection, I simply put a Toast saying "Please check your internet connection"
Requirements
I would like to show news article from the last session if the user doesn't have an active internet connection. I define session as the time when user launches the activity and exits it by pressing back button.
Libraries used
I am using Retrofit Library for making Http Requests and Picasso for loading images.
What I have tried so far
While exploring Retrofit, I found out that retrofit by default caches the response for some time. So without any internet connection also I am able to get the data. In Picasso also, I found that we can save the image to any location on the device.
How to go for its Implementation ?
Since it will be a big change in my application, I wanted to know what is the best way to enable offline reading using the above two libraries? How do other applications manage to do so? Also if I can get some references or some blogs regarding this implementation, then it would be great.
Use the internal storage of the application.
Parse the image to a byteArray and the text to a single String so you can easily convert this also to a byteArray.
Name the files so you can easily retrieve them and link them back together.
You can storage the last updated data on local, with SharedPreferences or json file.
Instead of show toast, you can load the last updated data from local.
Picasso is a good choice for images, it saves images locally and reuse it automatically later.
For your items, I suggest to use a small local DataBase : in Android, we use SQLiteDataBase. here is a small tutorial : http://www.androidhive.info/2011/11/android-sqlite-database-tutorial/
So, I suggest you this pattern
user opens activity
system retrieves data from database
in parallel, system starts to download the new items.
When new items have been downloaded, you should notice user like 9gag or Facebook apps do.
I am working on an android fitness app and I want to get the hang of using ContentProviders. I was thinking about using the myfitnesspal api to get a list of exercises, but the api is private and my request has not been addressed yet. Then I considered scraping exercises from a website--but I am a little concerned about the reliability of this approach (if the site goes down, app won't keep working).
What is the best way to go about this? Is it "safe" to get information from a website (rather than an api) with a ContentProvider?
Correct me If I am wrong. You want user to acces your data even if there is not web API active. So my thought for it would be
Download all the data from web API and store it in database
create an node to check if data has been updated in the API if updated download new data in background and update the database else show same data from database
Benefits
User don't need to download data all the time they use app and their volume of internet would be saved
User don't need to see blank page if there's not any data
If im wrong, i would really like to know.. but the answer is simple: a ContentProvider allows only the connection to a database in your cellphone. You can't use a ContentProvider to get data from the internet. What you're trying to do is achievable with a WebService, which is an application running on a determined domain on the Internet and allows you to call some pre-defined methods linked to URLs of this same domain (but i imagine you know about that, right?).
I have an application in hand where we need to use a tab for data entry. The tab loads initial data from the remote server. Subsequently remote server needs to be updated, inserted (for new data) as the user inserts/updates data on the tab. Out database server is SQL Server 2008.
As suggested by the many experts at stackoverflow we are going to use Webservices at the server to facilitate data interchange. However I am still not sure of the following points -
1. whats the best mechanism for authentication in such case.
2. should i take a chunk of data from sqlite table at android, convert to JSON and pass it on to the Webservices for insert/update operation or take single row and update. Though I think sending single row would not be efficient.
3.How I manage failure to upgrade remote server. This is easier in case I use single row. My plan is to set status flag for sqlite records to 1 (default is 0) for records being updated/inserted to remote server. If update/insert fails I change the status flag back to 0 so that i can use them again next time. In case of success change the flag to 2.
thanks in advance
UPDATE
Doen some study and tried to use SampleSyncAdapter. Still some confusion about the whole operation. My Sqlite database is created by a program and content provider class exists in that application. Package name for the application is com.xylo.pds. I am trying to write a sync application which attempts to sync the data used in the first application. If I follow the SampleSyncAdapter sample - I need to develop server side application for authentication and then uploading android data to the server(in my case one way is sufficient). I can do that with the help of server side code given with the sample.
So I just copied codes of the sample code for my Authentication and Sync. My authenticator.xml has the existing entries-
android:contentAuthority="com.android.contacts"
android:accountType="com.example.android.samplesync
So now my application can add account and sync the contact. And no wonder it works with dummy server id given with the sample.
Now I need to put my own code in the application so that I can load my local database to the server. In order to that I need to add codes at onPerformSync of SyncAdapter. In order to use existing ContentProvider I have the following entries in the manifest file
<uses-permission android:name="com.xylo.pds.RCDataProvider" />. The application which defines the ContentProvider has the following entries -
<provider android:name=".RCDataProvider"
android:authorities="com.xylo.pds.provider"
android:exported="true"
android:readPermission="android.permission.permRead" />
Now if I have added a call to the contentresolver inside SyncAdapter keeping every thing else same just to check things are ok. So that, it is ok, I can change onPerformSync to add codes for uploading data. However now the application stops sysnc the contacts. What I am missing
Please enlighten me. Thanks
1) whats the best mechanism for authentication in such case.
You could/should use OAuth2. either implement your own token on web service website or use common OAuth2 web services in conjunction with the Android Account Manager.
The reason for suggesting this approach is really down to the suggested/recommended way of handling user authentication as per the Google docs.
See "Remembering your user" here http://developer.android.com/training/id-auth/identify.html
Which leads nicely on to your next questions
2) should i take a chunk of data from sqlite table at android, convert to JSON and pass it on to the Webservices for insert/update operation
or take single row and update. Though I think sending single row would
not be efficient.
You should use the android sync adapter which will make use of the account manager functionality described in the link I gave you in answer to question 1
You can code your android service in whatever way you wish but you should be using JSON rather than XML in both directions.
The really neat thing about using the account manager with a sync adapter is that your SQLite content provider methods can use the notifyChange method to tell the sync adapter to update the web service.
You can tell the sync adapter to get the latest data from your web service at the same time or you can schedule syncs.
3) How I manage failure to upgrade remote server. This is easier in case I use single row. My plan is to set status flag for sqlite
records to 1 (default is 0) for records being updated/inserted to
remote server. If update/insert fails I change the status flag back to
0 so that i can use them again next time. In case of success change
the flag to 2.
This is explained by Virgil in the Google I/O video embeded into into this sync adapter tutorial https://sites.google.com/site/andsamples/concept-of-syncadapter-androidcontentabstractthreadedsyncadapter
An alternative solution to using a sync adapter to get the data FROM your web service would be to use GCM (Google Cloud Messaging service. http://developer.android.com/google/gcm/gs.html
Basically Account Manager/sync adapter/gcm is the functionality that Android recommend you use and these are the services that Google uses itself for things like GMail and give your users the ability to keep their data intact even after clearing their data or uninstalling the app and re-installing the app and it also allows for a user to be able to install the app on a new phone and keeping their data.
Hope that helps
UPDATE in response to comments
You should always try hard to minimise traffic and size of data being sent in either direction. I would send the whole lot in one single JSON request gzipped.
Your web server should be able to automatically handle gzipped requests and if gzip is not installed on your server it's simple enough to add
A reference to creating a gzipped output stream from your app can be found here
http://developer.android.com/reference/java/util/zip/GZIPOutputStream.html
For the web server the solution you need will depend on the server you use and you should check with your host about gzip but here are a couple of links for the most popular web servers
Apache - http://howtounix.info/howto/Apache-gzip-compression-with-mod_deflate
NGinx Tutorial - http://www.howtoforge.com/how-to-save-traffic-with-nginxs-httpgzipmodule-debian-squeeze
GZip is the most popular solution for web servers and is very simple to implement.
I don't really have enough info to provide much more advice other than to say that I normally use Ruby on Rails for stuff like this and gzip is handled very simply with the ative support gzip library using something similar to this contacts = ActiveSupport::JSON.decode(gzipped_contacts.gsub("+", ""))
UPDATE 2 notifyChange()
Just to pick up on your point about notifyChange not being appropriate in the content provider due to there being no internet access.
It is fine to use notifyChange() in your content provider as it will tell the sync adapter to update as soon as it is appropriate to do so which means when the device is not too busy and as soon as an internet connection becomes available. That's the whole point of the sync adapter. Should you need to make use of notifyChange in your content provider for other services such as array adapters but you do not want the sync adapter to be told to update then there is a little documented boolean parameter that you can add to the end of the notifyChange params list. set it to false and the content provider will ignore the notifyChange
e.g. instead of the usual getContext().getContentResolver().notifyChange(uri, null);You can use getContext().getContentResolver().notifyChange(uri, null, false);
a) You could ask the users to sign in / sign up from the mobile apps, exactly as you would do it for a web site.
b) Take a look at this http://android-developers.blogspot.ro/2013/01/verifying-back-end-calls-from-android.html
Send more records in the same request, the idea is to make as few requests as possible.
I don't think you should keep the flag for error the same as the default value, it should be a different value so that you will be able to handle it more easily.
I am dealing with huge data (downloading from webserver to client/phone). Currently I am trying to parse and load complete data into sqlite database when the application launches.
This is taking a lot of time. I want to load the data based on the screen navigation.
How do I achieve that?
You'll want to pass information between your server and the device as XML.
This way the device can request URLs for specific information such as example.com/news/latest (return headlines of the latest 20 news articles), example.com/news/americas (the latest 20 article headlines from the Americas) or example.com/news/article/177309/ (one full article).
The server can then query its database for the needed information based on the query and output it for the client as XML. The client can parse the XML and add the data to it's local SQLiteDatabase.
Is this not restricting the dataset returned from the source first, then downloading it onto the client device?
If you are looking for performance boost up , i prefer running an async task in which the data gets uploaded or downloaded to the server. Its similar to threads but much better.