I am working on an Android App and have a class where user can update his "choices". This is from a Dialog Box which appears when a user installs the app, BUT he can also access it later on via overflow. At the startup, according to the choices by user, I upload a class, NCUP.class on Parse.com. But when user clicks on overflow icon to change preferences, I want to "refresh" the table by deleting ALL the previous records and adding new ones. I was previously using SQLite database and I just used
database.delete(MySQLiteHelper.TABLE_NCUP, null, null);
Now, I can think 3 ways:
(Currently doing) As soon as the user clicks "Done" after selecting his pref, I delete all the objects in the table by below code, but this is taking upto 5 seconds for a class with 13 entries.:
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date date = new Date();
String current = dateFormat.format(date);
ParseQuery<NCUP> query = ParseQuery.getQuery(NCUP.class);
query.equals("objectId");
// query.whereLessThan("createdAt", date);
query.findInBackground(new FindCallback<NCUP>() {
#Override
public void done(List<NCUP> ncupList, ParseException e) {
if (e == null) {
Log.d("QUERY", "Retrieved " + ncupList.size() + " data");
Log.d("QUERY", ncupList.get(1).getCreatedAt().toString());
for (NCUP ncup : ncupList) {
try {
ncup.delete();
} catch (ParseException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
} else {
Log.d("QUERY", "Error: " + e.getMessage());
}
}
});
Get the query by using the line that I have commented above i.e by using current date and adding to query whereLessThan to get and delete older items. But this doesnt work, returns ncupList.size() as 0. Tried different formatting but none helped.
Drop the whole NCUP class and make a new one. I tried to search for this method for it seems to me fastest, but I think I can not do it programatically.
Any suggestions?
The problem might be that you are using ncup.delete(), which is executing an http request on the main thread.
Replace with ncup.deleteInBackground() and your UI won't block.
Also look into ParseObject.deleteAllInBackground(List<ParseObject> objects, DeleteCallback callback) which would seem to do what you need (deleting a list of ParseObjects)
Related
This question already has answers here:
How to skip initial data and trigger only new updates in Firestore Firebase?
(4 answers)
Closed 2 years ago.
i have a problem with my code. I want only to listen when the document is added or deleted. The code is working nearly good. Now when the doc is added - toast appear. That works fine. But when i look at the read counter in my database - it increasing so quickly, like the function is 100% time reading all the data from database - not only for changes, like i want. I need to listen only for the changes in collection. Is it a way to do this in android?
I have a webapp and there my javascript code is working fine, read data only when the change appear.
Below my code:
public void listenToDocument() {
// [START listen_document]
myDatabase.collection("markery").addSnapshotListener(new EventListener<QuerySnapshot>()
{
#Override
public void onEvent(#Nullable QuerySnapshot snapshots,
#Nullable FirebaseFirestoreException e) {
if (e != null) {
Log.w(TAG, "listen:error", e);
return;
}
for (DocumentChange documentChange : snapshots.getDocumentChanges()) {
switch (documentChange.getType()) {
case ADDED:
String popup_data = documentChange.getDocument().getData().get("popup_data").toString();
GeoPoint geop = (GeoPoint) documentChange.getDocument().getData().get("geop");
Context context = getApplicationContext();
Toast toast = Toast.makeText(context, popup_data, Toast.LENGTH_LONG);
toast.show();
double lng = geop.getLongitude();
double lat = geop.getLatitude();
symbolLayerIconFeatureList.add(Feature.fromGeometry(
Point.fromLngLat(lng, lat)));
break;
case MODIFIED:
break;
case REMOVED:
break;
}
}
}
});
// [END listen_document]
}
When you add a listener to a query (or a collection reference, which is just a query for all documents in the collection), it will read all of the documents and deliver them all to your listener for the first invocation. There is no way to add a listener for only new and changed documents after some point in time.
If you want only new changes, you should add some sort of timestamp field that gets updates with each change, and filter your query using that timestamp, so that only newly modified documents will be delivered to the listener. For example:
myDatabase
.collection("markery")
.whereGreaterThan("timestamp", new Date())
.addSnapshotListener(...)
It will be up to you to make sure that timestamp is updated to the current time along with every update to every document in that collection.
I want something like
objectid id name lastname pic
hx5w887 1 name1 lastname1 pic1
lops4wus 2 name2 lastname2 pic2
zh7w8sa 3 name3 lastname3 pic3
I don't want to change the objectId, just I want that field and every time I save an object increment in 1. I am searched a lot in google, about this, it is no possible at least you can something with Cloud Parse code, but I do not know how to make this function, I don't know if "Increment" can help me with this, and I do not know how to run the function anyway.
Parse.Cloud.afterSave("counter", function(request) {
var nameId = request.object.get("name").id;
var Name = Parse.Object.extend("Name");
var query = new Parse.Query(Name);
query.get(nameId).then(function(post) {
post.increment("idkey",+1);
post.save();
}, function(error) {
throw "Got an error " + error.code + " : " + error.message;
});
});
I deploy and
call the function in Android
ParseCloud.callFunctionInBackground("counter", new HashMap<String, Object>(), new FunctionCallback<String>() {
// #Override
public void done(String result, ParseException e) {
if (e == null) {
} else {
// handleError();
}
}
});
But nothing happens, what can be the problem? Sorry my bad english.
You can use ParseCloud 'beforeSave' functionality.
You can declare a code which will run before saving a new object of a specific class.
In this code you query for your class items, order it and get the first item (the highest value) then you can the next value (highest +1) to the new saved object.
For more info you can take a look at Parse documentation and in this thread (it is not in java but it is very similar)
EDIT: Since Parse is not longer is now an open source might be that things have changed.
can please anyone help me with the following:
the following method retrieve data from an online database and i am able to display it but the problem is it takes too long about 1 Minute to display because the application searches through the database to display the latest result from database. can anyone please help me with the application to just go straight to the last rows of the table? so that the application can take few seconds to display data and also be able to refresh every 10 seconds.
here is the method:
private class GetAllProductsTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
myJavaClient = new Client.Builder(appKey, mastersecret,getApplicationContext()).build();
myJavaClient.enableDebugLogging();
myJavaClient.ping(new KinveyPingCallback() {
#Override
public void onSuccess(Boolean arg0) {
System.out.print("Success");
}
#Override
public void onFailure(Throwable arg0) {
System.out.println("Failure");
}
});
try {
myJavaClient.user().loginBlocking(appKey, mastersecret).execute();
System.out.println("Client login -> "+ myJavaClient.user().isUserLoggedIn());
} catch (IOException e) {
System.out.println("Couldn't login -> " + e);
e.printStackTrace();
}
// Ignore for now
myJavaClient.appData("tdSensorData", Sensor.class).get(new KinveyListCallback<Sensor>() {
#Override
public void onSuccess(Sensor[] result) {
Toast.makeText(MainActivity.this,"Get All Worked!\n Got: " + result.length,Toast.LENGTH_LONG).show();
for(Sensor eventID : result)
{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String currentDateandTime = sdf.format(new Date());
String currentDate = currentDateandTime.substring(0,10);
String times = eventID.getDatetime();
String tim1 = times.substring(0,10);
if (currentDate .compareTo(tim1)==0){
String sens1 = eventID.getSensorr1().toString();
Senso1.setText(sens1);
String sens2 = eventID.getSensorr2().toString();
Senso2.setText(sens2);
String sens3 = eventID.getSensorr3().toString();
Senso3.setText(sens3);
String tmp = eventID.getTemp();
temper.setText(tmp+ " " + "°C");
String dat = eventID.getDatetime();
Device1.setText(dat);
}
}
}
#Override
public void onFailure(Throwable error) {
Toast.makeText(MainActivity.this,
"Get All error: " + error.getMessage(),
Toast.LENGTH_LONG).show();
}
});
return null;
}
}
}
You can put one more boolean column called "fetched data" instead of datatime of creation or update. When it is inserted very first time, you can put the "fetched data" value to false and when it is fetched by the client, you can change it to "true" means it is already fetched. You can fetch the data based on this column value like "fetched data=false" in your query.
You can implement GCM, whenever fresh data will be available to the server it will send it to the client automatically. Hope it will help you.
` Main_Table
Id(primary key) Name Age
1 Balvier 28
2 Kagis 23
User_Table_9920018278
Id(Primary key of Main_Table as Foreign Key)
1
User_Table_9768466084
Id(Primary key of Main_Table as Foreign Key)
1
2 `
GCM is more efficient way to do it, as i said whenever new data will be available to the server, server informs to client automatically. And I tell you steps to fetch data efficiently:
Get the unique id from the client like his phone number and create a table namely that unique number so that every user has separate unique table which has only one column which contains
a. the primary key of main data table as a foreign key
Whenever you insert new data to the main_table, create another entry in the user table also by passing the newly created row's primary key as foreign key.
GCM informs user to download the newly created data to download, or if the data is smaller upto 4kb, you can send the data with gcm notification itself. No need to implement step 2,4,5,6.
On recieve of the notification you check only the user table, is there any row in the user_table.
if yes, then get foreign key of that newly inserted data from user_table and get the whole newly inserted data from the Main_table based on the primary key you get from user table as foreign key.
delete the row from the user_table as you already fetched it.
I have an SQLite query in my android app that seems to crash when it takes too long to execute. It crashes with NullPointerException and tells me the line number...
When I put breakpoints around that line and see that it always gets filled with a variable, the app does not crash and does what it is supposed to.
So aside from having a phantom null pointer, it appears the problem is that the breakpoints actually slow things down giving the query time to complete. Without breakpoints it always crashes without fail.
Others here seem to have a similar problem, and I've read some things about SQLite taking an erratic amount of time to complete tasks, but this table should only ever have a few entries in it (the one I'm testing should only have three entries, 4 columns)
Suggestions on how to make it not crash? Perhaps put a thread wait inside the method that makes the query?
public void fetchItemsToRemove() throws SQLException{
Cursor mCursor =
mapDb.query(myMain_TABLE, new String[] {myOtherId, myCustomID, myDATE}, null, null, null, null, null);
if(mCursor.moveToFirst())
{
do
{
/*taking "dates" that were stored as plain text strings, and converting them to
*Date objects in a particular format for comparison*/
String DateCompareOld = mCursor.getString(mCursor.getColumnIndex(myDATE));
String DateCompareCurrent = "";
Date newDate = new Date();
DateCompareCurrent = newDate.toString();
try {
DateCompareOld = (String)DateCompareOld.subSequence(0, 10);
DateCompareCurrent = (String)DateCompareCurrent.subSequence(0, 10);
SimpleDateFormat dateType = new SimpleDateFormat("EEE MMM dd");
Date convertDate = dateType.parse(DateCompareOld);
newDate = dateType.parse(DateCompareCurrent);
if(convertDate.compareTo(newDate) < 0)
{
//remove unlim id
mapDb.delete(myMain_TABLE, myDATE + "=" + mCursor.getString(mCursor.getColumnIndex(myDATE)), null);
}
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}while(mCursor.moveToNext());
mCursor.close();
}
else
{
mCursor.close();
}
}
Now "line 342" where it crashes with NullPointerException is DateCompareOld = (String)DateCompareOld.subSequence(0, 10); where it gets a subsequence of the string. If it gets here and is null, this means the string was never filled at String DateCompareOld = mCursor.getString(mCursor.getColumnIndex(myDATE));
as if the query just got skipped because it took too long. Do note this is in a while loop, and I have done tests to make sure that the mCursor never goes out of bounds.
You're deleting things from a DB table whilst iterating over the results of a query from that table. Sounds a bit dangerous.
Try building a list, inside the loop, of things to be deleted, and then delete them in a single go after the loop finishes.
Also, wrap the entire thing in a DB transaction. When you're modifying the DB in a loop, that can make a huge difference to performance.
EDIT: a quick explanation of transactions:
A transaction allows you to combine a bunch of DB queries/modifications into a single atomic operation which either succeeds or fails. It's primarily a safety mechanism so your DB isn't stuck in an inconsistent state if something goes wrong half way through, but it also means that any modifications are committed to the DB's file storage in a single shot rather than one at a time, which is much faster.
You start the transaction at the start of your function:
public void fetchItemsToRemove() throws SQLException{
db.beginTransaction();
Cursor mCursor = ....
You set it as successful if the whole function completes without errors. This probably means you want to remove the inner try/catch and have an outer try/catch enclosing the loop. Then at the end of the try{ }, you can assume nothing's gone wrong, so you call:
db.setTransactionSuccessful();
Then, in a finally clause, to make sure you always close the transaction whether it's successful or otherwise:
db.endTransaction();
I have one problem with my application.
I create a one AsyncTask for downloading list of files from server . When all the files are download after that i update the database. But when i called the update query its give me the below error.
Failure 21 (out of memory) on 0x0 when
preparing update
Can any one tell me why this error occurs ?
Sample Code
public void setStatus(int index)
{
try
{
db.OpenDatabase();
db.updateStatus(id.get(index), 1);
db.closeDatabase();
}
catch(Exception e)
{
e.printStackTrace();
}
}
Above function called from the AsyncTask ....
public void updateStatus(int id,int status)
{
try
{
db.execSQL("update sample set status =" + status + " where id = " + id);
}
catch(Exception e){e.printStackTrace();}
}
This may not be related to the database pe se, but rather to the fact that the memory (heap) is almost full and opening the database completely fills it up.
Remember that most handsets have 48MB of heap or even less.
Sometime while working I also got the same error.
I used this link
"Failure 21 (out of memory)" when performing some SQLite operations
It said that this error occurs when you try to work on a closed DB.
I looked back into my code and found that I was also doing the same. Got it working afterwards
I think you are also trying to work on a closed DB.
Have you tried to use the update() method instead of execSQL()?
public void updateStatus(int id,int status)
{
try
{
ContentValues values = new ContentValues();
values.put("status", status);
db.update ("sample", values, "id = ?", new String[]{Integer.toString(id)});
}
catch(Exception e){e.printStackTrace();}
}
I has "out of memory" error (21) when I try to call sqlite3_prepare() with a NULL pointer to database handle.
Check if your handle is valid and the database is opened.