I need to load a data coming from a service in a table on the SplashScreenActivity. I've followed this tutorial and everything works just fine. I have also added a custom AsyncTask to run the insert loop in the background.
The problem is that if a configuration change happens in the middle of the insert (e.g. screen rotation) everything blows up and I get corrupted data saved on the database.
I've read stuff about CursorLoader but that's only for querying the database. I've also looked at ContentProviders but they don't solve the problem.
Any ideas on how to handle this problem?
What I basically need is:
Access database from a background thread to keep the UI responsive.
Handle configuration changes when doing inserts on the database.
UPDATE:
public class SplashScreenActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash_screen);
...
// Create a Volley Request and fetch data
}
When I get the Response object I start the AsyncTask:
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
if (response.optString("lastrunstatus").equals(
"success")) {
JSONObject results = response
.optJSONObject("results");
JSONArray objects = results
.optJSONArray("objects");
new HandleResponseAsyncTask().execute(objects);
}
}
In the AsyntTask, I insert all objects:
private class HandleResponseAsyncTask extends
AsyncTask<JSONArray, String, Void> {
#Override
protected void onPreExecute() {
mDataSource.open();
}
#Override
protected Void doInBackground(JSONArray... params) {
publishProgress("Deleting data...");
mProductosDataSource.deleteAll();
publishProgress("Saving data...");
JSONArray objects = params[0];
for (int i = 0; i < objects.length(); i++) {
JSONObject object = objects.optJSONObject(i);
// Get each column value from JSON
...
mDataSource.insert(id, name, description);
}
return null;
}
#Override
protected void onProgressUpdate(String... messages) {
mTextViewLoading.setText(messages[0]);
}
#Override
protected void onPostExecute(Void result) {
mDataSource.close();
// Go to main
startMainActivity();
}
}
NOTE: mDataSource holds an instance of a helper class that calls the methods in my custom SQLiteOpenHelper class.
Related
How can I add elements to an Array or ArrayList from the AsyncTask class(Inner) , from where I am receiving data from server .
I tried adding elements from doInBackgroud() and printing them in onPostExecute() ,it works fine then .
But the Array and List are both empty when I am trying to access them outside the AsyncTask class.
Code :-
public String[][] mov_details ;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.vpmovies);
mov_details=new String[NUM_OF_MOVIES][9];
new MyHttpMovies().execute();
Toast.makeText(this,mov_details[0][2],Toast.LENGTH_LONG).show(); //prints blank
doInBackgroud() and onPostExecute() -
for(int i=0; i < jsonArray.length(); i++){
JSONObject jsonObject = jsonArray.getJSONObject(i);
//parsing some json
mov_details[i][0] = (jsonObject.optString("name").toString());
mov_details[i][1] = (jsonObject.optString("lang").toString());
mov_details[i][2] = (jsonObject.optString("genre").toString());
.
.
.
.
return mov_details;
}
protected void onPostExecute(String[][] strings) {
super.onPostExecute(strings);
Toast.makeText(VPmovies.this,strings[0][1],Toast.LENGTH_LONG).show();
// prints successfully
}
public class MainActivity extends AppCompatActivity {
ArrayList<String> list;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public class fetchData extends AsyncTask<Void,Void,Void> {
#Override
protected Void onPreExecute() {
super.onPreExecute();
list = new ArrayList<String>();
}
#Override
protected Void onPostExecute(Void... params) {
...
list.add("bla bla");
...
return null;
}
}
}
Use publishProgress("data") inside your doInBackgroung and pass data from AsyncTask to your Activity/Fragment. Keep in mind doInBackgroung runs in separate thread you can not directly update your main GUI from doInBackgroung, if you will call some methods directly from doInBackgroung than your calling method should run in main thread.
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
// send data to your required location its recommended to use interfaces for communication
}
Solved by simply using the get() method on the AsyncTask instance that would return the output/result of the AsyncTask backgroud thread.
mov_details = new MyHttpMovies().execute().get(); //returns 2d array
and instead of using mov_details variable inside doInBackground() , I used some other 2d array variable local to the just AsyncTask.
I know how to use AsyncTask to download file, create a zip file or so.. as I call publishProgress() in my loop.
I got stuck when doInBackground() has a single slow line, no loops here, just creating an object where its constructor has slow loops.
I'm not sure about the reasonable way of updating progress in such case.
Here's a sample code:
public class Session {
private QQActivity activity;
public int createdParts;
public DailyClass daily;
private void checkDaily() {
if(!isDailyReady){
new SetAsyncQQDaily().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
class SetAsyncQQDaily extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... params) {
String sdq = null;
daily = new DailyClass(Session.this); //Very very Slow!
// Do other network http
sdq = new String(Base64.encode(bos.toByteArray(),Base64.DEFAULT));
// Do some work
return sdq;
}
#Override
protected void onPostExecute(String sdq) {
//Never mind
}
#Override
protected void onPreExecute() {
Toast.makeText(activity,"Preparing the daily. Get ready!",Toast.LENGTH_LONG).show();
}
#Override
protected void onProgressUpdate(Void... values) {
//TODO: Update Value of leftBar
activity.leftBar.setProgress((100*createdParts)/Utils.DAILY_PART_COUNT);
}
}
}
In the slow constructor class, I can set-back an integer of the current progress: createdParts, but cannot call publishProgress.
public class DailyClass implements Serializable {
public DailyClass(Session session){
for(int i=1;i<=partCount;i++ ){ //Very slow loop
session.createdParts = i; //TODO: reflect value to progress bar!?
for(int j=0;j<questionsCount;j++){
objects[i-1][j] = createDefined(i);
}
Log.d("Daily","created part"+i);
}
}
//Bla .. !
}
I also though of passing the object of the AsyncTask to the slow constructor in order to call publishProgress() from there, but cannot. As publishProgress() is accessible only from doInBackground()
What's the best practice?
In my Project android i have a big data that i want insert to database.
I am using AsyncTask for inserting big data to database. for average 5 min needed to inserting.
But when my phone screen is off two bug exist.
1- for complete inserting the Screen must be On.
2- if one or many time Screen will be off then database not good inserted.
Question
1- where i am wrong.
2- Other way to inserting big data to database
part of My code
public class MainActivity extends Activity {
DatabaseHandler db;
MobileInformation mobile;
private SetDataBaseTask setDataBaseTask;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
db = new DatabaseHandler(this);
mobile = new MobileInformation();
preferences = PreferenceManager.getDefaultSharedPreferences(this);
String state = preferences.getString("IsSetDataBase","");
if ( !state.equals("yes"))
{
setDataBaseTask=new setDataBaseTask();
setDataBaseTask.execute();
}
}
public void firstDatabaseInitialize()
{
for (int i = 0;i < samsung0.brandStringList.length ; i++ )
{
mobile.Clean();
mobile.Alert_types = samsung0.Alert_typesStringList[i];
mobile.brand = samsung0.brandStringList[i];
//and something other
db.insertMobileInfo(mobile);
}
//and many for for inserting
}
#Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
if (Loading==true)
{
stopLoadingAndDownloading();
if (setDataBaseTask != null && setDataBaseTask.getStatus() != AsyncTask.Status.FINISHED)
setDataBaseTask.cancel(true);
}
db.close();
}
private class SetDataBaseTask extends AsyncTask<Void, Void, String> {
#Override
protected void onPreExecute() {
showLoading();
}
#Override
protected String doInBackground(Void... esult) {
String msg="";
db.open();
db.clearTable("indexing");
db.clearTable("mobile");
firstDatabaseInitialize();
db.close();
return msg;
}
#Override
protected void onPostExecute(String result) {
stopLoadingAndDownloading();
preferences = PreferenceManager.getDefaultSharedPreferences(MainActivity.this);
SharedPreferences.Editor editor = preferences.edit();
editor.putString("IsSetDataBase","yes");
editor.commit();
}
}
}
In my Project android i have a big data that i want insert to database.
Then you could use an IntentService and when the insert is complete send a broadcast and the activity can register on that broadcast action (unregister is necessary as well) so it can display some UI updates.
I am using AsyncTask for inserting big data to database. for average 5 min needed to inserting.
I don't think it's a good idea, because on orientation changes you're screwed! Also, you will leak the parent activity for the duration of insertion. So moving the insertion to an IntentService will decouple the insertion from UI.
I am pretty much new in Java (& android), hence I can't solve it with my limited knowledge despite searching extensively.
In the code below, I want to get a JASONArray from a weblink through AsyncTask. After that I want to populate my database from the array data.
To do that I created the RemoteConnectivity class where I can populate an ArrayList importdata with all the data from JASONArray. But the problem is, I cannot access my database class mylibmandbhandler from inside RemoteConnectivity class (I guess because that is not extended to Activity). And in ImportExport class, if I write the code to insert into database just after calling RemoteConnectivity().execute() [as in code below], it starts inserting before execution ends (very obvious because it is property of AsyncTask).
Now, can anybody please guide me through this? Or any link please to understand the whole process (I am lost in at least 50 pages I read about it :( ).
P.S. mylibmandbhandler is a Class I created (not activity) in my package src folder for my database operations.
public class ImportExport extends Activity {
public void webimport(View v){
new RemoteConnectivity().execute(); // START OF ASYNCTASK
//INSERT importdata INTO DATABASE AFTER EXECUTE
mylibmandbhandler db = new mylibmandbhandler(this);
for (String[] s : importdata){
db.addRecord(new mylibman(s));
}
}
final ArrayList<String[]> importdata = new ArrayList<String[]>();
private class RemoteConnectivity extends AsyncTask<Void, Void, Void>
{
#Override
protected Void doInBackground(Void... arg0) {
..................
..................
importdata.add(dataline); // POPULATE ARRAYLIST IMPORTDATA
return null;
}
#Override
protected void onPostExecute(Void result1)
{
// WHAT TO WRITE HERE
}
}
}
You should insert the data in the onPostExecute as follows:
public class ImportExport extends Activity {
public void webimport(View v){
new RemoteConnectivity().execute(); // START OF ASYNCTASK
}
final ArrayList<String[]> importdata = new ArrayList<String[]>();
private class RemoteConnectivity extends AsyncTask<Void, Void, Void>
{
#Override
protected Void doInBackground(Void... arg0) {
..................
..................
importdata.add(dataline); // POPULATE ARRAYLIST IMPORTDATA
return null;
}
#Override
protected void onPostExecute(Void result1)
{
//INSERT importdata INTO DATABASE AFTER EXECUTE FINISH (POST EXECUTE)
mylibmandbhandler db = new mylibmandbhandler(ImportExport.this);
for (String[] s : importdata){
db.addRecord(new mylibman(s));
}
}
}
}
The reason is because, onPostExecute is the method (callback) which is executed after the data has been done downloading in the doInBackground method.
Alternatively: You can also put the insert statements inside the doInBackground if you want the inserting to be done by background thread. This may be helpful, if inserting into the database is time consuming. In such a case the UI thread won't block. '
public class ImportExport extends Activity {
public void webimport(View v){
new RemoteConnectivity().execute(); // START OF ASYNCTASK
}
final ArrayList<String[]> importdata = new ArrayList<String[]>();
private class RemoteConnectivity extends AsyncTask<Void, Void, Void>
{
#Override
protected Void doInBackground(Void... arg0) {
..................
..................
importdata.add(dataline); // POPULATE ARRAYLIST IMPORTDATA
//INSERT importdata INTO DATABASE. NOW DONE IN THE BACKGROUND THREAD (Alternate method)
mylibmandbhandler db = new mylibmandbhandler(ImportExport.this);
for (String[] s : importdata){
db.addRecord(new mylibman(s));
}
return null;
}
#Override
protected void onPostExecute(Void result1)
{
}
}
}
Update: The important this to highlight in my answer is that I used new mylibmandbhandler(ImportExport.this); instead of new mylibmandbhandler(this); as this refers to AsyncTask which is not what the constructor supports.
You need to use method onPostExecute to insert data to datatable. Like this:
private class RemoteConnectivity extends AsyncTask<Void, Void, Void>
{
#Override
protected Void doInBackground(Void... arg0) {
..................
..................
importdata.add(dataline); // POPULATE ARRAYLIST IMPORTDATA
return null;
}
#Override
protected void onPostExecute(Void result1)
{
//INSERT importdata INTO DATABASE AFTER EXECUTE FINISH (POST EXECUTE)
mylibmandbhandler db = new mylibmandbhandler(ImportExport.this);
for (String[] s : importdata){
db.addRecord(new mylibman(s));
}
}
}
In my main activity I got an arraylist called data. I call an asynctask and do some stuff that gives me a different arraylist called values.
In the post execute of the asynctask I want to use items in 'values' to add some objects to 'data'. However, when debugging I noticed that the objects dont get added.
public class MainActivity extends Activity
{
ArrayList<DataItem> data;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
data = new ArrayList<DataItem>();
update();
}
public void update()
{
AsyncCallAWS thisTask = new AsyncCallAWS();
thisTask.execute();
}
private class AsyncCallAWS extends AsyncTask<String, Void, Void>
{
ArrayList<String> values = new ArrayList<String>();
protected void onPostExecute(Void result)
{
Log.i(TAG, "onPostExecute");
DataItem d;
for(String s : values)
{
d = new DataItem();
d.setValue(s);
d.setDataStreamName("test");
data.add(d);
}
}
//code to fill array
I'm guessing it's because I try to add items from the asynctask? Idk how to solve this, I need the data arraylist for a listview.
In AsyncTask class override method onProgressUpdate(), where you will add elements to array. Then in doInBackground() call publishProgress() for sending elements to onProgressUpdate(). Here http://developer.android.com/reference/android/os/AsyncTask.html -is great example.
private class TestAsyncTask extends AsyncTask<Object, String, Object> {
#Override
protected Object doInBackground(Object... params) {
String item = "";
//Do some stuff
publishProgress(item);
return null;
}
#Override
public void onProgressUpdate(String... value) {
data.add(value[0]);
}
#Override
protected void onPostExecute(Object result) {
}
}
I dont think you should create objects in the onPostExecute-method. Instead create it in the doInBackground-method of the class that extends AsyncTask, and then use set-methods in the onPostExecute-metod.