recently i opened a question about how to call a method in another class... ok, i did call the example method, but the method i really want to call isn't working:
I have 2 classes:
I want to call the method here: TelaCadastroRestaurante.java
I have the method here: Metodos.java
http://i.imgur.com/JVMjz8J.png
http://i.imgur.com/IuBTmCY.png
public class TelaCadastroRestaurante extends Activity {
private EditText nomeRestaurante, emailRestaurante, telefoneRestaurante;
private Button buttonProximo;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tela_cadastro_restaurante);
incializarComponentes();
acaoBotoes();
}
public void incializarComponentes() {
nomeRestaurante = (EditText) findViewById(R.id.editTextNomeRestauranteTelaCadastroRestaurante);
emailRestaurante = (EditText) findViewById(R.id.editTextEmailRestauranteTelaCadastroRestaurante);
telefoneRestaurante = (EditText) findViewById(R.id.editTextTelefoneRestauranteTelaCadastroRestaurante);
buttonProximo = (Button) findViewById(R.id.buttonProximoTelaCadastroRestaurante);
}
public void acaoBotoes() {
buttonProximo.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Metodos metodos = new Metodos();
Metodos.taskInProgres(true, getApplicationContext());
}
});
}
public void pegarValores(){
Restaurante rest = new Restaurante();
rest.setNomeRest(nomeRestaurante.getText().toString());
rest.setEmailRest(emailRestaurante.getText().toString());
rest.setTelefoneRest(Integer.parseInt(telefoneRestaurante.getText().toString()));
Toast.makeText(getApplicationContext(), rest.getNomeRest() + "\n" + rest.getEmailRest() + "\n" + rest.getTelefoneRest(), Toast.LENGTH_SHORT).show();
}
}
CLASS WITH METHODS
public class Metodos {
private static ProgressDialog dialog;
public static void taskInProgres(boolean mostrar, Context context) {
if (dialog == null) {
dialog = new ProgressDialog(context);
dialog = ProgressDialog.show(context, "","Aguarde a verificação...", true);
}
if (mostrar) {
dialog.show();
} else {
dialog.dismiss();
}
}
}
In your xMetodos.java class change the method to be static :
private static void... and in TelaCadastroRestaurante.java class call it like this :
xMetodos.taskInProgres(true,getApplicationContext());
If you declared method as static you can call it without instantiating it.
You have to make an instance of class xMethodos to be able to call the method.
Code would look like:
xMethodos foo = new xMethodos ():
foo.taskInProgress([YOUR_BOOL], [YOUR_CONTEXT);
Where the context would probably your activity, which can be reffered to as this.
Related
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 have 3 classes.
One of them have the attributes with setters and getters
On my main activity I have the class nameClass = new class
This My main Activity
coffe_cal coffecalo1 = new coffe_cal();
public void addf1(View view){
coffecalo1.setFraps01(true);
coffecalo1.setFraps1(65.00);
showfrappeup();
}
public void checkout(View view){
Intent checkout2 = new Intent (this, check_out.class);
startActivity(checkout2);
}
and I have an onClick event that set my boolean = true but in my third class I have the following
TextView stuff = (TextView) findViewById(R.id.StuffTotal);
String SoutTotal = "";
SoutTotal += coffecalo1.TotalTicket();
stuff.setText(SoutTotal);
}
On my TotalTicket method I have this :
public String TotalTicket(){
String message = "";
if (this.isFraps01()){
message += "Frappuccino moka .................." + this.getFraps1() + "\n\n";
}
return message;
}
This is the onClick event :
public void addf1(View view){
coffecalo1.setFraps01(true);
coffecalo1.setFraps1(65.00);
showfrappeup();
}
When I run my app the TextView doesn't show anything. There 2 different activities by the way.
define the variable as a public static variable shall to the trick.
public class MyActivity {
public static boolean myVar = false;
}
public class AnotherClass {
public void someMethod() {
if (MyActivity.myVar) { // do some work
}
}
I would like to know just out of curiosity if there are any convenient ways of pulling data out of an async task created inside a class, and then modifying the data in another class (Without extending classes)
I have a way to do it, but it involves making methods static along with the Async task itself
for example, here I'm just making a string "text" in the Async task
public class Main extends Activity{
//Context ctx;
static class MyAsyncTask extends AsyncTask<Void,String,String>{
static String result;
private static Context context;
public MyAsyncTask(Context m)
{
this.context = m;
}
#Override
protected String doInBackground(Void... noArgs) {
result = "text";
return result;
}
protected void onPostExecute(String result)
{
super.onPostExecute(result);
}
public static String getStr()
{
return result;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText et = (EditText)findViewById(R.id.editText1);
Button btn = (Button)findViewById(R.id.button1);
MyAsyncTask task = new MyAsyncTask(this);
task.execute();
final Test t = new Test();
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v)
{
et.append(t.modifiedString());
}
});
}
}
and in a new class I make a simple String method to modify that data from the async task
public class Test{
public String modifiedString()
{
// Main main = null;
// MyAsyncTask task = new MyAsyncTask(main.ctx);
// task.execute();
String s = (String)Main.MyAsyncTask.getStr();
return "modified " + s + "\n";
}
}
I'm wondering, is there a way I can do this without having to make the async task static? Perhaps with sharing contexts or something?
by the way I'm not doing this to solve any particular problem, I'm only doing it out of curiosity
Just create a singleton
public class Main extends Activity{
public static Main instance;
public static String thestring;
public class MyAsyncTask extends AsyncTask<Void,String,String>{
static final String result = "text";
Context context;
public MyAsyncTask(Context m)
{
this.context = m;
}
#Override
protected String doInBackground(Void... noArgs) {
return result;
}
protected void onPostExecute(String result)
{
super.onPostExecute(result);
}
public String getStr()
{
return result;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText et = (EditText)findViewById(R.id.editText1);
Button btn = (Button)findViewById(R.id.button1);
MyAsyncTask task = new MyAsyncTask(this);
task.execute();
thestring = task.getStr();
instance = this;
final Test t = new Test();
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v)
{
et.append(t.modifiedString());
}
});
}
public String pulledFromAsyncTask()
{
return thestring;
}
public static Main getInstance(){
return instance;
}
}
and then in the another class
public class Test{
public String modifiedString()
{
Main main = Main.getInstance();
//so with main.something.. you can call the methods you want
//a good solution is to make a singleton class only for MyAsyncTask setting the
//functions get/set so you can take the values from other classes
return "modified " + main.pulledFromAsyncTask() + "\n";
}
}
Reference to a Context in a static way is generally bad idea, it can cause memory leaks
Why don't you simply pass MyAsyncTask object to Test and then do whatever modifications you want, i.e. non-static fashion?
When it comes to testable code static/ singleton is a tough choice.
Depending upon your requirement on the state of data you can however start with an Observer pattern or producer-consumer pattern.
Check out Event bus library for probably an out of the box solution for this use case
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.
My interface:
public interface LoginDialogDismissListener {
void loginDialogCancel();
void loginDialogSuccess();
}
My activity:
public class MainActivity extends Activity implements LoginDialogDimissListener {
public void loginDialogCancel() {
//do stuff here
}
public void loginDialogSuccess() {
//do some other stuff here!
}
}
My LoginDialog:
public class LoginDialog extends Dialog implements OnClickListener, LoginChecker {
private ProgressBar pbLogin;
private TextView tvLoginstatus;
private Button cancel;
private Button save;
private EditText username;
private EditText password;
public LoginDialog(Context context) {
super(context);
setContentView(R.layout.login_dialog);
pbLogin = (ProgressBar) findViewById(R.id.progressBarLogin);
tvLoginstatus = (TextView) findViewById(R.id.dialogTvLoginstatus);
cancel = (Button) findViewById(R.id.bDialogCancel);
save = (Button) findViewById(R.id.bDialogSave);
username = (EditText) findViewById(R.id.dialogEtUsername);
password = (EditText) findViewById(R.id.dialogEtPassword);
setTitle("Brukerdata");
pbLogin.setVisibility(View.INVISIBLE);
tvLoginstatus.setVisibility(View.INVISIBLE);
cancel.setOnClickListener(this);
save.setOnClickListener(this);
//setOnDismissListener(this);
}
public void onClick(View v) {
if (v.getId() == R.id.bDialogSave) {
saveClick();
}
else if (v.getId() == R.id.bDialogCancel) {
cancelClick();
}
}
private void saveClick() {
save.setEnabled(false);
String[] credentials = {username.getText().toString(), password.getText().toString()};
pbLogin.setVisibility(View.VISIBLE);
CheckLoginTask logintask = new CheckLoginTask(this, credentials, 0);
logintask.execute();
}
private void cancelClick() {
this.dismiss();
//Here I want to call LoginDialogDismissListener.loginDialogCancel()
}
//Called from my AsyncTask (CheckLoginTask)
public void onLoginSuccess(int requestCode) {
this.dismiss();
//Here I want to call LoginDialogDismissListener.loginDialogSuccess()
}
//Called from my AsyncTask (CheckLoginTask)
public void onLoginFail(int requestCode) {
pbLogin.setVisibility(View.INVISIBLE);
tvLoginstatus.setText("Feil brukernavn/passord ...");
tvLoginstatus.setVisibility(View.VISIBLE);
save.setEnabled(true);
}
}
If you have read my comments in the code, you see that I want to call my MainActivity with the methods it implements from my interface. The thing is that I can't figure out how to send my activity only once to my LoginDialog.
I mean, first it needs the Context, second I would like to provide it LoginDialogDismissListener (should probably change that name...), which is my activity.
I feel there is a better solution than this:
//Constructor
public LoginDialog(Context context, LoginDialogDismissListener listener) {
}
//Activity creating the Dialog
new LoginDialog(this, this);
I have tried to define the constructor to only have LoginDialogDismissListener as argument, but I am not allowed to cast it or somehow get the context that I need for my super(context)
Answer from #android-dev
Make a parent Activity that implements my interface and have all activities extend that again.
Don't use "this", use getApplicationContext().