Creating Object from other class - android

I have a settings screen where you can choose between, add and remove configurations for the app.
When adding a configuration, I create a new Instance of a inputBox Class (extending the settings activity class - where I stored the procedure for the standard android text input box) to query the name for the new configuration.
In the Onclick of this inputbox a procedure from the superClass (the settings-activity) is called to create a new configuration object.
This Procedure queries some things from the activity (e.g. selected spinner element) including the progress of a seekBar.
This is where I get a NPE:
java.lang.NullPointerException: Attempt to invoke virtual method'android.view.Window$Callback android.view.Window.getCallback()' on a null object reference
The same object creation procedure is also called on initialization of the app and works just fine.
I understand from the Error that the issue is that when calling the procedure from a child class the reference of the variables to the corrseponding elements of the screen is not set anymore - and therefore cannot be queried.
So the question:
How can I query values of activity elements, when the procedure is called from another class?
I know that the topic is quite broad, but I can't figure it out for a couple of days now
Thanks for your help in advance.
Here is a scheme of the problem:
public class Settings extends AppCompatActivity{
Context settingsContext = this;
private Spinner someSpinner;
//other elements
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
someSpinner = (Spinner) findViewById(R.id.someView);
//other elements
addNewConfig.setOnClickListener((v) --> {
inputBox inputBox = new inputBox("OK", "Cancel", settingsContext, "sourcePath",1,1);
newConfigName = inputBox.show();
});
public sSetting makeNewConfig(String name, String sourcePath, int dataFrom, int dataTo){
sSetting newConfig;
newConfig = new sSetting("NAME", someSpinner.getProgress()>0, ...);
return newConfig;
}
}
And the inputBox:
public final class inputBox extends Settings {
//someVars
inputBox(String buttonOk, String buttonCancel, Context setContext, String sourcePath, int dataFrom, int dataTo){
//variable setters
}
private String show() {
//show msgbox
//onclick ok
super.makeNewConfig(....);
}

For solving the problem I restructured my Project a little:
I removed the inputBox-Part, which, after some research considered for a too complicated solution for what I needed anyway.
However: I now added a editText to my Settings View.
Although I had to change my Settings view for this, it now looks better and it was ridiculously easy to edit the configuration name for the user.
I think in most cases that will do the trick. Adding Popup-Boxes just needs more error handling and makes the design more complicated
I hope this helps ;)
If you need the code for it it is available here:
GitHub - AIM

Related

How to get data from First Fragment to Last Fragment?

