Why Android Database inserting wrong when onPause - android

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.

Related

Async task not populating list properly

I'm developing a feed app, where people can make posts and these posts will populate a RecyclerView.
I have a FAB button that leads to a post activity, but when I post and then comeback to the MainActivity the list is not updated. But when I use the logout button and log back in, the list gets updated, or when I launch the activity it works.
I think this happens because my Async function gets called to work on onCreate, but I can't work like these, I need the AsyncTask to automatically fetch, otherwise people won't get the list updated in real time.
Could you please show me a light in the dark? Here are the codes for MainActivity, PostActivity and logout function from another class.
Main Activity:
public class MainActivity extends AppCompatActivity {
private AppCompatActivity activity = MainActivity.this;
private RecyclerView recyclerViewNews;
private List<Noticia> listNoticias;
private NewsRecyclerAdapter newsRecyclerAdapter;
private DBNoticias databaseHelper;
private Button btnLogout;
private LinearLayoutManager mLayoutManager;
UserSession userSession;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
userSession = new UserSession(getApplicationContext());
recyclerViewNews = findViewById(R.id.recyclerViewNews);
btnLogout = findViewById(R.id.btlogout);
TextView usuario = findViewById(R.id.textView5);
/**
* Olá mundo by Alciomar
*/
SharedPreferences sharedPreferences = getSharedPreferences("Reg", Context.MODE_PRIVATE);
String uName = sharedPreferences.getString("Name", "");
usuario.setText(uName.toUpperCase());
try {
btnLogout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
userSession.logoutUser();
}
});
} catch (Exception e) {
e.printStackTrace();
}
initStuff();
getDataFromPostgres();
FloatingActionButton fab = findViewById(R.id.fabNews);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, PostNews.class);
startActivity(intent);
}
});
}
/**
* This method is to initialize objects to be used
*/
private void initStuff() {
try {
listNoticias = new ArrayList<>();
newsRecyclerAdapter = new NewsRecyclerAdapter(listNoticias);
mLayoutManager = new LinearLayoutManager(getApplicationContext());
mLayoutManager.setReverseLayout(true);
mLayoutManager.setStackFromEnd(true);
recyclerViewNews.setLayoutManager(mLayoutManager);
recyclerViewNews.setItemAnimator(new DefaultItemAnimator());
recyclerViewNews.setHasFixedSize(true);
recyclerViewNews.setAdapter(newsRecyclerAdapter);
databaseHelper = new DBNoticias(activity);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* This method is to fetch all user records from SQLite
*/
private void getDataFromPostgres() {
// AsyncTask is used that SQLite operation not blocks the UI Thread.
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
listNoticias.clear();
for (DBNoticias dbNoticias : databaseHelper.getNewsList()) {
Noticia noticia = new Noticia();
noticia.setUser_id(dbNoticias.getId());
noticia.setNewsTitle(dbNoticias.getNewsTitle());
noticia.setNewsMessage(dbNoticias.getNewsPost());
listNoticias.add(noticia);
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
newsRecyclerAdapter.notifyDataSetChanged();
}
}.execute();
}
Post News Activity:
public class PostNews extends AppCompatActivity {
private DBNoticias dbNoticias;
private Button btnpostar;
private EditText editTextCDNewsTitle;
private EditText editTextCDNewsPost;
private Noticia noticia;
private SharedPreferences sharedPreferences;
public void alert(String titulo, String txt){
AlertDialog alertDialog = new AlertDialog.Builder(PostNews.this).create();
alertDialog.setTitle(titulo);
alertDialog.setMessage(txt);
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alertDialog.show();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_post_news);
btnpostar = findViewById(R.id.btn_postar);
dbNoticias = new DBNoticias();
editTextCDNewsTitle = findViewById(R.id.EditTextNewsTitle);
editTextCDNewsPost = findViewById(R.id.EditTextNewsPost);
}
public void salvarNoticia(View view) {
try {
{
String newsTitle = editTextCDNewsTitle.getText().toString();
String newsPost = editTextCDNewsPost.getText().toString();
if (!(editTextCDNewsTitle.getText().toString().equals("") || editTextCDNewsTitle.getText() == null ||
editTextCDNewsPost.getText().toString().equals("") || editTextCDNewsPost.getText() == null
)) {
sharedPreferences = getSharedPreferences("Reg", Context.MODE_PRIVATE);
String uName = sharedPreferences.getString("Name", "");
String uEmail = sharedPreferences.getString("Email", "");
int uIdUser = sharedPreferences.getInt("IdUser", 0);
dbNoticias.setNewsTitle(newsTitle);
dbNoticias.setNewsPost(newsPost);
dbNoticias.setIdUser(uIdUser);
dbNoticias.salvar();
noticia = new Noticia();
Toast.makeText(getApplicationContext(), "Notícia postada com sucesso",
Toast.LENGTH_LONG).show();
editTextCDNewsTitle.setText("");
editTextCDNewsPost.setText("");
}
}
}
catch (Exception e){
alert("Erro", e.getMessage());
}
}
Thank you in advance if you read and try to help!
There are multiple ways to do this:
Method 1 – Use onResume()
If you call your getDataFromPostgres() method in onResume instead of onCreate, it'll fetch data and refresh list every time the activity wakes from a pause (for example coming back from another activity)
// existing code
#Override
public void onResume(){
super.onResume();
getDataFromPostgres()
}
(This would be the simplest solution)
Method 2 – Poll the DB continuously
If there are other services that might be updating the database and you need to always show the latest state in the activity, another way (although really inefficient) would be to keep refreshing the list after a defined time period (let's say 10 seconds as an example).
How to run an async task for every x mins in android?
Method 3 – Use onActivityResult
If you want to update the list only when a new entry has been created in the second activity, you can use onActivityResult to notify the first activity on action and then refresh your list there.
How to manage `startActivityForResult` on Android?
Please use this, it's working for me
newsRecyclerAdapter.notifyItemInserted(position);
newsRecyclerAdapter.notifyDataSetChanged();

Safely insert data on SQLite database

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.

Select Statement not working properly [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I have an application consisting of two buttons and a text view.
btnInsert : when the user clicks this, an insert statement will be performed
btnShow : a select statement will be executed and the result is displayed in the TextView.
The problem is the following. I am using AsyncTask to perform write / read operations. I created two separate AsyncTasks, one for reading, one for writing. The insert (Write Async works properly, and I am sure that the values are getting inserted because if I run the same insert statement twice I get a PRIMARY KEY violation error:
07-19 11:46:48.080: E/AndroidRuntime(21486): FATAL EXCEPTION: main
07-19 11:46:48.080: E/AndroidRuntime(21486): android.database.sqlite.SQLiteConstraintException: PRIMARY KEY must be unique (code 19)
This is where the problem arises. Everything is performed properly, apparently, when I run the Select Statement ( by clicking the button), however instead of the value, I get com.example.testdb.MainActivity$Select#4203e900.
Does anyone know what the problem is? It is very annoying, I do not know what I am doing wrong. Please have a look at my code:
public class MainActivity extends Activity
{
static DatabaseImplementation db;
static SQLiteDatabase dbWrite;
static SQLiteDatabase dbRead;
static String insert = "INSERT INTO tbl_Test VALUES(7, 'Test');";
static String select = "SELECT test FROM tbl_Test WHERE _id = 1;";
Button btnInsert;
Button btnShow;
static TextView txtView;
//static String name = "";
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
db = new DatabaseImplementation(this);
dbWrite = db.getWritableDatabase();
dbRead = db.getReadableDatabase();
txtView = (TextView)findViewById(R.id.txtView);
btnInsert = (Button)findViewById(R.id.btnInsert);
btnInsert.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
new Insert().execute();
}
});
btnShow = (Button)findViewById(R.id.btnShow);
btnShow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
{
AsyncTask<String, Void, String> n = new Select().execute();
txtView.setText(n.toString());
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
//INSERT ASYNC
private class Insert extends AsyncTask<String, Void, String>
{
#Override
protected String doInBackground(String... params)
{
//Connect to Database First.
try
{
//String insert = executeInsert();
//onPostExecute(insert);
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String result)
{
//Connect to Database First.
dbWrite.execSQL(insert);
}
}
//SELECT ASYNC
private class Select extends AsyncTask<String, Void, String>
{
#Override
protected String doInBackground(String... params)
{
try
{
dbWrite = db.getWritableDatabase();
Cursor c = dbWrite.rawQuery(select, null);
String name = "";
c.moveToFirst();
name = c.getString(0);
return name;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String result)
{
}
}
}
I would really appreciate if someone could help me.
That has nothing to do with the database but just with this two lines:
AsyncTask<String, Void, String> n = new Select().execute();
txtView.setText(n.toString());
Variable n is of tyoe AsyncTask, and applying toString() on it therefore gives you just the name of the class like you described (com.example.testdb.MainActivity$Select#4203e900).
What you got to do is, to change the onPostExecute() method of your Select class to this:
#Override
protected void onPostExecute(String result)
{
txtView.setText(result);
}
and remove the line txtView.setText(n.toString()); from your onClick handler.

How do I refactor my code to use AsyncTask?

I made an application for Android that originally targeted a lower version (2.3). After I got my proof-of-concept working, I tried to get it to work on Android 4. That's when I got the NetworkOnMainThread exception.
After doing some research, I quickly found the AsyncTask, which sounded awesome. The problem is, I'm having a hard time wrapping my mind around it. For instance, here's my original code:
public void Refresh(Context c)
{
SummaryModel model = MobileController.FetchSummary(c);
TextView txtCurrentWeight = (TextView)findViewById(R.id.txtCurrentWeight);
TextView txtWeightChange = (TextView)findViewById(R.id.txtWeightChange);
TextView txtAvgPerWeek = (TextView)findViewById(R.id.txtAvgPerWeek);
if(model.ErrorMessage == "")
{
txtCurrentWeight.setText(model.CurrentWeight);
txtWeightChange.setText(model.WeightChange);
txtAvgPerWeek.setText(model.Average);
}
else
{
Toast.makeText(c, model.ErrorMessage, Toast.LENGTH_LONG).show();
txtCurrentWeight.setText("");
txtWeightChange.setText("");
txtAvgPerWeek.setText("");
}
}
I created an AsychTask like this:
public class WebMethodTask extends AsyncTask<Object, Integer, Object> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(Object result) {
super.onPostExecute(result);
SummaryModel model = (SummaryModel)result;
// Can't seem to access UI items here??
}
#Override
protected Object doInBackground(Object... params) {
Context c = (Context)params[0];
return MobileController.FetchSummary(c);
}
}
How do I access the UI items from the onPostExecute method? Or, do I have the wrong idea on how to use AsyncTask?
Thanks!
You should be able to accessUI where you put your comments (in the postExecute method)
Additionally, I would suggest to use more specialized class with for AsyncTask, so that your code looks better :
public class WebMethodTask extends AsyncTask<Object, Integer, SummaryModel> {
private Activity source;
public WebMethodTask(Activity activity) {
this.source=activity;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(SummaryModel model) {
super.onPostExecute(model );
TextView txtCurrentWeight = (TextView)source.findViewById(R.id.txtCurrentWeight);
TextView txtWeightChange = (TextView)source.findViewById(R.id.txtWeightChange);
TextView txtAvgPerWeek = (TextView)source.findViewById(R.id.txtAvgPerWeek);
if(model.ErrorMessage.length()==0)
{
txtCurrentWeight.setText(model.CurrentWeight);
txtWeightChange.setText(model.WeightChange);
txtAvgPerWeek.setText(model.Average);
}
else
{
Toast.makeText(c, model.ErrorMessage, Toast.LENGTH_LONG).show();
txtCurrentWeight.setText("");
txtWeightChange.setText("");
txtAvgPerWeek.setText("");
}
}
#Override
protected SummaryModel doInBackground(Context ... params) {
Context c = params[0];
return MobileController.FetchSummary(c);
}
}
Edit : Added a reference to your activity, to take your last comment into account.
However, if you acynctask can be long, it's maybe not a very good idea to keep a reference on an activity.
It would be a better design to create a listenerclass that will accept some displayModel(CummaryModel) method, and whose responsability is to cal the setText methods if the activity has not been paused / stopped in the meanwhile...
Fill the ui items with the loaded model data in the WebMethodTask#onPostExecute method.
You need a reference to your UI controls. When passing references to your UI controls to the ASyncTask you will create problems.
Assume the following scenario:
show activity (activity instance 1)
call async task with te activity as reference.
rotate your device (by default a device rotation will create a new activity) -> (activity instance 2)
when the sync task is finished, activity instance 1 is used to display the results. However the activity no longer exists causing exceptions.
The conclusion is that the ASyncTask should not be used for network activity related background tasks.
Fortunately there is a solution: RoboSpice.
RoboSpice uses another approach. Look at https://github.com/octo-online/robospice/wiki/Understand-the-basics-of-RoboSpice-in-30-seconds for a good explanation.
More information: https://github.com/octo-online/robospice
create an inner class in refresh method as
enter code herepublic void Refresh(Context c)
{
SummaryModel model = MobileController.FetchSummary(c);
TextView txtCurrentWeight = (TextView)findViewById(R.id.txtCurrentWeight);
TextView txtWeightChange = (TextView)findViewById(R.id.txtWeightChange);
TextView txtAvgPerWeek = (TextView)findViewById(R.id.txtAvgPerWeek);
if(model.ErrorMessage == "")
{
txtCurrentWeight.setText(model.CurrentWeight);
txtWeightChange.setText(model.WeightChange);
txtAvgPerWeek.setText(model.Average);
}
else
{
Toast.makeText(c, model.ErrorMessage, Toast.LENGTH_LONG).show();
txtCurrentWeight.setText("");
txtWeightChange.setText("");
txtAvgPerWeek.setText("");
}
class WebMethodTask extends AsyncTask<Object, Integer, Object> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(Object result) {
super.onPostExecute(result);
SummaryModel model = (SummaryModel)result;
// Can't seem to access UI items here??
}
#Override
protected Object doInBackground(Object... params) {
Context c = (Context)params[0];
return MobileController.FetchSummary(c);
}
}
}

android asynctask update to the listview in postexecute

Hi I'm having problem refreshing my listview after Async operation.
I have a simplecursoradapter, and custon listview and a button. Initially when application starts, it sets the listview from the data read from database. Then when user clicks a button, it starts a async code to download some data which gets inserted into a database. When async task start, I'm displaying a progressdialog, which I dismiss in postexecute(). Data is getting downloaded fine, but now how do I requery the cursor and update listview on the main thread after background job is done?
A Method "refreshRemoteData" gets called via a menu button.
This is how my AsyncTask looks like.
public class MyActivity extends ListActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void onStart() {
myDBAdapter = new DBAdapter(this);
myDBAdapter.open();
populateMyList();
}
private void populateMyList() {
myCursor = myDBAdapter.fetchAllItems();
startManagingCursor(myCursor);
getListView().setAdapter(myDBAdapter);
}
private void refreshRemoteData() {
mPleaseWaitDialog = ProgressDialog.show(ExpirationDateTrackingActivity.this,
"Data", "Downloading data", true, true);
download_task = new InfoDownloaderTask();
download_task.execute();
}
private class InfoDownloaderTask extends AsyncTask<Object, String, Boolean> {
private static final String DEBUG_TAG = "InfoDownloaderTask";
protected DBAdapter mylocalDBAdapter=null;
#Override
protected void onPreExecute() {
Log.e(DEBUG_TAG, "onPreExecute: ");
mylocalDBAdapter = new DBAdapter(this);
mylocalDBAdapter.open();
}
#Override
protected void onPostExecute(Boolean result) {
Log.i(DEBUG_TAG, "onPostExecute: " );
mPleaseWaitDialog.dismiss();
mlocalDBAdapter.close();
}
#Override
protected Boolean doInBackground(Object... arg0) {
Log.v(DEBUG_TAG, "doInBackground");
///...
//Update the database
mylocalDBAdapter.insertData(....);
return true;
}
} //AsyncTask
}
I don't see my listview getting updated with new list data right after async operation is complete. But If I invoke another ativity and comeback to the listview then I see all new items (list update).
What am I missing?
You're inserting data through mylocalDBAdapter, but you aren't telling myDBAdapter about it. Try calling myDBAdapter.notifyDataSetChanged(); at the end of onPostExecute().

Categories

Resources