I am fetching data from web service and storing it to SQLite database. The records I'm fetching are more in number so it takes too much time to fetch the data. I want to fetch this data such that while fetching data I can use the app. That is I want to fetch data in the background like we download large files. While downloading we can do the rest of task. How should I implement it in my app?
you should call web service from asyncktask which works on background.
#Override
protected String doInBackground(String... params) {
//call your webservice from here;
return ;
}
In the beginning I was using my custom Asynctask, but fetch information from a web service was very slow. Now I use Retrofit, and the time is very short. My best advice is that implements Retrofit.
Retrofit
already there are lot of answers similar to this is available, anyway here is the sample code.
create a innerClass name as MyAsyncClass
class MyAsyncClass{
#Override
protected Object doInBackground(Void... params) {
// write your method to fetch data from network
}
#Override
protected void onPostExecute(Object output) {
// do what ever you want to do with 'output' data
}
}
now you can call this class like this
MyAsyncClass myAsyncClass = new MyAsyncClass();
myAsyncClass.execute();
and here you can open some new activity.
Intent intent = new Intent(this, yourActivityName.class);
startActivity(intent);
Related
I want to get a data from a kinvey Collection, put it in a db and then modify it locally.I want to be sure that all data is gotten from collection before any modification. My problem is that, getting collection is done via AsyncAppData which runs in background,which makes my task impossible.
A sample code is shown
//getting data
ArrayList<String> runfunc = new ArrayList<String>();
final AsyncAppData<EventEntityWhy> myevents4 = mKinveyClient.appData("WhyWorldTemp", EventEntityWhy.class);
myevents4.get(new KinveyListCallback<EventEntityWhy>() {
#Override
public void onSuccess(EventEntityWhy[]){
for (EventEntityWhy x1 : result) {
String temp1 = (String) x1.get("whyindex");
runfunc.add(temp1)
}
}
}
//then processing will start
//runfunc array will be processed here
That's not how asynchronous programming works, and Kinvey has no plans to change that paradigm. The proper way to build your code is by processing your data inside the onSuccess callback rather than on the mainthread.
What you could do is set an event flag inside the callback, and then you create a waiter at your "//then processing will start" point that waits for that flag.
I'm doing a lost property office application. It consists of four tabs, each tab must display announcement feed uploaded by users. By clicking on a particular item opens a new activity to derive more information.(Well, sort of news feed). I take the data from the API site in the form of JSON.
I did four tabs using ViewPager, Fragment. image my fragments
I have tried to place every Fragment listview and display their data with JSON with AsynTask. And caused AsyncTask for each fragment also called the same JSON in the first fragment. May be it is not right.
So, please tell me the correct move.
What used to for display data into listview from json
How to display information on a new activity that opens when you press the listview item?
Send to fragment over the intent or download a JSON again?
How to realize adding ads by user?
If possible, write the steps. Thank you very much, I will be glad of any help.
P.S Sorry for bad English
First of all you can use a simple list adapter to be able to put JSON data into a listview, you can see a tutorial of this here.
Second to be able to see details about a item in a list view you can use a onListItemClick, with extending ListActivity. An example of doing this would be:
MyListActivity.java
public class MyListActivity extends ListActivity {
// . . .
protected void onListItemClick(ListView l, View v, int position, long id) {
//handle the list click here
intent = new Intent(this, ListDetails.class);
//convert the position int into a string to pass to the intent
value = String.valueOf(position);
//put the value into the intent
intent.putExtra("key", value);
//start the activity here
MyListActivity.this.startActivity(intent);
}
}
ListDetails.java
public class ListDetails extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//gets the value sent with the intent
Intent intent = getIntent();
final String helpView = intent.getStringExtra("key");
// . . .
}
This is assuming that you are using a ListActivity to make the list and it really depends on what sort of information you want to display, if you want to display all the data, you could pass the JSON data as a string through the intent, then get it like in the example above.
Thirdly if you want to keep the JSON data you can just pass it along with the intent and then when the user presses back, just pass it back to the original activity once again through the intent. If you want to re-download the JSON data, you can, but to save with users mobile internet connection going over (especially for large JSON files repeatedly), in would not recommend using this option. If you want to download the JSON data again, you will need to use a AsyncTask to download the data, so not to disrupt the user interface and that it will raise a error when you try to do this (believe me, I have pulled my hair out over this). A example of a AsyncTask is (from the android project I am working on, that uses google maps to calculate a route):
private class ReadTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... url) {
String data = "";
try {
HttpConnection http = new HttpConnection();
data = http.readUrl(url[0]);
} catch (Exception e) {
Log.d("Background Task", e.toString());
}
return data;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
Log.i("Log","Parser Task Started");
Log.i("Log",result);
new ParserTask().execute(result);
}
}
private class ParserTask extends
AsyncTask<String, Integer, List<List<HashMap<String, String>>>> {
#Override
protected List<List<HashMap<String, String>>> doInBackground(
String... jsonData) {
JSONObject jObject;
List<List<HashMap<String, String>>> routes = null;
try {
jObject = new JSONObject(jsonData[0]);
PathJSONParser parser = new PathJSONParser();
routes = parser.parse(jObject);
} catch (Exception e) {
e.printStackTrace();
}
return routes;
}
#Override
protected void onPostExecute(List<List<HashMap<String, String>>> routes) {
//process the JSON data here
}
}
You would place this inside a activity, adding in the necessary processing for the JSON data inside the onPostExecute in ParserTask. To download the JSON data, you would call (replacing the url with your url for getting the JSON data):
String url = "http://www.example.com"
ReadTask downloadTask = new ReadTask();
downloadTask.execute(url);
EDIT:
Lastly to show the latest or most important/relevant lost property adverts, you can once again use JSON to get this from your backend website. In PHP you can customise server responses, sending back JSON responses depending on values in the GET (?thisIsTheGet=blahblahblah). To add advertisements you can create a seperate activity, with EditTexts etc, to create a form, then send the data through a GET request to your backend server (where the JSON is held), so the server can update the advertisement list. Once again you can use a AsyncTask to send the GET request to the server, perhaps using methods above to send back from the server the success of the adding of the advertisement. A example of what your form could look like (XML) would be:
activity_add_advertisement.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context="your.activity.class.root.activityAddAdvertisement"
tools:showIn="#layout/activity_add_advertisement"
android:id="#+id/LLMainContent"
android:orientation="vertical"
>
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/edittext1"/>
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/edittext2"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/submitButton"/>
</LinearLayout>
Then set a on click listener for the button being pressed inside the activity:
activityAddAdvertisement.java
public class activityAddAdvertisement {
// . . .
Button submitButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
// . . .
submitButton = (Button) findViewById(R.id.submitButton);
submitButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//call the methods from above to send a request to a url, with the contents of the edit texts in the GET request
}
}
}
You can add more EditTexts and other elements and inside the contents inside the GET request. The server will then edit the JSON to include the new advertisements. The PHP won't be too hard, if you need some tutorials on PHP, W3Schools has good tutorials and examples for you to use.
Further Reading:
Android Intents
I don't understand how is the Parse working?
I download data in parse to my arraylist , but when I show the Pets.size inside (//here) method "done" it will show 4, but when I show pets.size outside the done's method it will show 0?
public class Test extends AppCompatActivity {
ArrayList<Pet> pets;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
pets = new ArrayList<>();
ParseQuery<Pet> query = new ParseQuery<>("Pets");
query.findInBackground(new FindCallback<Pet>() {
#Override
public void done(List<Pet> list, ParseException e) {
if (e!=null){
Toast.makeText(Test.this,"Error",Toast.LENGTH_LONG).show();
}
for (Pet pet : list){
Pet newPet = new Pet();
newPet.setName(pet.getName());
newPet.setType(pet.getType());
pets.add(newPet);
}
// here
}
});
Toast.makeText(Test.this,"You have "+pets.size()+" pets",Toast.LENGTH_LONG).show();
}
Here's my Pet class:
#ParseClassName("Pets")
public class Pet extends ParseObject {
public String getName(){
return getString("name");
}
public void setName(String name) {
put("name", name);
}
public String getType(){
return getString("type");
}
public void setType(String type) {
put("type", type);
}
}
And an orther question , what should I do if I wanna save the data in local data?
Explanation:
findInbackground performs an operation to find all ParseObjects in a background thread (outside the main thread, or UI thread). So when it completes in the place where you have the comment
//here
That is when the background thread finishes it's call to find the objects. When you try to look at the size of the array outside that call where it shows size of 0, it is because it reached that point before the background thread finishes it's work (of adding to your array from objects it found).
What is happening is the operation for find() is happening in parallel with your main threads code.
And for your second question, make sure you enableLocalDatastore and then you can pin results from queries to your local cache. This data is stored on the device until the user deletes your app or clears cached data in settings.
Follow this guide to setup local cache Local Datastore with Parse
Note: A solution to your problem for when the background task of finding the pets is complete is to call a method from within the Callback for the findInBackground call that will handle the newly found Pet ParseObjects. Also remember to handle if the query fails either by finding no objects or some failure in connection / timeout.
just calling pet.pin() or pet.pinInBackground(); you can save a parseObject in local storage , to query objects in local storage you need set query.fromPin(true)
https://parse.com/docs/android/guide#objects-the-local-datastore
"done" method fires when the background task ends.
I am using this Volley example
It works perfect, but when I change the response of data to 150+ records from server it takes a long time to load.
So I want to load small amount of data 5-10 record then another 5-10 records.
How can I do this with Volley?
Volley will fetch all the response which it is supposed to receive at client end(Mobile end). This type of behavior cannot be accomplished on Client Side or Mobile end.
This should be done in the API or server side by implementing pagination in services, something like below:
http://serviceendpoint.com?start=0&&end=5 fetch first five record.
http://serviceendpoint.com?start=5&&end=10 fetch next five record.
//Constant Variable denoting after how many
//to call in one service
//items numbers you need
private final int LIST_FETCH_COUNT =5;
private final int TOTAL_COUNT=1500;
private int start=0;
private int end=0;
//you can do something like this
for(int i=0;i<TOTAL_COUNT;i+=LIST_FETCH_COUNT){
callAsyncService(i,i+LIST_FETCH_COUNT);
}
private void callAsyncService(int start,int end){
//create a new async object
asynObject.execute(Void,Void,start,end);
}
//inside your async
doInBackground(params...){
//get start and end values from params and run a service
}
You could use AsyncTask to do something like this:
private class DatabaseTask extends AsyncTask<URL, Integer, String> {
protected String doInBackground(URL... urls) {
//put here your volley query.
}
return results;
}
protected void onProgressUpdate(Integer... progress) {
//You can show the progress of the download with this function:
setProgressPercent(progress[0]);
}
protected void onPostExecute(String results) {
//Parse the results here and show them in the UI.
}
}
Then, assuming you are trying to connect to an online database, for example a MySQL database, you could easily implement a PHP interface to your database which returns only the amount of records you want (for example 10) and call the DatabaseTask whenever you need the records.
Alternatively, you could do a separate Thread working on a timer which sends query whenever the timer fires.
I am in process of developing an Android tablet app using sqllite 3.7.4 which would
perform following:
Fetches information from the UI
Performs some logic and store related information to the sqlite database
The stored information has to be send immediately OR at schedule
interval (ex. at 5:00 on xyz date) over the network
Currently, we have developed a dispacher mechanism (thread ), which constantly polls the database for new information inserted in the database. The thread fetches the information and send to the network module.
But, I feel this is not the correct approach as
Polling every time is a overhead. There can be times when there is nothing to execute
It is not real time , because we poll after every 5 seconds
So
Is there a way to send a trigger to my network module as soon as information is updated in database?
Or any better way to achieve this task?
Thanks in advance.
This question is about one year ago, but i think this is a common problem. This is how i handled the Database changes:
In my Adapter ( SQL ADAPTER) i have methods for updating / deleting or inserting data into the Database obviously. Like this method:
public long addProduct(String code, String name ... String gid, String gdate) {
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_CODE, code);
initialValues.put(KEY_NAME, name);
...
initialValues.put(KEY_CHECK, this.checkfalse);
initialValues.put(KEY_GID, gid);
---------
Intent i = new Intent("data_inserted");
i.putExtra("date", date);
sendBroadcast(i);
---------
return mDb.insert(SQLITE_TABLE, null, initialValues);
}
After the change happened it will send an broadcast intent. To fetch this first register your Broadcast Receiver in your onCreate Method (uploaderClass or whatever). This will look like this:
registerReceiver(Updated, new IntentFilter("data_inserted"));
And this Method to handle the following actions!
private final BroadcastReceiver Updated= new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
doSomething(); // Data was inserted upload it
}
};
EDIT :
To fetch only new items from database, I sign new products. I have a colum "info" which can contain Strings like "upload", "update" or "delete". Then i fetch all Items from the database which contain these special strings and upload them. After that i set them to null or an empty String. Whatever you wish. Hope i explained it not to complicated :)
You can create your own database listener whenever something is updated to the database it will fetch the information and send to the network. I think will clear some idea for implementing this thing.
Now we can use Room to achieve this.
database.getInvalidationTracker().addObserver(new InvalidationTracker.Observer(tableToObserve) {
#Override
public void onInvalidated(#NonNull Set<String> tables) {
}
});
database is an instance of RoomDatabase, which is the base class for all Room databases. All classes that are annotated with "#Database" (which is the way to use the Room Libary) must extend this class.
In the creator method of InvalidationTracker.Observer, you can pass in an array of String (or in the form of varargs) to indicate the tables you'd like to observe, if any update happen to those tables, the callback method onInvalidated is invoked.
Some links to refer to:
https://developer.android.com/reference/android/arch/persistence/room/InvalidationTracker.html#addObserver(android.arch.persistence.room.InvalidationTracker.Observer)
hope so this will help you
private Handler h;
// in create time
h = new Handler();
// call where you want
h.postDelayed(myRunnable2, 1000); // after 1000 millisecond this function call automatically
// this function
private Runnable myRunnable2 = new Runnable() {
public void run() {
// do some thing
h.postDelayed(myRunnable2, 1000);
}
};