I have multiple fragments in ViewPager. How can i get fragment first EditText Data to last Fragment?
I have set value in my first fragment like below -
txtConsAcNo.setText(account_no);
txtMeterSrMo.setText(mtr_serial_no);
Now i am getting this txtConsAcNo, txtMeterSrMo value on my last fragment like below-
ConDetFirstFragment f1 = new ConDetFirstFragment();
txtConsAcNo = f1.txtConsAcNo.getText().toString();
txtMeterSrMo = f1.txtMeterSrMo.getText().toString();
Now what i want that i am getting Null value and my app get unfortunately stopped. i want to get this data to my last fragment without bundle. how can i achieve this ?
Very Easy to Achieve this without Creating Interface, Bundle or intent -
I have declared all the variables in all the fragment "Public Static" like Below -
public static EditText txtConsAcNo, txtMeterSrMo;
After on any fragment i have declared variable to get data like below-
public static String txtConsAcNo,txtMeterSrMo;
Now i have created function to get value from first fragment in above variable below-
public static void getalldata(){
ConDetFirstFragment f1 = new ConDetFirstFragment();
txtConsAcNo = f1.txtConsAcNo.getText().toString();
txtMeterSrMo = f1.txtMeterSrMo.getText().toString();
}
Happy Coding...
There are a couple of problems here:
The first fragment may have been destroyed by the Android system to conserve memory.
Your fragments should not talk to each other directly
To achieve what you need, you need to jump through a few hoops.
Assuming that the source texts are EditText objects (ie. editable by the user), then add a TextWatcher to each of the EditText objects.
Create an Interface:
public interface TextPurveyor {
void setText1(String t);
String getText1();
void setText2(String t);
String getText1();
}
Implement this interface in the host Activity; and save the text values locally in the activity. Don't forget to save/restore them with the rest of the Activity state.
Make the TextWatcher objects call the appropriate setText(..) methods on the host activity:
((TextPurveyor)getActivity()).setText1(...);
Make each fragment check that the host activity implements this method.
When the second fragment wants a string, ask the activity for it:
((TextPurveyor)getActivity()).getText1();
To avoid coupling your project code tightly, try to use the design patterns that have been proven to work best like the Publisher/Subscriber as I will show you below:
There is a popular library I have always used in my projects called EventBus - just add the following to your build.gradle (module-level) file under dependencies :
compile 'org.greenrobot:eventbus:3.0.0'
Secondly, create a simple Plain Old Java Object (POJO) to represent your Event:
public class FragmentAToLastEvent{
private String txtConsAcNo;
private String txtMeterSrMo;
FragmentAToLastEvent(String acNo, String srMO){
this.txtConsAcNo = acNO;
this.txtMeterSrMo = srMO;
}
//getters and setters if needed
public String gettxtConsAcNo(){
return txtConsAcNo;
}
public String gettxtMeterSrMo(){
return txtMeterSrMo;
}
}
Next step is to actually use your Event class here:
So, in your fragment that you want to send text from EditText, simply do this:
String txtConsAcNo = f1.txtConsAcNo.getText().toString();
String txtMeterSrMo = f1.txtMeterSrMo.getText().toString();
EventBus.getDefault().post(new FragmentAToLastEvent(txtConsAcNo, txtMeterSrMo));
In your last fragment, simply do this to complete:
Inside onCreate or onAttach of your Fragment:
//register your event - making this class a subscriber
EventBus.getDefault().register(this)
//next, override a single method to receive the values you passed from above code (Fragment 1?)
public void onEvent(FragmentAToLastEvent event){
String txtConsAcNo = event.gettxtConsAcNo();
String txtMeterSrMo = event.gettxtMeterSrMo();
//now you can use your text here without problems!
}
Finally, remember to unregister inside onDestroy:
#Override
public void onDestroy(){
super.onDestroy();
EventBus.getDefault().unregister(this);
}
This is what I have always done and it is cleaner, without using interfaces that your fragments MUST implement and do all that!
I hope you find it helpful to you and good luck!

How do I overcome this static vs. non-static method runaround?

I've used this quick-and-dirty msgbox (long live VB) routine extensively with Swing, for both debugging and user info messages:
public static void msgbox(String s){
javax.swing.JOptionPane.showMessageDialog(null, s);
}
I'm just beginning to learn about Android app development. I found Toast in my textbook as being a quick-but-awkward way to show info to the user. Here's the book's code:
String selected="...whatever...";
Toast toast=Toast.makeText(getApplicationContext(),selected,Toast.LENGTH_SHORT);
toast.show();
So I wrote this:
public void msgbox(String message)
{
android.widget.Toast.makeText(getApplicationContext(),
message,
android.widget.Toast.LENGTH_SHORT)
.show();
}
It worked the first time I used it when I only had one class, MainActivity. Then I tried to use it with a Fragment as follows:
public class FragmentA extends Fragment {
public View onCreateView(LayoutInflater
inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_a, container, false);
MainActivity.msgbox("Fragment A"); // **********************************
Button button = (Button) v.findViewById(R.id.button1);
//...
return v;
}
}
The error on the msgbox line is Non-static method msgbox cannot be referenced from a static context.
So I added static to the declaration for msgbox, which seemed like a good idea since that's how my Swing version of msgbox is declared:
public static void msgbox(String message)
{
android.widget.Toast.makeText(getApplicationContext(), // ********************
message,
android.widget.Toast.LENGTH_SHORT).show();
}
That makes the original error go away, but it's replaced by Non-static method getApplicationContext cannot be referenced from a static context.
To fix that error, I changed the declaration for msgbox to include a Context:
public static void msgbox(Context c, String message)
{
android.widget.Toast.makeText(c, message, android.widget.Toast.LENGTH_SHORT)
.show();
}
That works and makes perfect sense, but my quick-and-dirty string-parameter-only call to msgbox has now vanished. I now have to call msgbox like this from main ...
msgbox(getApplicationContext(), "onCreate; about to show fragment A");
... and like this from a separate class: ...
MainActivity.msgbox(getActivity(), "Fragment A");
I tried passing null to Context, which works with Swing JOptionDialog, but I get null pointer exception with makeText, whose first parameter (I thus found out) is documented as #NonNull.
Is there a method other than getApplicationContext and getActivity that I could use as the first parameter to makeText that would allow me to make msgbox static?
Or do I just have to suffer through supplying a Context parameter?
On the other hand, since it possible to do so with Swing, does anybody have a static one-String-parameter msgbox-type method to share? It doesn't have to use makeText.
(I struggled a long time to get as comfortable as I thought I was with Java. Android is every bit as daunting and is making me question what the heck I know ....)
I haven't tried this, but consider subclassing Application, and have it construct a static 'singleton object', giving it the application context. Then put your 'msgbox' method in the singleton.
Context is an extremely important concept in Android. I suggest you read up on it.
To answer the question, I would highly recommend you put that method to make the Toast in your Fragment. Use getActivity() for your context. If you want, you could make a static method in a Utils class that takes Context as a parameter. Then, access it from your Activity or your Fragment and just pass in this or getActivity(), respectively.

