I've the following code :
(basically it creates various JSONObjects (beneficiario) and put them all inside another JSONObject (proposta). I don't show it here but I've Cursors (ppt, c) created before
if (ppt.getString(45).equals("0")) {
int i = 0;
c.moveToFirst();
JSONObject ben = new JSONObject();
try {
while (c.isAfterLast() == false)
{
i++;
ben.put("b_nome" + i, c.getString(1));
ben.put("b_telefone" + i, c.getString(2));
ben.put("b_nif" + i, c.getString(3));
ben.put("b_bi" + i, c.getString(4));
ben.put("b_codigopostal" + i, c.getString(5));
ben.put("b_localidade" + i, c.getString(6));
ben.put("b_morada" + i, c.getString(7));
}
} catch (JSONException e) {
e.printStackTrace();
}
proposta.put("beneficiario" + i, ben);
}
And it gives a outofmemory error, I guess that's because I'm running it on main thread.
Can you give me an help/some code to use a thread or asynctask to do it?
use c.moveToNext(); in your While loop. Your Cursor is running Infinite.
Use async task something like this :
// You must provide types for the three generic parameters before the code will compile.
// For more details, see http://developer.android.com/reference/android/os/AsyncTask.html
private class MoveOutOfUIthread extends AsyncTask<
Params, // one or more values of this type are passed to doInBackground()
Progress, // the type of the progress units published during background crunching.
Result // the type of the result returned by doInBackground()
>
{
protected Integer doInBackground(Params... p1, p2, p3) {
// your background task here
Result result = new Result();
return result;
}
protected void onPostExecute(Result r) {
// this gets the object returned by doInBackground, and executes on the UI thread
}
}
*Execute async task like this : *
new MoveOutOfUIthread().execute(p1, p2, p3);
its not intercessory to pass parameters you can simply do this :
new MoveOutOfUIthread().execute();
NOTE : You cannot change UI elements in doInBackground. You have to put the code in onPreExecute or onPostExecute which change the UI.
UPDATE :
This is to run your code in background thread. And as per your OutOfMemory error I think you should use c.moveToNext(); in your while loop as M Mohsin Naeem answered.
Related
Hi I have been quite struggling with this for a while. Any help is appreciated.
I have a requirement to run one observable after completion of another observable. So e.g. The following code creates an observable from input value to value + 10.
Observable<ColoredIntegerModel> getSequenceObservable(int value, int delay, int color) {
return Observable.range(value,10)
.map(i -> {
Log.d(TAG, "Value " + i
+ " evaluating on " + Thread.currentThread().getName()
+ " emitting item at " + System.currentTimeMillis());
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
}
return new ColoredIntegerModel(i, color);
});
}
The ColorIntegerModel is as follows
public class ColoredIntegerModel {
private Integer mValue;
private int mColor;
public ColoredIntegerModel(Integer value, int color) {
mValue = value;
mColor = color;
}
public Integer getValue() {
return mValue;
}
public int getColor() {
return mColor;
}
}
I create the two observables as follows and concat them like so .
Observable<ColoredIntegerModel> observable1 = getSequenceObservable(1, 1000, Color.BLUE);
Observable<ColoredIntegerModel> observable11 = getSequenceObservable(11, 1000, Color.RED);
mDisposable =
observable1.concatWith(observable11)
.doOnDispose(() -> {Log.d(TAG, "observable disposed");})
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.repeat(2)
.subscribe((m) -> {
Utils.appendColoredText(mResultTextView, "Adding item "
+ m.getValue().toString() + "\n", m.getColor());
});
The above code prints 1..10 (in blue each item delayed by 1s) and 11..20 (in red).
So far so good.
But my requirement is to create the second observable only after the first is complete. Infact it could be array of observables, where the n+1 observable is only created after the nth is done. Each observable can emit multiple items. Is there any operator to achieve this?
I don't know if I understood it right but if you want to create the Observable when you subscribe to it you need the defer operator
You can start next observable from doOnCompleted() of previous one
Observable<MyData> observable1 = ...;
Observable<MyData> observable2 = ...;
Observable<MyData> observable3 = ...;
Observable
.concat(observable1.doOnCompleted(this::onCompleteObservable1),
observable2.doOnCompleted(this::onCompleteObservable2),
observable3.doOnCompleted(this::onCompleteObservable3))
...
...
Hope this help.
I created a database with a table named flagTable, this table only has two fields, which are id(auto increment) and an integer field. Next, in my program, I have a button that will trigger a thread to start. When the thread is starting, it constantly retrieve data from database, and check for the for the value, if the value is equal to one then it will trigger another new Thread, something like this:
private class statusOfStrummingInAnotherDevice extends Thread {
int value;
public void run() {
try{
while(true){
try{
if(flagCursor == null){
flagCursor = cdb1.getFlagAll();
}
}catch(Exception e){break;}
try{
Log.i("MAIN3ACTIVITY","getting status");
int size = cdb1.getSize(flagCursor);
Log.i("MAIN3ACTIVITY","SIZE is" + String.valueOf(xyz));
for(int i = 0 ; i < size ; i++){
flagCursor.moveToPosition(i);
Log.i("MAIN3ACTIVITY","getting status jkasdfasdf");
value = cdb1.getFlag();
if(value == 1){
Log.i("FLAGCURSOR=====>>>>","Succesful");
releasingNotes = new ReleasingNotes(IntendedChord);
releasingNotes.start();
//break;
}
cdb1.updateFlag(0);
Log.i("FLAGCURSOR=====>>>>",String.valueOf(value));
}
flagCursor = null;
}catch(Exception e){break;}
Log.i("MAIN3ACTIVITY","thread is sleeping");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
break;
}
}
}catch(Exception e){
}
}
}
In the meantime, the data that were retrieved from the database is using this function:
public Cursor getFlagAll(){
return getReadableDatabase().rawQuery(
"SELECT _ID, flag from flagTable", null);
}
And, the data that were updated to the database through this method:
public int updateFlag(int i) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("flag",i);
return db.update("flagTable" , contentValues , "_ID" + "= ?",new String[]{String.valueOf(1)});
}
Now, above codes will give no error, however, the data that were retrieved from the database is always 1, it keeps trigger a new function. In my above codes, I stated if the value is equal to 1, then the current thread will trigger a new thread to start, When its finished, the program will update the current data to 0. So that, the next round of the infinite loop can stop triggering new thread until a the conditon is met. What is problem overhere? did my codes really updated the new value? or I need to referesh the database every time I updated a new value.
Use Listeners to your database.
use SQLiteTransactionListener and do your things in onCommit()
Some guide in details here :
https://developer.android.com/reference/android/database/sqlite/SQLiteTransactionListener.html and
http://www.programcreek.com/java-api-examples/index.php?api=android.database.sqlite.SQLiteTransactionListener
I want to fill an ArrayList with the results I get back from a Parse query. When I get the results I add them to the ArrayList and print the ArrayList size to the console to make sure the results are added, which is succesful, but when I return the ArrayList it's empty. Can anyone explain to me why this happens?
public ArrayList<ParseObject>findAllGroupByUserId(ParseUser userId){
//TODO hier uit db halen alle groupen van user
final ArrayList<ParseObject> groups = new ArrayList<>();
ParseQuery<Group_user> query = ParseQuery.getQuery("Group_user");
query.whereEqualTo("user_id", userId);
query.findInBackground(new FindCallback<Group_user>() {
#Override
public void done(List<Group_user> objects, ParseException e) {
if (e == null) {
for (Group_user group : objects) {
Log.e("SUCCESS", group.getObjectId() + " , " + group.getGroup_id().getObjectId());
ParseObject g = new Group();
groups.add(g);
}
System.out.println(groups.size() + " :Done method"); //THIS RETURNS 2
} else {
Log.e("ERROR", "message: " + e);
}
Log.e("SUCCESS", "we have " + groups.size() + " results");
}
});
System.out.println(groups.size() + " :return"); // THIS RETURNS 0
return groups;
}
Because findInBackground() runs asynchronously on a different thread. You need to execute your remaining logic from the done() call back to get the populated array.
Think of it like this:
Thread 1 -> invokes findInBackground() -> thread one is running -----------> group is empty until Thread 2 finishes
Thread 2 spawned -> reaches out to server and gets query results -> invokes done call back on Thread 1 (now you have the data ready)
So I'm assuming that Group_user is a subclass of ParseObject that you've already defined. Since the findInBackground is async, you should change logic of the calling of the function to async too. Instead of returning list of objects like you were before, do all the logic in the done function of the query, no need to return.
public void findAllGroupByUserId(ParseUser userId) {
ParseQuery<Group_user> query = ParseQuery.getQuery("Group_user");
query.whereEqualTo("user_id", userId);
query.findInBackground(new FindCallback<Group_user>() {
#Override
public void done(List<Group_user> groups, ParseException e) {
if (e == null && groups != null) {
for (Group_user group : groups) {
// perform all logic here
}
} else {
Log.e("Find Callback", "Oh no! Query failed!");
}
}
});
}
My AsyncTask class do not work inside for loop. Below is my code please review it.
for (int i = 0; i < size; i++) {
String id = careplan_disease_Parser.DiseaseID.get(i);
String method = "GetCarePlan_Comment?CurrentValue=0&OptionId=" + id + "&DiseaseID=" + id + "&OrgId=" + orgId + "";
String link = "GetCarePlan_Comment_dislink";
task = new AsyncTask123();
task.execute(link, method);
method=null;
link=null;
task=null;
}
Task executes only once. so i can't get value from web service second time in a loop.
Please help me how to make it work.
Thanks
You can write a start-method, that gets called in the onPostExecute-part of you AsyncTask. It should look like this:
private void start(int number)
{
if(number == size)
{
//exit
}
else
{
new AsyncTask123().execute(link, method);
}
}
private class AsyncTask123 extends AsyncTask<> {
protected void onPostExecute() {
start(i++);
}
}
This should work, you just have to fit it for your needs.
if you want AsyncTask in for loop then you should call your class like:
new AsyncTask123().execute(link, method);
Not like :
task = new AsyncTask123();
task.execute(link, method);
I have list of files stored inside arraylist that I need to download in background thread. My initial thought is that AsyncTask should be up for that task. But, I have a problem, I don't know how to supply my list to doInBackground method.
My arraylist is defined as
private ArrayList<String> FilesToDownload = new ArrayList<String>();
My DownloadFiles subclass (the way it is written now) should be called with:
new DownloadFiles().execute(url1, url2, url3, etc.);
This is not suitable for me since I never know how many urls I will have. It is pretty much changing from case to case. So, I would like somehow to pass my arraylist to doInBackground method.
I tried to convert to array with toArray():
new DownloadFiles().execute(FilesToDownload.toArray());
But, eclipse tells me that execute is not applicable for argument Object[].
Suggestion was to cast to URL[], but when I tried that I got illegal casting error and app crashed.
It seems that doInBackground has to be implemented with parameters in varargs type (URL... urls).
Any ideas how to solve my problem? Thanks.
class DownloadFiles extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
Log.d("Evento", "&&&& downloading: " + FilesToDownload.get(i).toString());
// totalSize += Downloader.downloadFile(urls[i]);
// publishProgress((int) ((i / (float) count) * 100));
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
//setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
//showDialog("Downloaded " + result + " bytes");
}
}
Your AsyncTask is declared with a param type of URL, but you're trying to pass String (or ArrayList) objects. Either prepare an Array of URL objects in the calling program or modify DownloadFiles to accept String instead of URL parameters and convert each String to a URL in the execute() method.
Better yet, since you are accessing FilesToDownload from within execute(), you don't need to pass anything to execute() and you could declare the first generic parameter of DownloadFiles as Void.