Android;use "ContentProvider" to download from web server - android

Is it possible to use ContentProvider for retrieving(query) data from web server?
Some data that are used in App are stored locally and some others stored in web server,I want to encapsulate retrieving data and also storing data by ContentProvider.
Obviously retrieving local data is simple and may be done by ContentProvider.query() method.My problem is in about use that method to query from web.Clearly I can start AsyncTask to fetch data from web,but result returned from query method,before terminating doInBackground() of AsyncTask and downloaded data never used.
So how can I return downloaded data to query method?

Is it possible to use ContentProvider for retrieving(query) data from
web server?
No.
So how can I return downloaded data to query method?
you can not remove the delay of downloading obviously but you can use for example loader and after your data is ready(downloaded) insert it to the database and call
getContentResolver().notifyChange(your uri, null);
or you can use other method like LocalBroadcastManager or EventBus for sending messages to your object to query the ContentProvider again.

I think you can just move AsyncTask from content provider to main app and catch the result, like
new AsyncTask<String, Integer, Cursor>(){
#Override
protected Cursor doInBackground(String... params) {
return getApplicationContext().getContentResolver().query(...);
}
}.execute("");
P.S.
Also I've found interesting words in Google docs :
methods query(), insert(), delete(), update(), and getType()—are called from a pool of threads in the content provider's process, not the UI thread for the process.
But when I've tried to call network operation inside the query method (without AsyncTask) it simply throw NetworkOperationInMainThread exception.

Related

Android - Room Persistence Library - Access data both synchronously & through observer based on need