Passing value from static class to non static (android)?

I've successfully passed a value from a static class to a non-static one, but I got an error, null value, when I put that value to an EditText.
public class HelloBubblesActivity extends SherlockFragmentActivity {
public EditText editText1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_discuss);
editText1 = (EditText) findViewById(R.id.editText1);
}
public static class MyDialogFragment extends SherlockDialogFragment {
//i fill variable emotx is "test string"
public void emot(String emotx){
HelloBubblesActivity hb=new HelloBubblesActivity();
hb.smiley(emotx); //send value to smiley method..
}
}
public void smiley(String name){
Log.d("test", name); //result value is "test string" (success)
editText1.setText(name); //here is error
}
}
I'm not sure why I'm getting this issue. Can anyone see why this is not doing what is expected?
HelloBubblesActivity hb=new HelloBubblesActivity();
hb.smiley(emotx); //send value to smiley method..
Creates a new HelloBubblesActivity object but doesn't call onCreate and hence does not assign anything to editText1. Fields that have never been assigned are null in Java.
(Of course, to say the code is not doing what is "expected" would be wrong -- it's doing exactly what one would expect from the scenario.)
(Your mistake is most likely in thinking that setting a value in ANY HelloBubblesActivity object makes the value appear in ALL HelloBubblesActivity objects. Individual objects do not share instance fields, and what you set in one object does not magically appear in another. You can't just create an object of some class and expect it to have some sort of paranormal communications with others of it's class.)
(But this is a common mistake made by those who are dumped into OOP without a good background in assembler programming, et al.)

Static Keyword , Reinstallation Required

In my application I have an Activity" Model" in which i get a value 'n' from an edit text , I have declared this value n as static int . So , that i can access it inside any class of the Application.
The problem is that when I restart my application without reinstalling it , the value of 'n' remains the same as it was in the first case . And this affects my output.
I cannot use intent to send values because , the value is accessed randomly in the application even in classes that are not activities.
Can u please tell , where I m wrong.??
package com.integrated.mpr;
import java.io.File;
import android.app.Activity;
import android.app.Dialog;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class Model extends Activity implements OnClickListener{
EditText etPos;
Button bmodel;
static int n;//static variable to be used in other classes
File folder ;
File subfolder;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.inputpage);
etPos = (EditText) findViewById(R.id.etpos);
bmodel = (Button) findViewById(R.id.bModel);
bmodel.setOnClickListener(this);
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch(v.getId()){
case R.id.bModel:
String check = etPos.getText().toString();
String check1 = etNs.getText().toString();
n = Integer.parseInt(check);
Intent openAlternative = new Intent("com.integrated.mpr.ALTERNATIVE");
startActivity(openAlternative);
break;
}
}
}
If i first install my app , and enter value in the edittext as 2 , the value of n =2 ; If second time i run my app without installing it , even if i enter 3 in the edittext , value of n remains 2
Where is the twist??
Kumar,
The behavior you are seeing is the result of using a static member. static members do not require an instance and are therefore set upon first access (regardless of whether an instance was created or not) and stays in memory until Android decides it is no longer valid. In essence, it is doing exactly what it was supposed to. The proper use of static variables is a topic of extensive discussion among veteran and novice programmers alike, but essentially always leads to "be choosy about where and how you use static members".
That said, your need to access this from another component is a common problem, however, and there are a number of ways to solve it. If you need to have each instance have a different value, then it should not be static. Instead you will have to find a way to pass the instance of the Activity.
If each instance need not be different, but the value need to change according to some other parameter, simply find the appropriate place to change the value. If you can access it from anywhere in your application, you may also change it from anywhere in your application.
Solution 1: Passing by Intent
This solution is useful when the information is subject to change and must be sent to another component and the classes that it uses exlusively. You may pass virtually any value via an Intent extra.
openAlternative.putExtra("MyValue", Integer.parseInt(check));
In your responding component, you may retrieve the value by:
Intent myIntent = getIntent();
int n = myIntent.getIntExtra("MyValue", 0); //0 is the default if no value is sent.
From here, you may easily pass the retrieved value to any class being utilized by that component. An example:
MyClass.setN(n);
Solution 2: Storing outside of the LifeCycle
A safer alternative is to move the value to an extended Application. This is not subject to UI or LifeCycle processing.
public class MyApplication extends Application
{
static int n;
}
Adjust your AndroidManifest.xml...
<application android:name=".MyApplication" ... >
<!-- All of your components -->
</application>
Now, you can set the variable this way:
MyApplication.n = Integer.parseInt();
And you can get it by
int myN = MyApplication.n;
This solution has gotten me through many a troubled day. However, it should really be used for non-instance related data.
Solution 3: The REALLY UNSAFE method
This solution only works if you can guarantee a single instance of the component. This requires that singleTask is set. Be very careful with this
Change n to non-static
int n;
Change Activity to Singleton
static private Model myInstance;
In OnCreate, set myInstance
myInstance = this;
Create a getter:
static public Model getStaticInstance()
{
return myInstance;
}
This is unreliable (at best) and can cause huge memory leaks if not managed correctly.
Hope this helps,
FuzzicalLogic

