when my Async task is executed it completely crashes the app
Here is the code to the class. It sits inside of my main activity class.
I'm new to threading, so sorry if I've done something ridiculous lol, I don't fully understand it.
EDIT:
private class TeamSearchTask extends AsyncTask<String,Void,Void> {
CharSequence nfo;
String [] matches;
protected Void doInBackground(String... teamNumber)
{
//Team information ------------------------------------------------------------------------------------
//Array of team data
String [] data = APIconnection.getTeams(teamNumber[0], "");
//Display basic team info
nfo = ("\nFormal Team Name:\n" + data[1] +
"\n\nLocation:\n" + data [3] + ", " + data[4] + ", " + data[5] +
"\n\nRookie Year:\n" + data[6] +
"\n\nRobot Name:\n" + data[7] +
"\n\nWebsite:\n" + data[8] + "\n\n\n\n\n\n\n\n\n");
//Make match archive --------------------------------------------------------------------------------------
String [] events = APIconnection.getEventIdsByYear(year1);
String [] matches = new String [(events.length*11)];;
for (int i = 0; i<events.length; i++)
{
matches[(i*11) + i] = APIconnection.getMatches2(teamNumber[0], events[i] ,"","")[i];
}
return null;
}
protected void onProgressUpdate(Void...voids )
{}
protected void onPostExecute(Void result) {
info.setText(nfo);
matchArchive(matches);
}
}
titlets.setText(ttl.toString());
Don't touch UI elements in different thread then UI-thread. You can use Activity::runInUiThread(Runnable r) or Handler::post(Runnable r). In second case, handler should be paired with UI-thread.
private class TeamSearchTask extends AsyncTask<String,Void,Void> {
private String[] data;
protected Void doInBackground(String... teamNumber) {
// Do your background work! No UI-stuff here!!
data = APIconnection.getTeams(teamNumber[0], "");
return null;
}
protected void onPostExecute(Void result) {
// Do all UI related stuff here, it's executed when the doInBackground is finished
}
}
edit: My bad, fixed the error with onPostExecute. You need to use Void instead of Long as you use
extends AsyncTask<String,Void,Void>
which means input parameter is String, Progress parameter type (in onProgressUpdate) and the 3rd one is for the Result.
Related
I have a query running to collect a youtube id from a database. The AsyncTask works and I get the piece of information but I can't pass it from onPostExecute to onCreate.
Here is what I have tried doing.
Make youtubeIdCode a global variable.
Run the query to get the id from the database.
Return the youtubeid in doInBackground.
Set youtubeIdCode = the result of doInBackground in onPostExecute.
Try calling the youtubeIdCode in onCreate to see if the result from onPostExecute passed to youtubeIdCode. This is where I have the issue. It is not passing from onPostExecute to onCreate. How can I pass it because in onCreate is where I will be needing the id to form a youtube url.
//Activity needs added to manifest.
public class DetailsActivity extends AppCompatActivity {
//LOG tag for debugging
private static final String TAG = "GalleryActivity";
String youtubeIdCode;
//Override on Create and set contentView to new activity_details layout.
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_details);
//Log for debugging so we can tell if activity started successfully.
Log.d(TAG, "onCreate: started.");
youtubeIdCode = "";
loadMovieData();
String test = "The value is" + youtubeIdCode;
Log.v("youtube code test", test);
Intent intent = getIntent();
Movie movie = intent.getParcelableExtra("movie");
String image = movie.getMoviePoster();
String title = movie.getTitle();
String releaseDate = movie.getDate();
String voteAverage = movie.getVoteAverage();
String plot = movie.getPlot();
ImageView poster = findViewById(R.id.details_image);
Picasso.with(this).load(image).into(poster);
TextView name = findViewById(R.id.details_title);
name.setText((getResources().getString(R.string.movie_title)) + " " + title);
TextView dateRelease = findViewById(R.id.details_release_date);
dateRelease.setText((getResources().getString(R.string.release_date)) + " " + releaseDate);
TextView averageVote = findViewById(R.id.details_voter_average);
averageVote.setText((getResources().getString(R.string.vote_average)) + " " + voteAverage);
TextView moviePlot = findViewById(R.id.details_plot);
moviePlot.setText((getResources().getString(R.string.plot)) + " " + plot);
}
public class FetchTrailer extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... strings) {
final String YOUTUBE_ID = "id";
final String RESULTS = "results";
String youtubeId = " ";
Intent intent = getIntent();
Movie movie = intent.getParcelableExtra("movie");
String id = movie.getID();
final URL trailerUrl = NetworkUtils.buildUrlTrailer(id);
Log.v("Built trailer url", trailerUrl.toString());
try {
String jsonResponse = NetworkUtils.getReponseFromHttpUrl(trailerUrl);
JSONObject moviesObject = new JSONObject(jsonResponse);
JSONArray resultsArray = moviesObject.getJSONArray(RESULTS);
for(int i = 0; i < resultsArray.length(); i ++){
JSONObject movieObject = resultsArray.getJSONObject(i);
youtubeId = movieObject.getString(YOUTUBE_ID);
Log.v("youtubeid", youtubeId);
}
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return youtubeId;
}
#Override
protected void onPostExecute(String s) {
youtubeIdCode = s;
Log.v("onposttest", s);
}
}
//Tell the new method to get the data based on the search term within the url.
private void loadMovieData() {
//If there is a network connection, fetch the data.
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null &&
activeNetwork.isConnectedOrConnecting();
if (isConnected) {
new FetchTrailer().execute();
} else {
Toast toast = Toast.makeText(this, getString(R.string.no_internet_toast), Toast.LENGTH_LONG);
toast.show();
}
}
}
I think you need to rethink the logic of the app. The main idea of using an AsyncTask is that the main thread would not block while the task is running.
This means onCreate() shouldn't wait for the AsyncTask to finish to continue it's execution, which is what you are implying that should happen.
The way to think your app, is that the URL setup you want to do with the youtube id, and any aditional processing should be trigged by onPostExecute() when the task is finished.
At a time of call asynTask you can do like that, may be it work i am not confident.
new FetchTrailer(){
#Override
protected void onPostExecute(Object o) {
super.onPostExecute(o);
}
}.execute()
Just do a setter of the var you need to put te value, then onPostExecute just call that setter function and pass the value of the var in the AsyncTask, and after that use a method to fetch the text on your widgets, if you do it before you pass the value it will be null.
Also try to do AsyncTask in a separate class
AsyncTask OnPostExecute
#Override
protected void onPostExecute(List<ListaLineal> superlistItems) {
super.onPostExecute(superlistItems);
activity.setSuperListItems(superlistItems); -> this retrieve the value of a list that I was using (I got the value of the list in doInBackground)
activity.setupData(); -> method for setting up data
}
In your case setupData will look similar to this
public void setupData(){
String image = movie.getMoviePoster();
String title = movie.getTitle();
String releaseDate = movie.getDate();
String voteAverage = movie.getVoteAverage();
String plot = movie.getPlot();
ImageView poster = findViewById(R.id.details_image);
Picasso.with(this).load(image).into(poster);
TextView name = findViewById(R.id.details_title);
name.setText((getResources().getString(R.string.movie_title)) + " " + title);
TextView dateRelease = findViewById(R.id.details_release_date);
dateRelease.setText((getResources().getString(R.string.release_date)) + " " + releaseDate);
TextView averageVote = findViewById(R.id.details_voter_average);
averageVote.setText((getResources().getString(R.string.vote_average)) + " " + voteAverage);
TextView moviePlot = findViewById(R.id.details_plot);
moviePlot.setText((getResources().getString(R.string.plot)) + " " + plot);
}
I have a Activity that contains over 100 complex views (with images, text views etc). Showing up these views is to hard to do it without a Thread that loads the views asynchronously. So I tried to do it with an AsyncTask. I am not sure whether this is the correct way because the "hard staff" is something that HAS to be done in the UI Thread.
Now I've got the problem that the UI freezes though I used the onProgressUpdate for adding the views in the to parent view. I thought that this would result in single loading views that appear successive in the parent view. But this is not the case.
doInBackground fires all publishProgress calls and after that the main thread is blocked (activity frozen, loadbar does not rotate anymore). Is there a way to achieve what I wanted to have? I looked for solutions but alway ended up with ideas of using AsyncTask and no one had to do view-stuff as "hard staff". I am not using "get" in the AsyncTask what seems to be a problem with AsyncTask.
Here is my code for this. If you need any further information please tell me!
Is there any other way to solute this problem? Is my AsyncTask implementation not correct? I am looking for a way to load these complex views asyncronous to the parent view without blocking the main thread.
Thanks in advance!
public class LoadKraut extends AsyncTask<Integer,Kraut,Void> {
private Context context;
private LinearLayout parent;
private HashMap<String,HeadlineAlphabet> headlinesAlphabet = new HashMap<String, HeadlineAlphabet>();
private long time;
private Integer kategorie;
private char letter = 'X';
private int counter = 0;
private ProgressDialog dialog;
public LoadKraut(Context context) {
/**
* Kategorie:
* 1 - A-Z
* 2 - Notiz
* 3 - Favorit
* 4 - Giftig
*/
Log.i("Kraut", "Start thread" + (System.currentTimeMillis()-time) + "ms");
this.context = context;
this.dialog = new ProgressDialog(context);
this.time = System.currentTimeMillis();
}
#Override
protected void onPreExecute() {
dialog.setMessage("Lade Kräuter. Dieser Vorgang kann einen Moment dauern.");
dialog.show();
}
#Override
protected Void doInBackground(Integer... params) {
this.kategorie = params[0];
//Create overview
try {
DatabaseHelper databaseHelper = new DatabaseHelper(context);
Dao<Kraut,Integer> dao = databaseHelper.getKrautDAO();
parent = (LinearLayout) ((Activity) context).findViewById(R.id.ll_conainter_sv_uebersicht_kraeuter);
//setKraeuter(list, linearLayout, giftig)
long test = System.currentTimeMillis();
List<Kraut> list = new ArrayList<>();
switch (kategorie) {
case 1:
list = dao.queryForAll();
break;
case 2:
list = dao.queryBuilder().where().ne("notiz","").query();
break;
case 3:
list = dao.queryBuilder().where().eq("favorit",true).query();
break;
case 4:
list = dao.queryBuilder().where().eq("toedlichBunny",true).query();
break;
}
Log.i("Kraut","Fetching duration: " + String.valueOf(System.currentTimeMillis() - test));
Iterator<Kraut> iterator = list.iterator();
while(iterator.hasNext()) {
Kraut kraut = iterator.next();
Log.i("Kraut","called pp for" + kraut.getName());
publishProgress(kraut);
}
} catch (SQLException e) {
e.printStackTrace();
}
Log.i("Kraut", "End " + (System.currentTimeMillis()-time) + "ms");
return null;
}
#Override
protected void onProgressUpdate(Kraut... value) {
//Set all Krauts and headlines A-Z
long test = System.currentTimeMillis();
Kraut kraut = value[0];
Log.i("Kraut", String.valueOf(counter));
if((kategorie==1 || kategorie==4) && kraut.getName().charAt(0)!=letter) {
letter = kraut.getName().charAt(0);
HeadlineAlphabet letterHeadline = new HeadlineAlphabet(context);
letterHeadline.setText(String.valueOf(kraut.getName().charAt(0)));
headlinesAlphabet.put(String.valueOf(letterHeadline.getText()),letterHeadline);
parent.addView(letterHeadline);
}
KrautView krautView=null;
if(kategorie==1 || kategorie==3) {
krautView = new KrautUebersicht(context,kategorie);
} else if(kategorie==2) {
krautView = new KrautUebersichtNotiz(context);
}
if(krautView!=null) {
krautView.setKraut(kraut);
parent.addView((LinearLayout) krautView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
}
parent.getRootView().invalidate();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
counter++;
Log.i("Kraut","Kraut View creation duration: " + String.valueOf(System.currentTimeMillis() - test));
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
if(kategorie==1) {
//Set Alphabet Column right side
ArrayList<String> anfangsbuchstaben = Kraut.getAnfangsbuchstaben(context);
// Do this with an xml !
for (int i = 1; i <= 26; i++) {
//Log.i("Kraut", String.valueOf(i));
String currentLetter = Helper.getCharForNumber(i);
int id = context.getResources().getIdentifier("tv_"+currentLetter.toLowerCase(),"id",context.getPackageName());
TextView textView = (TextView) ((Activity) context).findViewById(id);
//If no Kraut contains Letter
if (!anfangsbuchstaben.contains(currentLetter)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
textView.setTextColor(context.getResources().getColor(R.color.darkgrey, context.getTheme()));
} else {
textView.setTextColor(context.getResources().getColor(R.color.darkgrey));
}
//Make clickable to jump to A-Z Headlines
} else {
textView.setOnClickListener(new JumpToLetterOnClickListener(headlinesAlphabet));
}
}
}
parent.invalidate();
if(dialog.isShowing()) {
dialog.dismiss();
}
}
}
Note that onProgressView() is called repeatedly as your AsyncTask runs. Therefore, it should be kept as short as possible. This also means that your current code is creating lots of views and adding them to the UI. Instead, you should add the view just once and then update its data in onProgressView().
Also, as Mike M. states in the comments, you should not call Thread.sleep() in onProgressView() since it runs on the UI thread. This is most likely the main reason your app is freezing.
I am trying to populate recyclerview from an async task. and in Async task the data is fetched through API call and pushed to a SQLite table, then the list populates from the SQLite Table. The list fails to display on first load. But when I close the app and reopen the app, the list populates. Is this a general issue that need to be addressed properly or I am missing with something else?
public class KingsActivity extends AppCompatActivity {
RecyclerView mRecyclerView;
RecyclerView.Adapter mAdapter;
RecyclerView.LayoutManager mLayoutManager;
List<King> kingList=new ArrayList<King>();
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.d("method_track","onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//To avoid the load on the main thread
new DownloadDataAsync().execute(this);
}
public class DownloadDataAsync extends AsyncTask<Context, Integer, Context> {
#Override
protected Context doInBackground(Context... ctx) {
downloadData(ctx[0]);
return ctx[0];
}
#Override
protected void onProgressUpdate(Integer... progress) {
}
#Override
protected void onPostExecute(Context result) {
Log.d("method_track","PostExecute");
Cursor kingsRows=DatabaseHelper.getInstance(result.getApplicationContext()).getData(DatabaseHelper.TABLE_WESTEROS_KINGS);
kingsRows.moveToFirst();
while(kingsRows.moveToNext()){
String kingName=kingsRows.getString(kingsRows.getColumnIndex(DatabaseHelper.KEY_WESTEROS_KINGS_NAME));
int battleCount=kingsRows.getInt(kingsRows.getColumnIndex(DatabaseHelper.KEY_WESTEROS_KINGS_BATTLE_COUNT));
int rating=kingsRows.getInt(kingsRows.getColumnIndex(DatabaseHelper.KEY_WESTEROS_KINGS_RATING));
kingList.add(new King(kingName,rating,battleCount));
}
kingsRows.close();
mRecyclerView = (RecyclerView)findViewById(R.id.my_recycler_view);
mLayoutManager = new LinearLayoutManager(result);
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new KingsAdapterRC(kingList,result);
mRecyclerView.setAdapter(mAdapter);
mAdapter.notifyDataSetChanged();
}
public void downloadData(final Context ctx){
// Get a RequestQueue
RequestQueue queue = HttpRequestHandler.getInstance(ctx.getApplicationContext()).
getRequestQueue();
String url ="http://starlord.hackerearth.com/gotjson";
// Request a string response from the provided URL.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
// Display the first 500 characters of the response string.
//Log.d("result_check",response.substring(0,500));
loadToDb(response,ctx);
populateList(ctx);
calculateRating(ctx);
logRatings(ctx);
//mTextView.setText("Response is: "+ response.substring(0,500));
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("result_check","Error");
//mTextView.setText("That didn't work!");
}
});
// Add a request to RequestQueue.
HttpRequestHandler.getInstance(ctx).addToRequestQueue(stringRequest);
}
protected void loadToDb(String jsonResponse,Context ctx){
DatabaseHelper.getInstance(ctx.getApplicationContext()).truncate(DatabaseHelper.TABLE_WESTEROS_DATA);
try {
JSONArray jsonArray = new JSONArray(jsonResponse);
for(int i=0;i<jsonArray.length();i++){
JSONObject jsonObj = (JSONObject)jsonArray.get(i);
Iterator<String> iter = jsonObj.keys();
HashMap<String,String> fieldVales=new HashMap<String, String>();
while (iter.hasNext()) {
String key = iter.next();
try {
Object value = jsonObj.get(key);
fieldVales.put(key,value.toString());
} catch (JSONException e) {
// Something went wrong!
Log.e("loadTodb",e.toString());
}
}
DatabaseHelper.getInstance(ctx.getApplicationContext()).insert(DatabaseHelper.TABLE_WESTEROS_DATA,fieldVales);
}
} catch (Throwable t) {
//Log.e("My App", "Could not parse malformed JSON: \"" + json + "\"");
}
}
protected void populateList(Context ctx){
List<King> kingList=new ArrayList<King>();
String[] kings;
int kingsCount=0;
String sql="SELECT DISTINCT "+DatabaseHelper.KEY_WESTEROS_ATTACKER_KING+ " FROM "+ DatabaseHelper.TABLE_WESTEROS_DATA
+" WHERE "+ DatabaseHelper.KEY_WESTEROS_ATTACKER_KING +" <> ''";
Cursor rows=DatabaseHelper.getInstance(ctx.getApplicationContext()).getReadableDatabase().rawQuery(sql, null);
kingsCount+=rows.getCount();
String sql2="SELECT DISTINCT "+DatabaseHelper.KEY_WESTEROS_DEFENDER_KING + " FROM "+ DatabaseHelper.TABLE_WESTEROS_DATA
+ " WHERE "+ DatabaseHelper.KEY_WESTEROS_DEFENDER_KING + " NOT IN ( "+sql+ " ) AND "
+ DatabaseHelper.KEY_WESTEROS_DEFENDER_KING +" <> ''";
Cursor rows2=DatabaseHelper.getInstance(ctx.getApplicationContext()).getReadableDatabase().rawQuery(sql2, null);
kingsCount+=rows2.getCount();
kings=new String[kingsCount];
int i=0;
if (rows.moveToFirst()) {
while (!rows.isAfterLast()) {
//your code to implement
kings[i]=rows.getString(rows.getColumnIndex(DatabaseHelper.KEY_WESTEROS_ATTACKER_KING));
i++;
rows.moveToNext();
}
}
rows.close();
if (rows2.moveToFirst()) {
while (!rows2.isAfterLast()) {
//your code to implement
kings[i]=rows2.getString(rows2.getColumnIndex(DatabaseHelper.KEY_WESTEROS_DEFENDER_KING));
i++;
rows2.moveToNext();
}
}
rows2.close();
DatabaseHelper.getInstance(ctx.getApplicationContext()).truncate(DatabaseHelper.TABLE_WESTEROS_KINGS);
for(i=0;i<kingsCount;i++){
HashMap<String,String> fieldValues=new HashMap<String, String>();
fieldValues.put(DatabaseHelper.KEY_WESTEROS_KINGS_NAME,kings[i]);
fieldValues.put(DatabaseHelper.KEY_WESTEROS_KINGS_RATING,"400");
fieldValues.put(DatabaseHelper.KEY_WESTEROS_KINGS_BATTLE_COUNT,"0");
DatabaseHelper.getInstance(ctx.getApplicationContext()).insert(DatabaseHelper.TABLE_WESTEROS_KINGS,fieldValues);
}
}
protected void calculateRating(Context ctx){
Cursor battles_cur=DatabaseHelper.getInstance(ctx.getApplicationContext()).getData(DatabaseHelper.TABLE_WESTEROS_DATA);
if(battles_cur.moveToFirst()){
while(!battles_cur.isAfterLast()){
String attackingKing=battles_cur.getString(battles_cur.getColumnIndex(DatabaseHelper.KEY_WESTEROS_ATTACKER_KING));
String defendingKing=battles_cur.getString(battles_cur.getColumnIndex(DatabaseHelper.KEY_WESTEROS_DEFENDER_KING));
if(!attackingKing.equals("") && !defendingKing.equals("")){
HashMap<String,String> whereConDfk=new HashMap<String,String>();
whereConDfk.put(DatabaseHelper.KEY_WESTEROS_KINGS_NAME,defendingKing);
Cursor cursor1=DatabaseHelper.getInstance(ctx.getApplicationContext()).getData(DatabaseHelper.TABLE_WESTEROS_KINGS,whereConDfk);
double defKing_rating;
double defKing_battleCount;
if(cursor1.moveToFirst()){
defKing_rating=cursor1.getDouble(cursor1.getColumnIndex(DatabaseHelper.KEY_WESTEROS_KINGS_RATING));
defKing_battleCount=cursor1.getDouble(cursor1.getColumnIndex(DatabaseHelper.KEY_WESTEROS_KINGS_BATTLE_COUNT));
cursor1.close();
HashMap<String,String> whereConAtk=new HashMap<String,String>();
whereConAtk.put(DatabaseHelper.KEY_WESTEROS_KINGS_NAME,attackingKing);
Cursor cursor2=DatabaseHelper.getInstance(ctx.getApplicationContext()).getData(DatabaseHelper.TABLE_WESTEROS_KINGS,whereConAtk);
Double atkKing_rating;
Double atkKing_battleCount;
if(cursor2.moveToFirst()){
atkKing_rating=cursor2.getDouble(cursor2.getColumnIndex(DatabaseHelper.KEY_WESTEROS_KINGS_RATING));
atkKing_battleCount=cursor2.getDouble(cursor2.getColumnIndex(DatabaseHelper.KEY_WESTEROS_KINGS_BATTLE_COUNT));
cursor2.close();
atkKing_battleCount++;
defKing_battleCount++;
Double defKing_rating_tr=Math.pow(10,(defKing_rating/400));
Double atkKing_rating_tr=Math.pow(10,(atkKing_rating/400));
Double defKing_rating_ex=defKing_rating_tr/(defKing_rating_tr+atkKing_rating_tr);
Double atkKing_rating_ex=atkKing_rating_tr/(defKing_rating_tr+atkKing_rating_tr);
String attackerStatus=battles_cur.getString(battles_cur.getColumnIndex(DatabaseHelper.KEY_WESTEROS_ATTACKER_OUTCOME));
Double atkKing_rating_new=atkKing_rating;
Double defKing_rating_new=defKing_rating;
if(attackerStatus.equals("win")){
atkKing_rating_new=atkKing_rating+(32*(1-atkKing_rating_ex));
defKing_rating_new=defKing_rating+(32*(0-defKing_rating_ex));
}else if(attackerStatus.equals("loss")){
atkKing_rating_new=atkKing_rating+(32*(0-atkKing_rating_ex));
defKing_rating_new=defKing_rating+(32*(1-defKing_rating_ex));
}else if(attackerStatus.equals("draw")){
atkKing_rating_new=atkKing_rating+(32*(0.5-atkKing_rating_ex));
defKing_rating_new=defKing_rating+(32*(0.5-defKing_rating_ex));
}
String update_atkKing_ratingQuery="UPDATE "+ DatabaseHelper.TABLE_WESTEROS_KINGS + " SET "
+ DatabaseHelper.KEY_WESTEROS_KINGS_RATING+" = "+atkKing_rating_new+", "
+ DatabaseHelper.KEY_WESTEROS_KINGS_BATTLE_COUNT+" = "+atkKing_battleCount
+ " WHERE "+ DatabaseHelper.KEY_WESTEROS_KINGS_NAME +" =\""+attackingKing+"\"";
String update_defKing_ratingQuery="UPDATE "+ DatabaseHelper.TABLE_WESTEROS_KINGS + " SET "
+ DatabaseHelper.KEY_WESTEROS_KINGS_RATING+" = "+defKing_rating_new+", "
+ DatabaseHelper.KEY_WESTEROS_KINGS_BATTLE_COUNT+" = "+defKing_battleCount
+ " WHERE "+ DatabaseHelper.KEY_WESTEROS_KINGS_NAME +" =\""+defendingKing+"\"";
DatabaseHelper.getInstance(ctx.getApplicationContext()).getWritableDatabase().execSQL(update_atkKing_ratingQuery);
DatabaseHelper.getInstance(ctx.getApplicationContext()).getWritableDatabase().execSQL(update_defKing_ratingQuery);
}
}
}
battles_cur.moveToNext();
}
}
}
protected void logRatings(Context ctx){
Log.d("method_track","logratings");
Cursor kings_cur=DatabaseHelper.getInstance(ctx.getApplicationContext()).getData(DatabaseHelper.TABLE_WESTEROS_KINGS);
try {
while (kings_cur.moveToNext()) {
String name=kings_cur.getString(kings_cur.getColumnIndex(DatabaseHelper.KEY_WESTEROS_KINGS_NAME));
String rating=kings_cur.getString(kings_cur.getColumnIndex(DatabaseHelper.KEY_WESTEROS_KINGS_RATING));
String battleCount=kings_cur.getString(kings_cur.getColumnIndex(DatabaseHelper.KEY_WESTEROS_KINGS_BATTLE_COUNT));
//Log.d("method_track", "logratings");
Log.d("rating_inspect",name+" - "+rating+" - "+battleCount);
}
}finally {
kings_cur.close();
}
}
}
}
Here:
downloadData(ctx[0]);
Problem caused by downloadData method.
In downloadData method using StringRequestto get data from server. StringRequest process all requests on worker Thread and return result back using Response.Listener.
doInBackground also done all work on worker Thread. so doInBackground method's Work Thread just executing downloadData method without waiting to get response from StringRequest.
No need to use extra Thread when using StringRequest. just remove AsyncTask and use only StringRequest to get it work properly.
Yo should not call volley StringRequest from doInBackground because async task immediately shot the post execute method and your list will be empty so that it won't show any data. Simply use string request and after getting response save it in your 'database' and fetch from there(you can save and fetch the data from database directly or using async task).
For not just use StringRequest without any async task and test it.
I am relatively new to RxJava/RxAndroid. I have been using AsyncTask to do my long running tasks before now.
I have converted most of my AsyncTask to RxJava but this one.
The particular problem I am having is calling something like AsyncTask's publishProgress(params); in
the background thread. I need to do this to update the progress of a ProgressBar.
First this is the code in AsyncTask
private static class AddBooksToDatabase extends AsyncTask<String, String, String> {
//dependencies removed
AddBooksToDatabase(AddBooksDbParams params) {
//Removed assignment codes
}
#Override
protected String doInBackground(String... strings) {
//Initializing custom SQLiteOpenHelper and SQLite database
File mFile = new File(mFolderPath);
int booksSize = getFilesInFolder(mFile).size();
String[] sizeList = {String.valueOf(booksSize)};
//The first publishProgress is used to set the max of the progressbar
publishProgress(sizeList);
for (int i = 0; i < booksSize; i++) {
//publishProgress with current item, current file
publishProgress(String.valueOf(i), getFilesInFolder(mFile).get(i).getName());
//Inserting current items in database. Code removed
}
return null;
}
#Override
protected void onPreExecute() {
//Show ProgressBar
}
#Override
protected void onPostExecute(String s) {
//Hide ProgressBar
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
if (values.length == 1) {
//The first call to publishProgress
mProgressBar.setMax(Integer.parseInt(values[0]));
} else {
//Subsequent calls to publish progress
Log.i(TAG, "Current item is " + values[0] + " and current file is " + values[1]);
infoText.setText(values[1]);
mProgressBar.setProgress(Integer.parseInt(values[0]), true);
}
}
#Override
protected void onCancelled() {
cancel(true);
}
}
Code Using RxJava
final Observable<String[]> addBooksObserver = Observable.create(new Observable.OnSubscribe<String[]>() {
#Override
public void call(Subscriber<? super String[]> subscriber) {
subscriber.onNext(setAddSubscription());
subscriber.onCompleted();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
private String[] setAddSubscription() {
S//Initializing custom SQLiteOpenHelper and SQLite database
File mFile = new File(mFolderPath);
int booksSize = getFilesInFolder(mFile).size();
String[] sizeList = {String.valueOf(booksSize)};
//The first publishProgress is used to set the max of the progressbar
addBooksObserver.doOnNext(addReturnParams(String.valueOf(sizeList.length), null, null));
for (int i = 0; i < booksSize; i++) {
EpubReader reader = new EpubReader();
//publishProgress with current item, current file*
addBooksObserver.doOnNext(addReturnParams(String.valueOf(sizeList.length),
String.valueOf(i), getFilesInFolder(mFile).get(i).getName()));
//Inserting current item in database. Code removed
}
return null;
}
private String[] addReturnParams(String totalItems, String currentItem, String currentFile) {
return new String[]{totalItems, currentItem, currentFile};
}
The problem is that lines addBooksObserver.doOnNext(addReturnParams( are displaying this error
doOnNext (rx.functions.Action1) cannot be applied to (java.lang.String[])
I don't know have any idea how to fix this because I thought that since setAddSubscription() and addReturnParams(String totalItems, String currentItem, String currentFile) are returning String array then this shouldn't be a problem. Please can you help me out?
you just have to pass the values to the onNext method of your subscriber, not the doOnNext method of your observable!
you also have to subscribe to the service. try something like this for your obserable:
Observable.create(new Observable.OnSubscribe<String[]>() {
#Override
public void call(Subscriber<? super String[]> subscriber) {
setAddSubscription(subscriber);
subscriber.onCompleted();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<String[]>() {
#Override
public void onCompleted() {
// handle 'oparation is done'
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(String[] values) {
if (values.length == 1) {
//The first call to publishProgress
mProgressBar.setMax(Integer.parseInt(values[0]));
} else {
//Subsequent calls to publish progress
Log.i(TAG, "Current item is " + values[0] + " and current file is " + values[1]);
infoText.setText(values[1]);
mProgressBar.setProgress(Integer.parseInt(values[0]), true);
}
}
});
you also need to modify your private methods a little bit:
private void setAddSubscription(Subscriber<? super String[]> subscriber) {
//Initializing custom SQLiteOpenHelper and SQLite database
File mFile = new File(mFolderPath);
int booksSize = getFilesInFolder(mFile).size();
String[] sizeList = {String.valueOf(booksSize)};
//The first publishProgress is used to set the max of the progressbar
subscriber.onNext(addReturnParams(String.valueOf(sizeList.length), null, null));
for (int i = 0; i < booksSize; i++) {
EpubReader reader = new EpubReader();
//publishProgress with current item, current file*
subscriber.onNext(addReturnParams(String.valueOf(sizeList.length),
String.valueOf(i), getFilesInFolder(mFile).get(i).getName()));
//Inserting current item in database. Code removed
}
}
private String[] addReturnParams(String totalItems, String currentItem, String currentFile) {
return new String[]{totalItems, currentItem, currentFile};
}
You can use Subject to call onNext() manually like this:
Subject<Event> event = Subject.create();
Now call the onNext() for sending event like:
event.onNext("event");
Finally you can return Observable by using this code:
event.toFlowable(BackpressureStrategy.LATEST)
.toObservable();
Your Observer should be like Observable.create(new Observable.OnSubscribe<String>() & in your call method you should loop through the StringArray & pass it to onNext for example:
#Override
public void call(Subscriber<? super String> subscriber) {
for(String val : setAddSubscription()) {
subscriber.onNext(val);
}
subscriber.onCompleted();
}
now onNext shall return you individual items & onCompleted will be called upon the loop is finished.
Edit
myObserver.subscribe(new Subscriber<String>() {
#Override
public void onCompleted() {
// handle completion.
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(String value) {
// do whatever with each value passed to onNext
}
});
Observable.create(emitter -> {
for (int i = 0; i < 10; i++) {
int[] ii = {i, i * 2};
emitter.onNext(ii);
}
emitter.onComplete();
}).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()).subscribe(o -> {
// update progress
int[] i = (int[]) o;
Toast.makeText(SearchActivity.this, "oftad " + i[0] + " - " + i[1], Toast.LENGTH_SHORT).show();
}, t -> {
// on error
Toast.makeText(SearchActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
}, () -> {
// progress tamom shod
Toast.makeText(SearchActivity.this, "completed", Toast.LENGTH_SHORT).show();
});
Actually what i am trying to do is that call an asyncTask several times inside a loop. So, first time the asyncTask will start immediately and from second time onwards, it will check whether the AsyncTask has been finished-if finished than again call it with different values.
Below is my code for the activity:
In onCreate()
btnUpload.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
count_response = 0;
newUploadWithSeparate();
}
});
The newUploadWithSeparate() method:
private void newUploadWithSeparate()
{
responseString_concat = "";
if(filePath.length > 0)
{
for(int i=0;i<filePath.length;i++)
{
count_response = i;
if(i == 0)
{
uploadAsync.execute(filePath[0]);
mHandler = new Handler() {
#Override public void handleMessage(Message msg) {
String s=(String)msg.obj;
Log.d("logIMEI","\n Response from Asynctask: " + s);
str_response_fromAsync = s;
}
};
}
else
{
uploadAsync.getStatus();
while(uploadAsync.getStatus() == AsyncTask.Status.RUNNING) // this while loop is just to keep the loop value waitining for finishing the asyncTask
{
int rx = 0;
}
if(uploadAsync.getStatus() != AsyncTask.Status.RUNNING)
{
if(uploadAsync.getStatus() == AsyncTask.Status.FINISHED)
{
if(str_response_fromAsync != "" || !str_response_fromAsync.equals("") || !str_response_fromAsync.isEmpty())
{
uploadAsync.execute(filePath[i]);
x = i;
mHandler = new Handler() {
#Override public void handleMessage(Message msg)
{
String s=(String)msg.obj;
Log.d("logIMEI","\n Response from Asynctask_" + x + ": " + s);
str_response_fromAsync = s;
}
};
}
}
}
}
}
}
}
And the asyncTask:
private class UploadFileToServer extends AsyncTask<String, Integer, String>
{
#Override
protected void onPreExecute()
{
super.onPreExecute();
}
#Override
protected String doInBackground(String... params)
{
return uploadFile(params[0]);
}
private String uploadFile(String pr)
{
//inside here calling webservice and getting a response string as result.
MyWebsrvcClass mycls = new MyWebsrvcClass();
return responseString_concat = mycls.Call(xxx,yyy) ;
}
#Override
protected void onPostExecute(String result)
{
Log.d("logIMEI" , "\n count_response : "+ count_response + " fileprath_len : " + filePath.length);
Message msg=new Message();
msg.obj=result.toString();
mHandler.sendMessage(msg);
super.onPostExecute(result);
}
}
Now the problem is that its not working as expected. The first time when value of i is equals 0 than the AsyncTask gets called and after that its not getting called anymore.
Plus, when first time AsyncTask is called- its still not directly entering to onPostExecute(). When the loop ends totally and newUploadWithSeparate() method ends then the onPostExecute() is working.
Any solutions for this or any other way to do this job done for using AsyncTask inside loop?
You cannot call execute() on the same object more than once. So create a new instance of UploadFileToServer for each iteration of the loop.