I have 3 classes, one in my CustomDialog class, another one is a non-activity class where i call my custom dialog, and a third class that is my App class from where I want want to dismiss the custom dialog.
Custom Dialog class:
public class DCCView extends Dialog {
private final String dCancel= "CANCEL";
private ResultListener listener;
private Button btnCurrency1;
private Button btnCurrency2;
private Button btnCancel;
private TextView tvCurrency1;
private TextView tvCurrency2;
private TextView tvMsg;
private Handler mTimer;
private Response response;
public DCCView(#NonNull Context context) {
super(context);
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.dcc_interface);
setCancelable(false);
btn1 = findViewById(R.id.btn1);
btn2 = findViewById(R.id.btn2);
btnCancel = findViewById(R.id.btn_cancel);
tv1 = findViewById(R.id.tv1);
tv2 = findViewById(R.id.tv2);
tvMsg = findViewById(R.id.tv_dcc_msg);
btnCurrency1.setOnClickListener(view -> {
response = Response.C1;
cancelAlert();
listener.onResult(response);
});
btnCurrency2.setOnClickListener(view -> {
response = Response.C2;
cancelAlert();
listener.onResult(response);
});
btnCancel.setOnClickListener(view -> {
response = Response.CANCEL;
cancelAlert();
listener.onResult(response);
});
}
public interface ResultListener {
void onResult(Response response);
}
public void showDCC(String transCurrency, double transAmount, String dccCurrency, String dccAmount,String dataDisplay, #NonNull ResultListener listener) {
this.listener = listener;
Handler hnd = new Handler(getContext().getMainLooper());
hnd.post(() -> {
showAlert();
btn1.setText(transCurrency);
tv1.setText(String.format("%.2f",transAmount));
btn2.setText(dccCurrency);
tv2.setText(dccAmount);
btnCancel.setText(dCancel);
tvMsg.setText(dataDisplay);
});
}
public void showAlert() {
if (!isShowing()) {
show();
}
}
public void cancelAlert() {
dismiss();
}
Non-activity class:
public class MSG1002{
private static DCCView mDccView;
public MSG1002() {
Handler hnd = new Handler(App.getContext().getMainLooper());
hnd.post(() -> {
mDccView = new DCCView(App.getContext());
});
}
public void process(){
mDccView.showDCC(transactionCurrency, transA, dccCurrency, dccAmount, dataUserDisplay, (DCCView.Response response) -> {
onDccResponse(response, socketCliente);
});
}
App class:
public class App extends Application{
private static DCCView mDCCView;
public static void realCancelAlert() {
mDCCView.cancelAlert();
}
#Override
public void onCreate() {
super.onCreate();
mContext = getApplicationContext();
mDCCView =new DCCView(mContext);
}
App.realCancelAlert();
So when I call my custom dialog from MSG1002 class, the dialog appears and it works, but when i what to close it from the class App with the command line App.realCancelAlert(); it doesn't close, and I don't understand why, because when I debug it the flow continues until it get's to dismiss() and it executs it but it doesn't dissapear.
WARNING Fragment or activity that had shown a dialogue is responsible for closing it. No other class should be responsible for that. Otherwise, you are going down the route of memory leaks and code that is hard to maintain.
Why doesn't it close?
Inside of your App class in onCreate you instantiate an object of type DCCView and store it as a static variable of that class. Let us say that variable is now pointing to the memory address 0x1234.
Then somewhere else in the code you invoke constructor of MSG1002 class. It creates it's own instance of DCCView as new DCCView(App.getContext()); and stores it inside of MSG1002 class static variable. Let us say that variable is now pointing to the memory address 0x5678.
These variables MSG1002.mDCCView and App.mDCCView are two absolutely different variables that hold references to two different instances of mDCCView. That is why they have different addresses 0x1234 and 0x5678. By attempting to close App.mDCCView you do not close MSG1002.mDCCView dialogue.
How to fix?
Note: strongly recommend to go away from holding a static reference to something related to UI as it holds the reference to Context value and prevents it from being garbage collected when it should be. That is memory leak.
Make private static DCCView mDCCView; public or create get/set methods;
public class App extends Application{
public static DCCView mDCCView;
...
Remove private static DCCView mDccView; from MSG1002 class;
Update MSG1002 class to use App.mDccView:
public class MSG1002{
public MSG1002() {
Handler hnd = new Handler(App.getContext().getMainLooper());
hnd.post(() -> {
App.realCancelAlert();
App.mDccView = new DCCView(App.getContext());
});
}
public void process(){
App.mDccView.showDCC(transactionCurrency, transA, dccCurrency, dccAmount, dataUserDisplay, (DCCView.Response response) -> {
onDccResponse(response, socketCliente);
});
}
...
}
More about memory leaks: memory leak in android, stack overflow issues on dialogues causing memory leaks (9270 results).
Related
So I have this "middle man" nonactivity class, where I want to get a string path from an activity class. Then, from my nonactivity class send that string path to a different activity?
Activity A
#Override
public void onCreate(Bundle savedInstanceState)
{
Intent imageToFactory = new Intent(this,NonActivity.class);
imageToFactory.putExtra("yourImage", user_image_path);//I already set user_image path
}
NonActivity
public class NonActivity
{
private Intent grabImagePath = new Intent();
private String grabImagePathString = getIntent.getStringExtra("yourImage");//this obviously gives an error but for the example
public String grabUserImage()
{
return grabImagePathString;
}
}
Activity B
#Override
public void onCreate(Bundle savedInstanceState)
{
NonActivity nonActivity;
String example = nonActivity.grabUserImage();
}
So this method doesn't work for some reason, I think I have to use contexts some how but im not sure exactly how to use them, if anyone can help with examples or modify the example code i did below that'd be awesome!
You can build a static variable that can serve as message bridge, first thing you need to create a class and name it anything you like, in my case I will name the example class as Conn, then add a static HashMap.
public class Conn {
public static HashMap<String,String> storage = new HashMap<>();
}
To utilize this this class in your example:
Activity A
#Override
public void onCreate(Bundle savedInstanceState){
Conn.storage.put("yourImage",user_image_path_in_string);
}
Activity B
#Override
public void onCreate(Bundle savedInstanceState)
{
String example = Conn.storage.get("yourImage");
}
if you want to use third class ( here NonActivity.class ) for some reasons, just do it like this:
create globals class like this :
package helper;
public class Globals {
private static final Globals instance = new Globals();
private GlobalVariables globalVariables = new GlobalVariables();
private Globals() {
}
public static Globals getInstance() {
return instance;
}
public GlobalVariables getValue() {
return globalVariables;
}
}
and global variables class like this :
public class GlobalVariables {
public String grabImagePathString;
}
now in activity A::
Globals.getInstance().getValue(). grabImagePathString = "something......";
and in activity B::
String gtabImagePathString = Globals.getInstance().getValue(). grabImagePathString;
Good Luck
is it possible to get all activities in the application? i have a global integer variable that should be in the ActionBar of every activity. i thought something like this:
for (Layout/Activity l in (all activites)) {
l.setTitle(variable);
}
i already tried it with R.layout but this didnt work for me.
How can i do this or is there a better way to display my variable in all activity labels? later i want to call this code from my set method for the global variable.
There is only one activity running at a time, so you can’t get this kind of references.
Said that, I think the way to go it’s create an int static variable in some class, and called it from your activities.
//SomeClass
public static int xValue = 0;
//ActivityOne || ActivityTwo || ActivityThree ...
String text = String.valueOf(SomeClass.xValue);
SomeClass.xValue = 1;
Because it’s a public static variable, you don’t need to instantiate any object to get/set its value, and it will be accesible from any class. Furthermore, this value will be reachable as long as its class is in the memory, and destroy just when class gets unloaded.
yes it's possible with singleton.
This is how to use singleton:
This is Singleton class:
public class Singleton {
private static Singleton mInstance = null;
private String mTitle;
public void setmTitle(String mtitle){
this.mTitle=mtitle
}
public String getmTitle(){
return mTitle;
}
public static FilterArrayList getInstance(){
if(mInstance == null)
{
mInstance = new FilterArrayList();
}
return mInstance;
}
}
This is the first activity:
public class FirstActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Singleton.mInstance.setmTitle("This is Singleton");
}
}
and in second activity:
public class SecondActivity extends Activity {
String Title;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Title=Singleton.mInstance.getmTitle();
}
}
Friends In My Application , i want to use text box value in
all other activity without passing any argument. how it's possible? Anyone
know these give me a example, thanks in advance. by Nallendiran.S
There are a few different ways you can achieve what you are asking for.
1.) Extend the application class and instantiate your controller and model objects there.
public class FavoriteColorsApplication extends Application {
private static FavoriteColorsApplication application;
private FavoriteColorsService service;
public FavoriteColorsApplication getInstance() {
return application;
}
#Override
public void onCreate() {
super.onCreate();
application = this;
application.initialize();
}
private void initialize() {
service = new FavoriteColorsService();
}
public FavoriteColorsService getService() {
return service;
}
}
Then you can call the your singleton from your custom Application object at any time:
public class FavoriteColorsActivity extends Activity {
private FavoriteColorsService service = null;
private ArrayAdapter<String> adapter;
private List<String> favoriteColors = new ArrayList<String>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_favorite_colors);
service = ((FavoriteColorsApplication) getApplication()).getService();
favoriteColors = service.findAllColors();
ListView lv = (ListView) findViewById(R.id.favoriteColorsListView);
adapter = new ArrayAdapter<String>(this, R.layout.favorite_colors_list_item,
favoriteColors);
lv.setAdapter(adapter);
}
2.) You can have your controller just create a singleton instance of itself:
public class Controller {
private static final String TAG = "Controller";
private static sController sController;
private Dao mDao;
private Controller() {
mDao = new Dao();
}
public static Controller create() {
if (sController == null) {
sController = new Controller();
}
return sController;
}
}
Then you can just call the create method from any Activity or Fragment and it will create a new controller if one doesn't already exist, otherwise it will return the preexisting controller.
3.) Finally, there is a slick framework created at Square which provides you dependency injection within Android. It is called Dagger. I won't go into how to use it here, but it is very slick if you need that sort of thing.
I hope I gave enough detail in regards to how you can do what you are hoping for.
Create it static type and than you can get it where you want.
Private TextVeiw txtvw;
Public static String myText="";
myText=txtvw.getText();
Access this variable with class name in which it defined.
MyActivity.myString
I'm trying to track down a new null pointer exception which is appearing in my ACRA logs and which I can't reproduce. Here's the relevant code:
public class MyApplication extends Application {
public void onCreate() {
DataManager.instance().initializeData(this);
}
}
public class DataManager {
private static DataManger instance = new DataManger();
private List<DataModel> dataModels;
private List<I_Callback> callbacks = new ArrayList<I_Callback>();
private boolean isInitialized = false;
private DataManager(){}
public static DataManager instance() {
return instance;
}
public void initializeData(Context context) {
new DataManagerInitializer().execute(context);
}
public void setDataModels(List<DataModel> models) {
dataModels = models;
}
public void synchronized registerInitializeCallbacks(I_Callback callback) {
if (isInitialized) {
callback.executeCallback();
} else {
callbacks.add(callback);
}
}
public void synchronized setInitialized() {
isInitialized = true;
for (I_Callback callback:callbacks) {
callback.executeCallback();
}
callbacks.clear();
}
}
public class DataManagerInitializer extends AsyncTask<Context, Void, Void>{
protected Void doInBackground(Context... contexts){
List<DataModel> dataModels = new ArrayList<DataModel>();
/*various code to create DataModel objects and add to dataModels list*/
DataManager.instance().setDataModels(dataModels);
return null;
}
protected void onPostExecute(Void result) {
DataManager.instance().setInitialized();
}
}
public class ActivityA extends Activity implements I_Callback{
public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.graphical_layout);
DataManager.instance().registerInitializeCallbacks(this);
}
public void executeCallback() {
/* wire up button to call Activity B */
}
}
public class ActivityB extends Activity {
public void onCreate(Bundle savedInstanceState) {
List<DataModel> dataModels = DataManager.instance().getDataModels();
/* The following line of code throws a null pointer exception
in the stack trace*/
for (int i=0; i < dataModels.size(); i++){
/* do something with the data model */
}
}
}
To break down the above more simply, the application is launched which kicks off the initializion of the data manager singleton. ActivityA, the main activity, launches and waits for the data manager to complete initialization before allowing any actions, wiring up any events, etc. From ActivityA, its not possible to get to ActivityB without the call back method executing and ActivityB is only reachable from ActivityA. The only way for the list of data models to be null in the DataManager is for it to not have been initialized, but I'm struggling to see how this is possible. Any suggestions on how my null pointer may have occurred?
private static DataManger instance = new DataManger();
...
public static DataManager instance() {
return instance;
}
Is where the problem is. So your instance variable is getting garbage collected. As it is instantiated when it is declared, it is not being appropriately re-instantiated. So, try this instead:
private static DataManger instance = null;
...
public static DataManager instance() {
if (instance == null){
instance = new DataManager();
}
return instance;
}
This will ensure the call to instance() (usually called getInstance() but this is only convention), will return a valid single instance of the datamanager. Try to avoid instantiating global variables with their declaration, to avoid this specific problem.
Let's assume that:
you are interacting with the Activity B
press the home button:
start playing with other apps (consuming memory)
at some point the so needs memory and it's gonna start garbage collecting objects, included your "instance".
If that happens when you launch your app the framework will resume the activity B and the npe will happen.
You need to re-create the instance (in the activity B) if it is null.
I have an activity which creates an object instance of my class:
file MyActivity.java:
public class MyActivity extends Activity {
TextView myView = (TextView)findViewById(R.id.myView);
...
Points myPoints new Points();
...
}
--------------------------------------------------------------
file Points.java:
private class Points {
...
HOW TO USE myView HERE ???
...
}
--------------------------------------------------------------
How do I use the UI objects in my class (which does not extend an
Activity)? Should I pass some context to my Points class? How do I do, exactly?
see you post, i've edited it , to fix the problem
hope it helps :=)
here is the Edit :
file MyActivity.java:
public class MyActivity extends Activity {
TextView myView ;
protected void onCreate(android.os.Bundle savedInstanceState) {
myView = (TextView)findViewById(R.id.myView);
Points myPoints = new Points(this);
myPoints.displayMsg("Hello World !!!");
}
}
--------------------------------------------------------------
file Points.java:
private class Points {
protected MyActivity context;
//add a constructor with the Context of your activity
public Points(MyActivity _context){
context = _context;
}
public void displayMsg( final String msg){
context.runOnUiThread(new Runnable() {
#Override
public void run() {
context.myView.setText(msg);
}
});
}
}
Your Points can't be a private class without being an inner class. So your code doesn't even compile...
Pass the view as parameter to the constructor of your Points class:
public class MyActivity extends Activity {
TextView myView = (TextView)findViewById(R.id.myView);
Points myPoints new Points(myView);
private class Points {
public Points(TextView view) {
// todo
}
}
}
You should do everything and pass back the value to the activity to handle UI instead of doing any UI related stuff in the point stuff.
You can pass the main Activity's context (using Points(getApplicationContext());) to the class as a constructor parameter. You could also pass the specific UI elements you want to manipulate.
A better way to do it, however, may be to have Points not know about the Activity. Have your Activity call Points methods and take the necessary actions based on the method output.
You could just pass the view to your class.
Points myPoints = new Points(myView);
private class Points
{
private TextView mTextView;
Points(TextView textView)
{
this.mTextView = textView;
}
}
i was in same trouble..
i found the simple way..
make a static variable and function ...
call from other class..
TestActivity.java
public class TestActivity extends Activity {
static EditText edit_text1;
public void onCreate(Bundle savedInstanceState)
{
.....
edit_text1 = (EditText) findViewById(R.id.edit_text1);
.....
}
public static void setMSG(String str)
{
edit_text1.setText(str);
}
}
Test2.java
TestActivity.setMSG("this is text");
Could work using an interface
file MyActivity.java:
public class MyActivity extends Activity implements Points.MyListener {
TextView myView;
... onCreate(...){
myView = (TextView)findViewById(R.id.myView);
Points myPoints = new Points();
//pass in MyActivity's instance of the listener
myPoints.addListener(this);
}
#Override
public void updateTextView(String message){
myView.setMessage(message);
}
}
file Points.java:
public class Points {
public Points(){
}
public interface MyListener{
void updateTextView(String message);
}
MyListener myListener;
public void addListener(MyListener listener){
myListener = listener;
}
public void updatePoints(){
//do some operations in calculatePoints()
String points = calculatePoints();
//update views using MyActivity's implementation of updateTextView()
myListener.updateTextView(points);
}
}
Doing it this way, events can be fired / messages sent, for lack of better terms, from the external class to update the Activity UI. This might be overkill if all sb need is to call a method in the Points class that returns something