I am having a problem with getting the result from an asyncTask in a separate class. I have followed from a similar questions answer on here but I cant see where I have gone wrong.
My AsyncTask is in a separate class for easy calling, I needed to be able to have the notice that the asyntask had completed and then start the next activity.
I would welcome any help as I am not sure quite where I have gone wrong.
public class StartScreen extends Activity{
ProgressDialog pd;
CountDownTimer waitTimer;
public static final String APP_PREFERENCES = "AppPrefs";
SharedPreferences settings;
SharedPreferences.Editor prefEditor;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start_screen);
settings = getSharedPreferences(APP_PREFERENCES, MODE_PRIVATE);
// getPreferences();
// prefEditor = settings.edit();
waitTimer = new CountDownTimer(2000, 300) {
public void onTick(long millisUntilFinished) {
//called every 300 milliseconds, which could be used to
//send messages or some other action
}
public void onFinish() {
//After 2000 milliseconds (2 sec) finish current
//if you would like to execute something when time finishes
pd = ProgressDialog.show(StartScreen.this,"Title","Detail text",true,false,null);
getPreferences();
}
}.start();
}
private void getPreferences() {
String UserName = settings.getString("UserName", null);
if (UserName != null) {
// the key does not exist
Intent intent=new Intent(StartScreen.this,InitialPreferences.class);
startActivity(intent);
} else{
//if (UserName.equals(UserName)){
// handle the value
dataTask();
//pd.dismiss();
}
}
private void dataTask() {
// TODO Auto-generated method stub
new DATATask(this).execute(new FragmentCallback(){
#Override
public void onTaskDone() {
startMainAct();
}
});
}
private void startMainAct() {
Intent intent=new Intent(StartScreen.this,MainActivity.class);
startActivity(intent);
}
public interface FragmentCallback {
public void onTaskDone();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.start_screen, menu);
return true;
}
}
AsyncTask:
public class DATATask extends AsyncTask<Void, Void, ArrayList<String>> {
private FragmentCallback mFragmentCallback;
public void execute(FragmentCallback fragmentCallback) {
mFragmentCallback = fragmentCallback;
}
ArrayList<String> arr_data=new ArrayList<String>();
private Context context;
public DATATask(Context context)
{
this.context = context;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected ArrayList<String> doInBackground(Void... params) {
Document docVts, docTide;
String shippingList, tideTimes;
try {
docVts = Jsoup.connect("https://vts.mhpa.co.uk/main_movelistb.asp").timeout(600000).get();
Elements tableRows = docVts.select("table.dynlist td:eq(0),td:eq(1),td:eq(3),td:eq(4),td:eq(7),td:eq(8)");
tableRows.size();
for(int i = 1; i < 80; i++){//only allows x results from vts list, from 1 not 0. 0 produces needless results
shippingList = tableRows.get(i).text().replaceAll(" | ", "") +"\n";
arr_data.add(shippingList);// add value to ArrayList
System.out.println(shippingList);
};
docTide = Jsoup.connect("http://www.mhpa.co.uk/search-tide-times/").timeout(600000).get();
Elements tideTimeOdd = docTide.select("div.tide_row.odd div:eq(0)");
Elements tideTimeEven = docTide.select("div.tide_row.even div:eq(0)");
Elements tideHightOdd = docTide.select("div.tide_row.odd div:eq(2)");
Elements tideHightEven = docTide.select("div.tide_row.even div:eq(2)");
Element firstTideTime = tideTimeOdd.first();
Element secondTideTime = tideTimeEven.first();
Element thirdTideTime = tideTimeOdd.get(1);
Element fourthTideTime = tideTimeEven.get(1);
Element firstTideHight = tideHightOdd.first();
Element secondTideHight = tideHightEven.first();
Element thirdTideHight = tideHightOdd.get(1);
Element fourthTideHight = tideHightEven.get(1);
System.out.println("first tide time: " + firstTideTime.text() + " " + firstTideHight.text());
System.out.println("second tide time: " + secondTideTime.text() + " " + secondTideHight.text() );
System.out.println("third tide time: " + thirdTideTime.text() + " " + thirdTideHight.text());
System.out.println("fourth tide time: " + fourthTideTime.text() + " " + fourthTideHight.text());
{
/*
Work with data - all is OK
*/
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return arr_data;//<< return ArrayList from here
}
#Override
protected void onPostExecute(ArrayList<String> result) {
mFragmentCallback.onTaskDone();
}
}
Thanks for any help.
You are not calling the correct AsyncTask.execute(). The correct execute will invoke the onPreExecute() then doInBackground() then onPostExecute().
new DATATask(this).execute(new FragmentCallback(){
#Override
public void onTaskDone() {
startMainAct();
}
});
}
will call this method (the wrong one):
public void execute(FragmentCallback fragmentCallback) {
mFragmentCallback = fragmentCallback;
}
What you want to do is change this method to - setFragmentCallBack(FragmentCallback);
Then in the OnPostExecute() add this: startMainAct();
instead of doing this:
#Override
public void onTaskDone() {
startMainAct();
}
After this is done, then call the new DATATask(this).execute();
which will invoke the preExecute(), doInbackground, and PostExecute()
What you are doing is adding the FragCallback to the DataTask and not invoking the correct execute function.
I hope this helps.
Actually you did not execute your AsyncTask. You should call "super.execute(Params... params);" in you overloaded execute(FragmentCallback) method.
In your Activity:
DataTask dataTask = new DataTask();
dataTask.execute();
In your AsyncTask class:
onPostExecute(){
//put your intent to start the activity or whatever you want to do when it finishes
}
I think it is much simpler than you are making it. Hope that helps. Also, see AsyncTask Android example
You didn't execute the AsyncTask. Calling DATATask.execute(FragmentCallback) will just assign the callback to your task. You need to call either AsyncTask#execute(Runnable), AsyncTask#execute(Params...) or AsyncTask#executeOnExecutor(Executor exec, Params... params).
Also, I would pass the callback to DATATask via the constructor or a setter, instead of creating a new overloaded execute(FragmentCallback) method. It can easily confuse people.
Related
My applications hang for a bit when I populate data from realm database to my listview.
So I planned to do it using Asynchronously so meanwhile data is collected I display a Loading dialogue here is the Code.
Already referred to this question by not able to implement in my case.
private class YourAsyncTask extends AsyncTask<String, String, RealmResults> {
ProgressDialog progressDialog;
#Override
protected void onPreExecute() {
// start loading animation maybe?
progressDialog = ProgressDialog.show(DictionarySscWords.this,
"ProgressDialog",
"Loading all words!");
}
#Override
protected RealmResults doInBackground(String... params) {
RealmConfiguration realmConfig = new RealmConfiguration.Builder(context).build();
Realm.setDefaultConfiguration(realmConfig);
realm = realm.getDefaultInstance();
RealmQuery<Word> query = realm.where(Word.class);
for (int i = 0; i < words_for_ssc[Integer.parseInt(params[0])].length; i++) {
if (i == words_for_ssc[Integer.parseInt(params[0])].length - 1) {
query = query.equalTo("word", words_for_ssc[Integer.parseInt(params[0])][i]);
} else {
query = query.equalTo("word", words_for_ssc[Integer.parseInt(params[0])][i])
.or();
}
}
sscresult = query.findAll(); //error 1
return sscresult;
}
#Override
protected void onPostExecute(RealmResults r) {
progressDialog.dismiss();
list.setAdapter(new MyAdapter(sscresult)); //error 2
realm.close();
}
}
ok so there are two problems if anyone can be solved my application would be error-free
if I try to run list.setAdapter(new MyAdapter(sscresult)); in background process the error is:-
this can run only in UI thread
if try to run in postExecute error is :-
Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created.
I am not able to solve this issue please help
You can have your query evaluated on a background thread using asynchronous query API in Realm.
private OrderedRealmCollectionChangeListener<RealmResults<User> callback = new OrderedRealmCollectionChangeListener<>() {
#Override
public void onChange(RealmResults<User> results, OrderedCollectionChangeSet changeSet) {
if (changeSet == null) {
// The first time async returns with an null changeSet.
} else {
// Called on every future update.
}
}
};
private RealmResults<User> result;
public void onStart() {
result = realm.where(User.class).findAllAsync();
result.addChangeListener(callback);
}
But if you give the RealmResults to a RealmRecyclerViewAdapter, then this is all automatic.
P.S. not closing Realm instance in doInBackground() is like, S-class horrible mistake. Please close your Realm instance on non-looping background threads.
Specifically the following:
// private class YourAsyncTask extends AsyncTask<String, String, RealmResults> {
//
// ProgressDialog progressDialog;
// #Override
// protected void onPreExecute() {
// // start loading animation maybe?
// progressDialog = ProgressDialog.show(DictionarySscWords.this,
// "ProgressDialog",
// "Loading all words!");
// }
//
// #Override
// protected RealmResults doInBackground(String... params) {
// RealmConfiguration realmConfig = new RealmConfiguration.Builder(context).build();
// Realm.setDefaultConfiguration(realmConfig);
// realm = realm.getDefaultInstance();
// RealmQuery<Word> query = realm.where(Word.class);
//
// for (int i = 0; i < words_for_ssc[Integer.parseInt(params[0])].length; i++) {
// if (i == words_for_ssc[Integer.parseInt(params[0])].length - 1) {
//
// query = query.equalTo("word", words_for_ssc[Integer.parseInt(params[0])][i]);
// } else {
// query = query.equalTo("word", words_for_ssc[Integer.parseInt(params[0])][i])
// .or();
//
// }
//
// }
// sscresult = query.findAll(); //error 1
// return sscresult;
//
// }
//
// #Override
// protected void onPostExecute(RealmResults r) {
// progressDialog.dismiss();
// list.setAdapter(new MyAdapter(sscresult)); //error 2
// realm.close();
// }
//}
and
public class MyActivity extends AppCompatActivity {
private RealmResults<Word> words;
private Realm realm;
private WordAdapter wordAdapter;
#BindView(R.id.recycler_view)
RecyclerView recyclerView;
#Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.my_activity);
ButterKnife.bind(this);
realm = Realm.getDefaultInstance();
words_for_ssc = ...
RealmQuery<Word> query = realm.where(Word.class);
String[] array = words_for_ssc[Integer.parseInt(params[0])];
for (int i = 0; i < array.length; i++) {
query = query.equalTo("word", array[i]);
if (i != array.length - 1) {
query = query.or();
}
}
words = query.findAllSortedAsync("word");
wordAdapter = new WordAdapter(words);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(wordAdapter);
}
#Override
public void onDestroy() {
super.onDestroy();
realm.close();
realm = null;
}
}
public class WordAdapter extends RealmRecyclerViewAdapter<Word, WordViewHolder> {
public class WordAdapter(OrderedRealmCollection<Word> words) {
super(words, true);
}
#Override
public WordViewHolder onCreateViewHolder(...) {
...
}
#Override
public void onBindViewHolder(WordViewHolder holder, int position) {
holder.bind(getData().get(position));
}
public static class WordViewHolder extends RecyclerView.ViewHolder {
public WordViewHolder(View view) {
super(view);
ButterKnife.bind(this, view);
}
public void bind(Word word) {
...
}
}
}
I think a cleaner solution to your problem without changing much of the code can be written below. In this case, everything that realm does happen on the background thread inside doInBackground. The realm instance is also closed on the thread it was created.
Now what I did basically is that I extracted a deep copy of the list of Words from RealmResult from realm.copyFromRealm(sscresult) which is completely detached from realm and can be moved around and modified inside any thread. All these objects are now free from realm and can be used in onPostExecute without any worries. The only thing you need to modify is the MyAdapter constructor which doesn't take a RealmResult but instead a List of Words which is exactly what you need and can be iterated the same way as RealmResult was.
The only downside of this approach is that the list of Words will not get synced automatically since they're detached and their value won't change automatically if they get altered inside Realm from somewhere else. But I'm pretty sure though that it won't bother you.
I'm also going to attach an official reference for realm.copyFromRealm() which is here.
private class YourAsyncTask extends AsyncTask<String, String, List<Word>> {
ProgressDialog progressDialog;
#Override
protected void onPreExecute() {
// start loading animation maybe?
progressDialog = ProgressDialog.show(DictionarySscWords.this,
"ProgressDialog",
"Loading all words!");
}
#Override
protected List<Word> doInBackground(String... params) {
RealmConfiguration realmConfig = new RealmConfiguration.Builder(context).build();
Realm.setDefaultConfiguration(realmConfig);
try(realm = realm.getDefaultInstance()) {
RealmQuery<Word> query = realm.where(Word.class);
for (int i = 0; i < words_for_ssc[Integer.parseInt(params[0])].length; i++) {
if (i == words_for_ssc[Integer.parseInt(params[0])].length - 1) {
query = query.equalTo("word", words_for_ssc[Integer.parseInt(params[0])][i]);
} else {
query = query.equalTo("word", words_for_ssc[Integer.parseInt(params[0])][i])
.or();
}
}
// Here's the sort. Use findAllSorted instead.
// You can change Sort.ASCENDING to Sort.DESCENDING to reverse
// the order.
sscresult = query.findAllSorted("word", Sort.ASCENDING);
// This is where the magic happens. realm.copyFromRealm() takes
// a RealmResult and essentially returns a deep copy of the
// list that it contains. The elements of this list is however
// completely detached from realm and is not monitored by realm
// for changes. Thus this list of values is free to move around
// inside any thread.
ArrayList<Word> safeWords = realm.copyFromRealm(sscresult);
realm.close();
return safeWords;
}
}
#Override
protected void onPostExecute(List<Word> words) {
progressDialog.dismiss();
// Please note here MyAdaptor constructor will now take the
// list of words directly and not RealmResults so you slightly
// modify the MyAdapter constructor.
list.setAdapter(new MyAdapter(words));
}
}
Hope it helps!
I am pretty new at android developing(only 2 months)
I am trying to create an asyncTask which receives a user id and creates the user object, and after it finishes to replace fragment.
every thing went well, until I tried to add publish updates.
Inside my user object it creates days object when creating the user,
I want the asyncTast to change textView text according to the number of days created so far.
So I created an interface inside my User object which call dayCreated() function everytime day is created and pass to it the number of days so far.
Inside my asyncTask in doInBackground I tried to set the listener and call publishUpdates each time but it crashes.
Here is my AsyncTask code:
class CreateUserTask extends AsyncTask<Integer, Integer, User> {
private int uid = -1;
#Override
protected User doInBackground(Integer... params) {
uid = params[0];
try {
User user;
user = new User(MainActivity.this, uid);
user.setEventHandler(new User.EventHandler() {
#Override
public void dayCreated(int dayCounter) {
publishProgress(dayCounter);
}
});
return user;
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPreExecute() {
fragmentsReplace(loadingFragment, "Loading");
}
#Override
protected void onPostExecute(User userRecieved) {
if(userRecieved != null) {
fragmentsReplace(mainFragment, TAG_MAIN_FRAGMENT);
user = userRecieved;
login();
}
else{
fragmentsReplace(loginFragment, TAG_LOGIN_FRAGMENT);
}
}
#Override
protected void onProgressUpdate(Integer... values) {
loadingFragment.setDayCounter(values[0]);
}
}
And inside my User object this is how I call using interface:
int dayCounter = 0;
Cursor result = myDataBase.getDaysData(this.uid);
while (!result.isAfterLast()) {
try {
Calendar date = Calendar.getInstance();
date.setTimeInMillis(Long.parseLong(result.getString(result.getColumnIndex(DataBaseHelper.DB_DATE_COLUMN))));
DayOfWork day = new DayOfWork(this.uid, date, this.context);
this.daysOfWorkArray.add(day);
dayCounter++;
eventHandler.dayCreated(dayCounter++);
}catch (Exception e)
{
Log.e("error" , e.getMessage());
}
result.moveToNext();
And the eventHandler code:
EventHandler eventHandler = null;
public interface EventHandler{
void dayCreated(int dayCounter);
}
public void setEventHandler(EventHandler eventHandler){
this.eventHandler = eventHandler;
}
Does publishProgress() interact with anything in your UI? If so your issue is that you're calling it from a background thread in your async task. All UI interactions need to execute on the main/UI thread.
I've noticed a bug in a basic survey app I'm making to better learn android.
Occasionally I get a W/System.err﹕ at MainActivity.surveyAvailable(MainActivity.java:40) that points to this line of code:
button.setVisibility(View.GONE);
I've used setVisibility many times before and never had any issues.
Here's the function, this gets called when the user first enters the app, and after they finish taking a survey to check the server and see if there is another survey available for the user:
public void surveyAvailable(boolean surveyIsAvailable) {
Log.d("MainActivity", "App survey is available? " + surveyIsAvailable );
Button button = (Button)findViewById(R.id.takeSurveyButton);
if (surveyIsAvailable) {
button.setVisibility(View.VISIBLE);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
App.getInstance().showSurvey();
}
});
} else {
Log.d("MainActivity", "We hit here");
button.setVisibility(View.GONE);
}
}
When a survey isn't available, the appropriate lines are logged - App survey is available? false and 'We hit here'. But then the button sometimes doesn't get set to View.GONE and I see the System.Err line. But sometimes it works fine and the button's visibility does change. Any idea how to fix that? Or how to get more information on what the System.Err actually means?
EDIT:
I found that by setting Button surveyButton; in my activity and then referencing the button as this.surveyButton seems to get the functionality to work more along the lines of what we'd expect (e.g. when we call button.setVisibility(View.GONE) the view is actually consistently GONE). But it still throws the System.Err line which has me hesitant that things are working correctly.
Edited Activity:
public class MainActivity extends ActionBarActivity implements SurveyListener {
Button surveyButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.surveyButton = (Button)findViewById(R.id.takeSurveyButton);
}
public void surveyAvailable(boolean surveyIsAvailable) {
Log.d("MainActivity", "App survey is available? " + surveyIsAvailable );
if (surveyIsAvailable) {
this.surveyButton.setVisibility(View.VISIBLE);
this.surveyButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
App.getInstance().showSurvey();
}
});
} else {
Log.d("MainActivity", "We hit here");
this.surveyButton.setVisibility(View.GONE);
}
}
}
The activity implements this class:
public abstract interface SurveyListener
{
public abstract void surveyAvailable(boolean surveyAvailable);
}
Main App class that checks for surveys and calls 'surveyAvailable()`:
public class App
{
private static App _instance;
private SurveyListener _eventsHandler;
private String _apiKey = "";
private String _appuserId = "";
private String _surveyUrl = "";
private Activity _parentContext;
private Boolean _surveyAvailable;
public static App initWithApiKeyAndListener(String apiKey, SurveyListener surveyEventsHandler) {
if (_instance == null)
{
_instance = new App();
_instance._parentContext = (Activity) surveyEventsHandler;
_instance.setSurveyListener(surveyEventsHandler);
_instance.setApiKey(apiKey);
String appuserId = PreferenceManager.getDefaultSharedPreferences((Activity) _instance._eventsHandler).getString(tag, "no_appuser");
if (appuserId == "no_appuser") {
_instance._surveyAvailable = true;
_instance.alertAvailability(true);
} else {
_instance.checkForCampaigns();
}
}
return _instance;
}
private void alertAvailability(boolean surveyAvailable) {
App.getInstance()._eventsHandler.surveyAvailable(surveyAvailable);
}
private void checkForCampaigns() {
new CampaignCheck().execute();
}
public static App getInstance()
{
if (_instance == null)
{
_instance = new App();
}
return _instance;
}
public void donePushed()
{
App.getInstance().checkForCampaigns();
}
private class CampaignCheck extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... params) {
Boolean surveysAvailable = false;
try {
surveysAvailable = new AppuserConnection().checkCampaigns();
App.getInstance()._surveyAvailable = surveysAvailable;
App.getInstance().alertAvailability(_surveyAvailable);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
}
}
}
You shouldn't modify the UI elements from a different thread. You are doing this by calling App.getInstance().alertAvailability(_surveyAvailable); on a background thread. Move this to the AsyncTask's onPostExecute.
I'm newbie in Java/ADT and I'm trying to get an array from "Activity A" to "Activity B". The app takes information from a webpage, and then saves it in a pair of arrays and show the information. I want to click a "go to graph" button (calls to viewallday()) to redirect to Activity B who will show a graphic with all this information.
The problem is that they're a self refresh array (1sec refresh) and don't want to loose this feature when the app It's on graphic mode (Activity B). Any ideas about how to do that?
Thank all of you in advance, I'm learning a lot from this site.
UPDATE: I'm trying to do this with a Singleton pattern. But LogCat says:
02-26 22:21:59.300: E/AndroidRuntime(2677): FATAL EXCEPTION: main
02-26 22:21:59.300: E/AndroidRuntime(2677): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.Chispa/com.example.Chispa.Activity_allday}: android.os.NetworkOnMainThreadException
02-26 22:21:59.300: E/AndroidRuntime(2677): Caused by: android.os.NetworkOnMainThreadException
UPDATE 2: Finally got it!! Here's the code I used:
Here's the code for Activity A:
public class MainActivity extends Activity {
private TextView tvmax, tvmid, tvmin, tvactualval,tvvaloractual,tvdate;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvdate=(TextView)findViewById(R.id.tvdate);
tvvaloractual=(TextView)findViewById(R.id.tvvaloractual);
tvmax=(TextView)findViewById(R.id.tvmaximo);
tvmid=(TextView)findViewById(R.id.tvmedio);
tvmin=(TextView)findViewById(R.id.tvminimo);
new BackGroundTask().execute();
callAsynchronousTask();
}
public void callAsynchronousTask() {
final Handler handler = new Handler();
Timer timer = new Timer();
TimerTask doAsynchronousTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
public void run() {
try {
BackGroundTask performBackgroundTask = new BackGroundTask();
// PerformBackgroundTask this class is the class that extends AsynchTask
performBackgroundTask.execute();
} catch (Exception e) {
// TODO Auto-generated catch block
}
}
});
}
};
timer.schedule(doAsynchronousTask, 0, 1000); //execute in every 1000 ms
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public class Pair
{
public String[] bar;
public String[] values;
}
public void viewallday(View view) {
Intent intent = new Intent(MainActivity.this, Activity_allday.class);
startActivity(intent);
}
class BackGroundTask extends AsyncTask<Void, Void, Pair> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
public String[] getValuesGraph(Document doc) {
int cont=24,var=7;
String bar[] = new String[cont];
/*
* Getting elements from the graphic in an array from 0-23. 0 it's 1:00am, 23 it's 00:00am
*/
for (cont=0; cont < 24; cont++){
String onMouseOver = doc.select("a").get(var+cont).attr("onMouseOver");
bar[cont] = onMouseOver.split("'")[9];
}
return bar;
}
public String[] getValuesFooter(Document doc) {
String values[] = new String[7];
/*
* Getting elements from the graphic footer
*/
String delimiters= "[ /]+";
Elements elements = doc.select("td.cabeceraRutaTexto");
elements.size(); // 6
/* Getting text from table */
values[0] = elements.get(0).text(); // TITLE
values[1] = elements.get(1).text(); // TEXT MAX VALUE
values[2] = elements.get(2).text(); // TEXT MIDDLE VALUE
values[3] = elements.get(3).text(); // TEXTO MIN VALUE
/* Getting numbers from table */
values[4] = elements.get(4).text().split(delimiters)[0]; // NUMBER MAX VALUE
values[5] = elements.get(5).text().split(delimiters)[0]; // NUMBER MIDDLE VALUE
values[6] = elements.get(6).text().split(delimiters)[0]; // NUMBER MIN VALUE
return values;
}
public Document getUrl(){
try {
URL url= new URL("http://www.endesaonline.com/canal/precios/Canal_Preciosdelpool.asp?FECHA=20140226");
/*URL url= new URL("http://www.endesaonline.com/canal/precios/Canal_Preciosdelpool.asp?lang=es&frameId=4064&segmento=1&promocion=");*/
Document doc = Jsoup.connect(url.toString()).get();
return doc;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
public Pair doInBackground(Void... params) {
Pair p = new Pair();
GlobalVariables gs = (GlobalVariables) getApplication();
gs.setBar(getValuesGraph(getUrl()));
p.bar = getValuesGraph(getUrl());
p.values = getValuesFooter(getUrl());
return p;
}
public String ActualHourValue() {
Format formatter = new SimpleDateFormat("H");
String onlyhour = formatter.format(new Date());
return onlyhour;
}
public void ShowDateHour(){
Calendar c = Calendar.getInstance();
SimpleDateFormat df3 = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss a");
String formattedDate3 = df3.format(c.getTime());
tvdate.setText("Fecha y hora actuales : "+formattedDate3);
}
#Override
protected void onPostExecute(Pair p) {
int hour = Integer.parseInt(ActualHourValue());
tvvaloractual.setText(p.bar[hour]+" €/MWh");
tvmax.setText(p.values[4]+" €/MWh");
tvmid.setText(p.values[5]+" €/MWh");
tvmin.setText(p.values[6]+" €/MWh");
ShowDateHour();
/*super.onPostExecute(p.values);*/
}
}
}
And here's the code for Activity B:
public class Activity_allday extends MainActivity {
private TextView tvall;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.all_day_price);
TextView tvall=(TextView)findViewById(R.id.tvall);
GlobalVariables gs = (GlobalVariables) getApplication();
String[] s = gs.getBar();
tvall.setText(s[0]);
}
}
And here's a GlobalVariable class who captures the array I want to send to Activity B:
public class Activity_allday extends MainActivity {
private TextView tvall;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.all_day_price);
TextView tvall=(TextView)findViewById(R.id.tvall);
GlobalVariables gs = (GlobalVariables) getApplication();
String[] s = gs.getBar();
tvall.setText(s[0]);
}
}
That's all! hope It'll help to future users.
Thanks all for your help.
Here is something you could try:
Inside your AsyncTask, define an interface and a method inside it that will pass back the data to the calling activity and inside that method, call the next activity and set the data as an extra.
This is the simplest way.
In your AsyncTask, inside onPostExecute(result), use a try block to call the method which belongs to the above mentioned interface which must be implemented by the calling activity.
HomeActivity.java
/public class SampleActivity extends Activity implements SampleAsyncTask.OnUpdateListener{
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
executeAsync();
}
public void executeAsync(){
new SampleAsyncTask(this).execute("someFlagToCheck");
}
#Override
public void onDataProcessed(String result){
Intent intent = new Intent(this, SecondActivity.class);
intent.putExtra("data", result);
startActivity(intent);
}
}
SampleAsyncTask.java
public class SampleAsyncTask extends AsyncTask<Void, Void, String>{
Context context;
//constructor
SampleAsyncTask(Context context){
this.context = context;
}
#Override
public void doInBackground(String... params){
//do something depending on the arguments in params
return "data";
}
#Override
public void onPostExecute(String result){
try{
((OnUpdateListener) context).onDataProcessed(result);
}catch(Exception e){
e.printStackTrace();
}
}
public interface OnUpdateListener{
public void onDataProcessed(String data);
}
}
Follow this example. The calling activity implements the AsyncTask's interface and overrides its method which will be called when the async task is done with the result.
I hope this helped.
SOLUTION:
Here's the code for Activity A:
public class MainActivity extends Activity {
private TextView tvmax, tvmid, tvmin, tvactualval,tvvaloractual,tvdate;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvdate=(TextView)findViewById(R.id.tvdate);
tvvaloractual=(TextView)findViewById(R.id.tvvaloractual);
tvmax=(TextView)findViewById(R.id.tvmaximo);
tvmid=(TextView)findViewById(R.id.tvmedio);
tvmin=(TextView)findViewById(R.id.tvminimo);
new BackGroundTask().execute();
callAsynchronousTask();
}
public void callAsynchronousTask() {
final Handler handler = new Handler();
Timer timer = new Timer();
TimerTask doAsynchronousTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
public void run() {
try {
BackGroundTask performBackgroundTask = new BackGroundTask();
// PerformBackgroundTask this class is the class that extends AsynchTask
performBackgroundTask.execute();
} catch (Exception e) {
// TODO Auto-generated catch block
}
}
});
}
};
timer.schedule(doAsynchronousTask, 0, 1000); //execute in every 1000 ms
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public class Pair
{
public String[] bar;
public String[] values;
}
public void viewallday(View view) {
Intent intent = new Intent(MainActivity.this, Activity_allday.class);
startActivity(intent);
}
class BackGroundTask extends AsyncTask<Void, Void, Pair> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
public String[] getValuesGraph(Document doc) {
int cont=24,var=7;
String bar[] = new String[cont];
/*
* Getting elements from the graphic in an array from 0-23. 0 it's 1:00am, 23 it's 00:00am
*/
for (cont=0; cont < 24; cont++){
String onMouseOver = doc.select("a").get(var+cont).attr("onMouseOver");
bar[cont] = onMouseOver.split("'")[9];
}
return bar;
}
public String[] getValuesFooter(Document doc) {
String values[] = new String[7];
/*
* Getting elements from the graphic footer
*/
String delimiters= "[ /]+";
Elements elements = doc.select("td.cabeceraRutaTexto");
elements.size(); // 6
/* Getting text from table */
values[0] = elements.get(0).text(); // TITLE
values[1] = elements.get(1).text(); // TEXT MAX VALUE
values[2] = elements.get(2).text(); // TEXT MIDDLE VALUE
values[3] = elements.get(3).text(); // TEXTO MIN VALUE
/* Getting numbers from table */
values[4] = elements.get(4).text().split(delimiters)[0]; // NUMBER MAX VALUE
values[5] = elements.get(5).text().split(delimiters)[0]; // NUMBER MIDDLE VALUE
values[6] = elements.get(6).text().split(delimiters)[0]; // NUMBER MIN VALUE
return values;
}
public Document getUrl(){
try {
URL url= new URL("http://www.endesaonline.com/canal/precios/Canal_Preciosdelpool.asp?FECHA=20140226");
/*URL url= new URL("http://www.endesaonline.com/canal/precios/Canal_Preciosdelpool.asp?lang=es&frameId=4064&segmento=1&promocion=");*/
Document doc = Jsoup.connect(url.toString()).get();
return doc;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
public Pair doInBackground(Void... params) {
Pair p = new Pair();
GlobalVariables gs = (GlobalVariables) getApplication();
gs.setBar(getValuesGraph(getUrl()));
p.bar = getValuesGraph(getUrl());
p.values = getValuesFooter(getUrl());
return p;
}
public String ActualHourValue() {
Format formatter = new SimpleDateFormat("H");
String onlyhour = formatter.format(new Date());
return onlyhour;
}
public void ShowDateHour(){
Calendar c = Calendar.getInstance();
SimpleDateFormat df3 = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss a");
String formattedDate3 = df3.format(c.getTime());
tvdate.setText("Fecha y hora actuales : "+formattedDate3);
}
#Override
protected void onPostExecute(Pair p) {
int hour = Integer.parseInt(ActualHourValue());
tvvaloractual.setText(p.bar[hour]+" €/MWh");
tvmax.setText(p.values[4]+" €/MWh");
tvmid.setText(p.values[5]+" €/MWh");
tvmin.setText(p.values[6]+" €/MWh");
ShowDateHour();
/*super.onPostExecute(p.values);*/
}
}
}
Activity B:
public class Activity_allday extends MainActivity {
private TextView tvall;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.all_day_price);
TextView tvall=(TextView)findViewById(R.id.tvall);
GlobalVariables gs = (GlobalVariables) getApplication();
String[] s = gs.getBar();
tvall.setText(s[0]);
}
}
Global variable class who captures the array I want to send to Activity B:
public class Activity_allday extends MainActivity {
private TextView tvall;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.all_day_price);
TextView tvall=(TextView)findViewById(R.id.tvall);
GlobalVariables gs = (GlobalVariables) getApplication();
String[] s = gs.getBar();
tvall.setText(s[0]);
}
}
Thanks all for your help!!
When I run my app, onPostExecute doesn't seem to be called. It is not populated the UI like it should be. Also, on DoInBackground, any log messages past the for loop:
for (int i = 0; i < businesses.length(); i++) { }
excluding the log messages in that particular for loop are not shown. So for example, the log message in the 2nd for loop for(int j = 0; j < businessNames.size(); j++) { } are not shown for some reason. Is this a timing issue or am I missing something?
But just to sum up, the UI in my onPostExecute is not being hit (as I know of).
Here is my code
public class CoffeeResultActivity extends Activity{
ExpandableListAdapter listAdapter;
ExpandableListView expListView;
List<String> businessNames = new ArrayList<String>();
List<String> businessInfo = new ArrayList<String>();
HashMap<String, List<String>> listDataChild = new HashMap<String, List<String>>();
private int lastExpandedPosition = -1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
expListView = (ExpandableListView) findViewById(R.id.lvExp);
//Calling AsyncTask
new RetreiveSearchResults().execute("coffee");
// Listview Group click listener
expListView.setOnGroupClickListener(new OnGroupClickListener() {
#Override
public boolean onGroupClick(ExpandableListView parent, View v,
int groupPosition, long id) {
return false;
}
});
expListView.setOnGroupExpandListener(new OnGroupExpandListener() {
#Override
public void onGroupExpand(int groupPosition) {
if (lastExpandedPosition != -1 && groupPosition != lastExpandedPosition) {
expListView.collapseGroup(lastExpandedPosition);
}
lastExpandedPosition = groupPosition;
}
});
// Listview Group collasped listener
expListView.setOnGroupCollapseListener(new OnGroupCollapseListener() {
#Override
public void onGroupCollapse(int groupPosition) {
Toast.makeText(getApplicationContext(),
businessNames.get(groupPosition) + " Collapsed",
Toast.LENGTH_SHORT).show();
}
});
// Listview on child click listener
expListView.setOnChildClickListener(new OnChildClickListener() {
#Override
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
// TODO Auto-generated method stub
Toast.makeText(
getApplicationContext(),
businessNames.get(groupPosition)
+ " : "
+ listDataChild.get(
businessNames.get(groupPosition)).get(
childPosition), Toast.LENGTH_SHORT)
.show();
return false;
}
});
}
class RetreiveSearchResults extends AsyncTask<String, Void, Void> {
#Override
protected Void doInBackground(String... terms) {
// Some example values to pass into the Yelp search service.
String category = "coffee";
// Execute a signed call to the Yelp service.
OAuthService service = new ServiceBuilder().provider(YelpApi2.class).apiKey("key").apiSecret("key").build();
Token accessToken = new Token("key", "key");
OAuthRequest request = new OAuthRequest(Verb.GET, "http://api.yelp.com/v2/search");
request.addQuerystringParameter("location", "Waterfront, Boston, MA");
request.addQuerystringParameter("category", category);
service.signRequest(accessToken, request);
Response response = request.send();
String rawData = response.getBody();
try {
JSONObject json = new JSONObject(rawData);
JSONArray businesses;
businesses = json.getJSONArray("businesses");
for (int i = 0; i < businesses.length(); i++) {
JSONObject business = businesses.getJSONObject(i);
//Log.d("FOO FOO", "FOO FOO FOO" + business.toString());
businessNames.add(business.get("name").toString());
//The following log message gets displayed
Log.d("FOO FOO", "FOO FOO " + businessNames.get(i));
businessInfo.add(business.get("rating").toString());
//The following log message gets displayed
Log.d("FOO FOO", "FOO FOO " + businessInfo.get(i));
}
//The following log message gets displayed
Log.d("FOO FOO", "SIZE" + businessNames.size());
for(int j = 0; j < businessNames.size(); j++) {
//The following log message DOES NOT GET DISPLAYED. But it does run through this for loop in debugger.
Log.d("FOO FOO", "FOO FOO ##### Get Here?);
//In Debugger, listDataChild does get populated.
listDataChild.put(businessNames.get(j), businessInfo);
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
protected void onPostExecute() {
//Does not enter onPostExecute in Debugger nor on a Regular run.
//Log message does NOT get printed
Log.d("FOO FOO", "FOO FOO Get in POST?");
listAdapter = new ExpandableListAdapter(CoffeeResultActivity.this, businessNames, listDataChild);
listAdapter.notifyDataSetChanged();
// setting list adapter
expListView.setAdapter(listAdapter);
}
}
}
The signature of onPostExecute is wrong. It should be like
protected void onPostExecute(Void result) {
}
Your onPostExecute does not match the AsyncTasks signature.
Try adding a Void parameter to the method like so:
protected void onPostExecute(Void result){}
You seem to have forgot to add your #Override tag to your onPostExecute