Problem:
I am using Room Persistence Library and so far everything is working fine except that there is a data from select query which I need synchronously as I am calling it from a Periodic Job (Work Manager's Worker). I have defined the return type to be LiveData as I am also accessing it for display purposes in UI and so observers are great for that but now I also need the same data in Job.
Code Snippet
#Query("SELECT * from readings ORDER BY date, time ASC")
LiveData<List<Reading>> getAllReadings();
Tried
I have tried the getValue() method in LiveData but it returns null as the data is not loaded in LiveData while making the query.
readingDao().getAllReadings().getValue() // returns null
Possible Solution
There is only one solution that I can think of which is to duplicate the getAllReadings query with a different name and return type (without LiveData) but I don't think this is a clean approach as it increases duplication of code just to get a synchronous return type.
Please let me know if there is any other solution or perhaps some way to synchronously access data from LiveData variable.
You can allow main thread query when you initialize Room DB, but it's clearly not desirable. This will give you the synchronous behavior but will block user interface. Is there a specific reason you want this to be synchronous?
The reason why getValue() is returning null is because Room is querying data asynchronously. You can attach an observer or a callback function to get result when the query is finished. You can display the result to the UI or chain another call for sequential operation etc from there.
I use RxJava to wrap my query request for asynchronous query but I you can also use AsyncTask.

AsyncTask with SQLiteDatabase

I'm a beginner in android. I want to perform basic CRUD operations of SQLiteDatabase using AsyncTask class. I have one int and 4 String parameters for table.How do i pass arguments to insert data in table from DataBaseHelper Class to AsyncTask Class.
This tutorial explains the usage of ContentProvider and Loader. Although Content Providers are overkill for small applications, it is the best way to implement a SQLiteDatabase within your application. Basically it allows you to have a app database accessible from every other application you wish and eases the usage of CRUD operations inside any of those.
With it, you don't need any reference to your SQLiteOpenHelper in order to make any operation in your database. Content Providers work by calling getContentResolver().<insert/delete/update>() directly in your Activity, keeping your code clean. Also, every operation you do using this API is sent to the background thread, leaving you no work at all besides configuring it for the first time.
A class that extends ContentProviderwill have 4 methods: insert(), delete(), update() and query(). These same methods must receive an URI that points to the table you will be using in that operation. Cool, huh? 4 methods for every operation in any table. You could also use a Constants class to map your URIs and boom: you got state of the art code.

Fetching big amount of data, what is the best way to go?

I have severals URLs I need to get data from, this should happen in order, one by one. The amount of data returned by requesting those URLs is relatively big. I need to be able to reschedule particular downloads which failed.
What is the best way to go? Shall I use IntentService, Loaders or something else?
Additional note: I would need not only to download, but also post process the data (create tables in db, fill it with data, etc). So DownloadManger can't be of help here.
I would use an IntentService.
It has a number of advantages that are suitable for your needs, including being able to download the data without your application running and supporting automatic restart of the service using setIntentRedelivery().
You can set a number of identifiers for the particular job, you need to perform using Intent extras, and you can keep track of the progress using SharedPreferences - that way you can also resume the work if it's been cancelled previously.
The easiest way is probably to use the system DownloadManager http://developer.android.com/reference/android/app/DownloadManager.html
(answering from my phone, so please excuse the lack of formatting)
I would suggest a service for this. Having service resolves many problems
It would allow reporting of progress asynchronously to the application so you can enable or disable a specific gui in application based on the download status of data
It will allow you to continue the download even if the user switches to other application or closes the application.
Will allow you to establish independent communication with server to prioritize downloads without user interaction.
Try a WakefulIntentService for creating a long-running job that uses wakelocks to keep your task alive and running https://github.com/commonsguy/cwac-wakeful .
Also, if your whole app process is getting killed, you may want to look into persisting the task queue to disk, using something like Tape, from Square
I think the way to go is loading urls in an array, then starting an AsyncTask, returning a boolean to onPostExecute indicating if the operation has success or not. then, keeping a global int index, you can run the AsyncTask with the next index if success, or the same index otherwise. Here is a pseudocode
private int index=0;
//this array must be loaded with urls
private ArrayList<String> urlsArray;
new MyDownloaderAsyncTask().execute(urlsArray.get(index));
class MyDownloaderAsyncTask extends AsyncTask<String,String,Boolean>{
#Override
doInBackground(String... input){
//downlaod my data is the function which download data and return a boolean
return downloadMyData();
}
#Override
onPostExecute(Boolean result){
if(result)
new MyDownloaderAsyncTask().execute(urlsArray.get(++index));
else
new MyDownloaderAsyncTask().execute(urlsArray.get(index));
}
}
hope this help
I have just completed an open source library that can do exactly what you need. Using droidQuery, you can do something like this:
$.ajax(new AjaxOptions().url("http://www.example.com")
.type("GET")
.dataType("JSON")
.context(this)
.success(new Function() {
#Override
public void invoke($ droidQuery, Object... params) {
//since dataType is JSON, params[0] is a JSONObject
JSONObject obj = (JSONObject) params[0];
//TODO handle data
//TODO start the next ajax task
}
})
.error(new Function() {
#Override
public void invoke($ droidQuery, Object... params) {
AjaxError error = params[0];
//TODO adjust error.options before retry:
$.ajax(error.request, error.options);
}
}));
You can specify other data types, which will return different object types, such as JSONObject, String, Document, etc.
Similar to #Murtuza Kabul I'd say use a service, but it's a little complicated than that. We have a similar situation related to constant internet access and updates, although ours places greater focus on keeping the service running. I'll try to highlight the main features without drowning you in too much detail (and code is owned by the company ;) )
android.permission.RECEIVE_BOOT_COMPLETED permission and a BroadcastReceiver listening for android.intent.action.BOOT_COMPLETED to poke the service awake.
Don't link the service to the Activity, you want it running all the time. eg we call context.startService(new Intent(context.getApplicationContext(), OurService.class))
The service class is just a simple class which registers and calls an OurServiceHandler (as in our case we fire off repeated checks and the Handler manages the 'ticks')
We have an OurServiceRunnable which is a singleton which is checked and called by the Handler for each test. It protects against overlapping updates. It delegates to an OurServiceWorker to do the actual lifting.
Sounds heavy handed, but you want to ensure that the service is always running, always ticking (via the Handler) but only running a single check at a time. You're also going to run into database issue if you use the standard SqlLite DbHelper paradigm, as you can't open the DB on multiple threads and you definitely want the internet access off the main thread. Our hack was a java.util.concurrent.locks.ReentrantLock protecting access to the DB, but you could probably keep DB access on the UI thread and pass DB operations via the Handler.
Beyond this it's just a matter of keeping the downloads atomic in terms of "get task, download task, complete task" or enabling it to pick up from a failed state eg downloaded OK, attempt to complete.
You should take a look at the volley library :
http://www.javacodegeeks.com/2013/06/android-volley-library-example.html
There is also an interesting video of the author that took place at google io 2013 :
http://www.youtube.com/watch?v=yhv8l9F44qo
Mainly because it eases the process of managing a lot of these fastidious tasks that are connection checking, connection interruption, queue management, retry, resume, etc.
Quoting from the javacodegeeks "Advantages of using Volley :
Volley automatically schedule all network requests. It means that Volley will be taking care of all the network requests your app executes for fetching response or image from web.
Volley provides transparent disk and memory caching.
Volley provides powerful cancellation request API. It means that you can cancel a single request or you can set blocks or scopes of requests to cancel.
Volley provides powerful customization abilities.
Volley provides Debugging and tracing tools"
Update from dennisdrew :
For large file, better use a variant of volley which authorize using another http client implementation. This link gives more details :
The volley article about this modification :
http://ogrelab.ikratko.com/android-volley-examples-samples-and-demos/
The github file detail :
https://github.com/ogrebgr/android_volley_examples/blob/master/src/com/github/volley_examples/toolbox/ExtHttpClientStack.java
public class FetchDataFromDBThread implements Runnable {
/*
* Defines the code to run for this task.
*/
#Override
public void run() {
// Moves the current Thread into the background
android.os.Process
.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
FetchDataFromDB();
}
}

ContentAdapter Sqlite database multiple databases

This is actually two questions:
If i expose my SQLite as a ContentProvider in my application it will work in an asynchronous fashion ?
Imagine i have the following tables in my database:
TableChats
TableChatMessages
and i also have a class
Message
To work with ListViews and have those list views use data from the ContentProvider must that data returned be a Cursor ? or is it possible to query for all messages in a chat and return an array of Message.
Sorry i know this may be a dumb question but i'm new to android development and the concept of ContentProvider and ListViews and how to connect them isn't quite yet clear to me.
To my knowledge
A content provider manages access to a central repository of data which shared between multiple applications. Normally all methods access the data work on the UI thread. If you want asynchronous, they suggest to use CursorLoader.
You can query all messages, get data from Cursor and put to your Message object.
Sample:
Cursor sampleCursor = getContentResolver().query("Your query");
ArrayList<Message> list;
if(sampleCursor!=null){
while(sampleCursor.moveNext()){
Message item = new Message();
item.sender = sampleCursor.getString(senderColumnIndex);
item.messageBody= sampleCursor.getString(messageBodyColumnIndex);
list.add(item);
}}
//Pass your list to your adapter.
Or directly pass your cursor using CursorAdapter

AsyncTask Implementation

In my application, i need to reduce the time of inserting videos and other details from the database. I'm trying to use the AsyncTask concept in my application. But it gives an error in my insertion part when i do it in doInBackground().Another class does the insertion.
abc.insert(arguments);
where abc is the object of my database class.
Error shown is nullpointerexception in my class where insertion is done.
Is there any solution for this?
thanks,
niki
I don't fully get your case, but it sounds like your are a victim of synchronization issue - several Threads are calling your insertion code.
If this is the case, then a simle solutions is to use Java synchronized statement around your insertion code, e.g.:
public synchronized void insert() { /* code to insert */ }
or
private Object lock = new Object(); // a field of your DBHelper
// somewhere below in your DBHelper
synchronized (lock) {
/* code to insert */
}
If you are simply looking to add data to your database in a worker thread with no UI update post addition then use Java Threads insted of AsynTask.
The sole objective of AsyncTask is to perform the expensive operations in background and update UI after the operation has been performed.
As suggested by Arhimed the database locking can be an issue in your case if you have fired multiple AsyncTasks.

Categories

Resources