SharedPreferences and Application class

I have many shared preference for my app (mostly relating to color customization) and I'm unsure what the best method is to store/use them at runtime.
Currently I am doing something like this (with more or less preferences depending on the view) in every activity/fragment:
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getActivity());
int buttonbg = settings.getInt("buttonmenu_bg", 0);
int buttontxt = settings.getInt("buttonmenu_txt", 0);
int headerclr = settings.getInt("header", 0);
And then using those to set the various colors in the display. This seems like a lot of overhead to have to call the PreferenceManager each time and go through all that.
So I started looking at creating an application class, reading the preferences in once and using static variables from the application class in the activities/fragment to set the display.
My question is, are there any drawbacks or gotchas to doing this that I should consider before I venture further down the Application class path?
If you are not using so many static variables so this may not affect your application.But the problem with static variable may arise when your app goes to background and the app running on front requires memory so it may clear your static data,so when you will go to your app you may find nothing (null) in place of static data.
The purpose of the Application class is to store global application state or data (in memory of course), so your approach is correct. I've used it multiple times and it works like a charm.
What I usually do is to create a Map member variable and provide methods for getting and putting values into it, looks like this:
package com.test;
...
...
public class MyApp extends Application{
private Map<String, Object> mData;
#Override
public void onCreate() {
super.onCreate();
mData = new HashMap<String, Object>();
}
public Object get(String key){
return mData.get(key);
}
public void put(String key,Object value){
mData.put(key, value);
}
}
Then from my activities, I just do ((MyApp) getApplication()).get("key") or ((MyApp) getApplication()).put("key",object). Also, don't forget to set the android:name attribute in your manifest file, under the application tag:
<application
...
...
android:name="com.test.MyApp">
</application>
Is there any particular reason why you are not setting the display colors in res/values/styles.xml?

Categories

Resources