I have a class which has a static inner class. The OuterClass wants to use the variables from the static inner class. The problem is I need to instantiate the inner class if I'm using instance variables. So, I decided to use a static variables. Does it contrary to OOP concepts? If so, is there any other principle I should follow or any design pattern I should use to do the same thing?
The reason I used static class is I want to create a custom builder for android activity. The problem is I cannot use constructor to initialise OuterClass which extends Activity. So, I need to load those static variables inside the onCreate() method.
This is my sample code
public class DialogFactory extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setBackgroundDrawable(
new ColorDrawable(android.graphics.Color.TRANSPARENT));
setContentView(R.layout.activity_custom_dialog);
this.setDialogTitle(Builder.title);
this.setDialogMessage(Builder.message);
this.loadButtons();
}
public void onClick(View view) {
switch (view.getId()) {
case R.id.dialog_positive_button:
Builder.callable.onClickButton(Builder.type, DialogEventListener.ButtonType.POSITIVE_BUTTON);
this.finish();
break;
case R.id.dialog_neutral_button:
Builder.callable.onClickButton(Builder.type, DialogEventListener.ButtonType.NEUTRAL_BUTTON);
this.finish();
break;
case R.id.dialog_negative_button:
Builder.callable.onClickButton(Builder.type, DialogEventListener.ButtonType.NEGATIVE_BUTTON);
this.finish();
break;
}
}
private void setDialogTitle(String title) {
TextView view = (TextView) findViewById(R.id.dialog_title);
view.setText(title);
}
private void setDialogMessage(String message) {
TextView view = (TextView) findViewById(R.id.dialog_message);
view.setText(message);
}
private void loadButtons() {
Button positiveButton = (Button) findViewById(R.id.dialog_positive_button);
Button negativeButton = (Button) findViewById(R.id.dialog_negative_button);
Button neutralButton = (Button) findViewById(R.id.dialog_neutral_button);
positiveButton.setVisibility(View.GONE);
negativeButton.setVisibility(View.GONE);
neutralButton.setVisibility(View.GONE);
for (Map.Entry<DialogEventListener.ButtonType, String> entry: Builder.buttons.entrySet()) {
if (entry.getKey() == DialogEventListener.ButtonType.POSITIVE_BUTTON) {
positiveButton.setVisibility(View.VISIBLE);
positiveButton.setText(entry.getValue());
}
else if (entry.getKey() == DialogEventListener.ButtonType.NEGATIVE_BUTTON) {
negativeButton.setVisibility(View.VISIBLE);
negativeButton.setText(entry.getValue());
}
else if (entry.getKey() == DialogEventListener.ButtonType.NEUTRAL_BUTTON) {
neutralButton.setVisibility(View.VISIBLE);
negativeButton.setText(entry.getValue());
}
}
}
#Override
public void onBackPressed() {
//
}
public static final class Builder {
private static DialogEventListener callable;
private static DialogEventListener.DialogType type;
private static String title;
private static String message;
private Context context;
private static Map<DialogEventListener.ButtonType, String> buttons;
public Builder(Context context, DialogEventListener callable,
DialogEventListener.DialogType dialogType, String title, String message) {
Builder.callable = callable;
Builder.type = dialogType;
Builder.title = title;
Builder.message = message;
this.context = context;
Builder.buttons = new HashMap<DialogEventListener.ButtonType, String>();
}
public Intent build() {
return new Intent(this.context, DialogFactory.class);
}
public void addButton(DialogEventListener.ButtonType buttonType, String label) {
Builder.buttons.put(buttonType, label);
}
}
}
After looking at your code, I see multiple problems. To start with, the constructor in the Builder class is use less. And accessing all the attributes of the builder class with class name (declaring them as static) will give you uninitialized references and will result into null pointer exception.
I don't completely understand the purpose of your Builder class here, but if possible try to create a separate class that deals with the creation and initialization. After that create an instance of Builder class inside activity class, use constructor to inject dependencies, and try to use functions inside builder class to perform further operations.
Related
In my android app I'm trying to extend the Thread class to easy pass my values between the original thread and a another one. So I can easily update my UI.
To do this I extended the Thread class:
public class ThreadUpdateUI extends Thread {
AppCombatActivityExtended activity;
Map<?,?> values;
public ThreadUpdateUI(AppCombatActivityExtended activity, Map<?,?> values){
this.activity = activity;
this.values = values;
}
public void UpdateUI(Map<?,?> values){
this.activity.UIThreadFinished(values);
}
public Map<?,?> GetValues()
{
return this.values;
}
}
Not only did I extend Threads, but I also extended the class for Activity so I have a main function I can call in every activity to update my UI:
public class AppCombatActivityExtended extends AppCompatActivity {
protected void UIThreadFinished(Map<?,?> values){}
}
In my activity I use the ThreadUpdateUI class to run a thread in which I can pass all my own values to use in the other thread:
public class MainActivity extends AppCombatActivityExtended {
static final String carlooking_key = "text_carlooking";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//init views
final TextView text_carlooking = (TextView) findViewById(R.id.main_text_carlooking);
//init parameters for thread
HashMap<String, String> UIThreadParameters = new HashMap<>();
UIThreadParameters.put(carlooking_key, text_carlooking.getText().toString().replace(".", ""));
//ThreadUpdateUI
ThreadUpdateUI TU_UI = new ThreadUpdateUI(this, UIThreadParameters) {
#Override
public void run() {
try {
Integer counter = 0;
while (true) {
sleep(1000);
Map values = GetValues();
String text = values.get(carlooking_key).toString();
text += "_test";
Map result = new HashMap<String,String>();
result.put(carlooking_key, text);
UpdateUI(result);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
TU_UI.start();
}
#Override
protected void UIThreadFinished(Map<?, ?> values) {
super.UIThreadFinished(values);
final TextView text_carlooking = (TextView) findViewById(R.id.main_text_carlooking);
text_carlooking.setText(values.get(carlooking_key).toString());
}
}
My code crashes at:
UpdateUI(result);
Saying: "Only the original thread that created a view hierarchy can touch its views."
In my trace I can see the following:
at MainActivity.UIThreadFinished(MainActivity.java:56)
at ThreadUpdateUI.UpdateUI(ThreadUpdateUI.java:21)
at MainActivity$1.run(MainActivity.java:42)
Which could indicate that the reference changed in my ThreadUpdateUI causing to call ThreadUpdateUIFinished in a different thread than the original.
Is it possible to make this code return to the original thread to update my UI in a loop?
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
}
}
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.
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
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().