I'm trying to pass something from one class to my MainActivity, but it doesn't seem to work, I don't understand why.
I have my GPS Tracker on another class (not the MainActivity) in order to reuse it.
When the location changes, I want my other class to call a method from within the MainActivity to update my UI.
I summarized my code like that :
My MAIN ACTIVITY :
public class MainActivity extends Activity implements OnClickListener {
TextView tv;
EditText et;
Button btun;
int arg0;
int stuff;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.tv);
et = (EditText) findViewById(R.id.et);
btun = (Button) findViewById(R.id.btun);
btun.setOnClickListener(this);
}
private void setter(int stuff) {
tv.setText(stuff);
}
public void setText(int _stuff) {
_stuff = stuff;
setter(_stuff);
}
#Override
public void onClick(View v) {
Getter get = new Getter();
get.getInfo(Integer.parseInt(et.getText().toString()));
}
The other Class :
public class Getter {
int _getString;
MainActivity main = new MainActivity();
public void getInfo(int getString) {
_getString = getString * 8;
main.setText(_getString);
}
}
I end up having a NullPointerException in my LogCat
at :
- tv.setText(stuff);
- setter(_stuff);
- main.setText(_getString);
- get.getInfo(Integer.parseInt(et.getText().toString()));
and I don't really know why, and above all, how to fix it.
I'll appreciate any help !
(PS : My GPS tracker thingy is working fine, it's just about invoking my setter() method.
Instantiaing an Object of MainActivity doesn't automatically call onCreate method but this method is called when you start an activity using Intent; And using the same intent you can pass extra values. For example:
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra("key", value);
context.startActivity(intent);
and then in your main activity onCreate method:
String value = getIntent.getStringExtra("key");
Edit:
In your case why don't you change your void getInfo(int getString) to return a String value i.e.
public class Getter {
...
...
public String getInfo(int getString) {
_getString = getString * 8;
return Integer.toString(_getString);
}
}
and then in onClick event of MainActivity bind this returned text to TextView
It's maybe because the MainActivity's onCreate()-Method hasn't been called. Therefore the tv is still null causing the NullPointerException
One problem is here. main is an Activity, but it should be the MainActivity calling this object.
public class Getter {
int _getString;
MainActivity main = new MainActivity();
public void getInfo(int getString) {
_getString = getString * 8;
main.setText(_getString);
}
}
I cannot really make out what you are trying to achieve in the Getter class, but either:
1: Pass the Activity instance to the object
public class Getter {
int _getString;
MainActivity _main = null;
public Getter(MainActivity main) {
_main = main;
}
public void getInfo(int getString) {
_getString = getString * 8;
_main.setText(_getString);
}
}
#Override
public void onClick(View v) {
Getter get = new Getter(this);
get.getInfo(Integer.parseInt(et.getText().toString()));
}
or
2: set the text in the Activity and only get the value from the Getter (My choice)
public class Getter {
int _getString;
MainActivity main = new MainActivity();
public void getInfo(int getString) {
return getString * 8;
}
}
#Override
public void onClick(View v) {
Getter get = new Getter();
int info = get.getInfo(Integer.parseInt(et.getText().toString()));
setText(Integer.toString(info));
}
Use Application Class or create a separate Class and declare a static variable in it. Use getter & setter methods to get the value. To update the Textview in mainacivity from other class pass the texview reference variable from main activity and put null check condition in other class if textview is not null then update the value.
Related
My app doesn't display anything when passing data from one class to another. I located through with the debugger that my ArrayList doesn't get the right value from the class.
I'm sending data with the following function:
public class Adaugare extends AppCompatActivity {
private ListView myListView;
private NumeAdapter numeAdapter;
String inume;
int ivarsta;
Intent intent = new Intent();
private ArrayList persoanaArrayList = new ArrayList<>();
public ArrayList getPersoanaArrayList() {
return persoanaArrayList;
}
public int getPersoanaArrayListsize() {
return persoanaArrayList.size();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_adaugare);
myListView = (ListView) findViewById(R.id.persoana_list);
Button btn_fin = (Button) findViewById(R.id.btn_fin);
btn_fin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
EditText nume_edit_text = (EditText) findViewById(R.id.ins_nume);
EditText varsta_edit_text = (EditText) findViewById(R.id.ins_var);
ivarsta = Integer.parseInt(varsta_edit_text.getText().toString());
inume = nume_edit_text.getText().toString();
persoanaArrayList.add(new Persoana(inume, ivarsta));
}
});
}
}
And recieving it with:
public class Afisare extends AppCompatActivity {
ListView myListView;
NumeAdapter numeAdapter;
Adaugare ad = new Adaugare();
int cate;
int i;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_afisare);
myListView = (ListView) findViewById(R.id.persoana_list);
ArrayList<Persoana> persoanaArrayList = new ArrayList<Persoana>(ad.getPersoanaArrayList());
numeAdapter = new NumeAdapter(this, persoanaArrayList);
myListView.setAdapter(numeAdapter);
}
The class Persoana is:
public class Persoana {
private String nume;
private int varsta;
Persoana(String inume, int ivar) {
this.nume = inume;
this.varsta = ivar;
}
public String getNume() {
return nume;
}
public int getVarsta() {
return varsta;
}
public void setNume(String nume) {
this.nume = nume;
}
public void setVarsta(int varsta) {
this.varsta = varsta;
}
}
Persoana is the main class, everything is saved in it. ad is an object of Adaugare, Adaugare being the class from which I've taken the code for getPersoanaArrayList. At debugging some values appeared at ad, namely Adaugare #4556, and persoanaArrayList remains null.
I need the persoanaArrayList so that i can initialize my Adapter and listView. Everything else in the code seems fine from step by step testing with debugger.
Your problem is with the following line in the Afisare class:
Adaugare ad = new Adaugare();
You can't simply new one activity from another activity and expect to access a shared list between them. To share instance data between java objects you need a reference to the other object. Creating a new instance will create a new empty list. That's why you are "losing" data. A quick fix would be to make the list static so it can be accessed from any instance.
But since you're dealing with Android, the right way to share data between activities is by using intent extras. The first activity starts the second activity via an intent. The first activity places the desired data in the intent as extras. The second activity uses getIntent() and the various methods on Intent to access the extras.
One last tip, in Android, you never use the new operator with Activities. Activities are created by the system to service an intent. If you find yourself using the new operator, that's a sign that you're doing something wrong.
How can i send data from an activity to a class ?
I tried to pass a String using getter but this gives me the initial value of the variable , but my String's value changes in my onCreate. Any ideas how can i pass it to my class ?
Here is some code :
public class MainActivity extends AppCompatActivity {
private String global ;
public String getGlobal() {
return global;
}
...
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
global = String.valueOf(parent.getItemAtPosition(position));
}
});
}
And here is my class
public class SimpleVar {
MainActivity mainActivity = new MainActivity() ;
String data = mainActivity.getGlobal; }
Any help will be much appreciated. Thank you in advance !
global is not actually "global"
Each instance of the Activity has its own string, and the OS can decide to kill your Activity at any time and recreate it, so therefore don't rely on a variable from an Activity within another class.
Secondly, never ever make a new Activity. That is no longer tied to the Activity that you would eventually click the button on.
It's hard to determine what you really need, but this is more correct.
public class SimpleVar {
String data;
}
With the Activity sending data to it
private SimpleVar var;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
var = new SimpleVar();
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
var.data = String.valueOf(parent.getItemAtPosition(position));
}
});
}
If you need that object elsewhere, you need to pass it around to those classes from this Activity
try to make constructor for your class
public class SimpleVar {
private String data;
public SimpleVar(String data) {
this.data = data;
}
public void setData(String data) {
this.data = data;
}
}
then in your activity new the class and then set data to it
You should not create new mainactivity in your class.
When on instantiating the class pass to it a reference to Activity in which the class was created. Reference to Activity should be kept in a weakreference. Then You can make a getter in the Activity and call it from Your class.
Or You can do the opposite - keep reference to the instantiated object in the Activity. Use setter from the activity to pass new values to the object.
public class MainActivity extends AppCompatActivity {
public ShareData SD = new ShareData();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SD.set_numb(5);
}
// when button clicked
public void noviEkran(View view){
Intent i = new Intent(this,klasaB.class);
startActivity(i);
}
}
public class ShareData {
private int number;
public ShareData(){
this.number=0;
}
public void set_numb(int num){
number = num;
}
public int get_numb(){
return number;
}
}
public class klasaB extends Activity{
ShareData sd;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int i =sd.get_numb();
System.out.println("Saved numb:" + i);
}
}
My question is, if i declare object in 1st class, and set its parameter number to 5, how to acces this number from other class because now my apk crashes when reading " int i =sd.get_numb(); " in class "klasaB".
Any suggestion how to make this work?
ps: i dont want to use static variables, or putExtra with Intents.
If data is simple/primitive then use Intent to pass data from one activity to another. That is what Intent is for.
If it is not (some sort of complex data structure or object), I would extend Application, by making a custom sub class. Application class (as the name implies) is accessible to all Activities, even when app transitions from one to another. Below is a very simple example, just to show you the idea. You can modify/adjust that to your needs.
public class MyApplication extends Application {
private X x;
public static void setX(X x) { ... }
public static X getX() { ... }
}
public class ActivityA extends Activity {
...
MyApplication.setX(x);
}
public class ActivityB extends Activity {
...
X x = MyApplication.getX();
}
You may have mixed up Activity/MainActivity/AppCombatActivity inheritance... I suspect that the reason you are seeing the error -- by the way, please look into "how to ask" and include a bit more information next time -- is that sd in klasaB is never initialized.
MainActivity.SD will hold that 5 after its onCreate(), whereas klasaB.sd is never set to anything.
You never reference or instantiate SD in class B. To get the data to ClassB you will need to set the data as an extra in the intent. Most classes cannot be sent in the intent, so for your case you should pass the primitive types of the object, then create the object.
// when button clicked
public void noviEkran(View view){
Intent i = new Intent(this,klasaB.class);
i.putExtra("TAG", SD.get_num());
startActivity(i);
And then in Class B
ShareData SD = new ShareData();
SD.set_num(getIntent.getIntExtra("TAG", 0);
You can access your class object either using implements Serializable or Parcelable
1.Implement serializable into your ShareData class
public class ShareData implements Serializable{
private int number;
public ShareData(){
this.number=0;
}
public void set_numb(int num){
number = num;
}
public int get_numb(){
return number;
}
}
2.create object of SharedData and share with intent to classB
public class MainActivity extends AppCompatActivity {
public ShareData SD = new ShareData();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SD.set_numb(5);
}
// when button clicked
public void noviEkran(View view){
Intent i = new Intent(this,klasaB.class);
i.putExtras("key", SD)
startActivity(i);
}
}
3.Access in classB
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ShareData sd = (ShareData)getIntent().getSerializableExtra("key").
System.out.println("Saved numb:" + sd.get_num());
}
Use a singleton class
Declare an instance in ShareData class:
public class ShareData {
private static ShareData sdInstance = null;
...}
add this method in ShareData class:
public static ShareData getInstance(){
if(sdInstance == null){
sdInstance = new ShareData();
}
return sdInstance;
}
To get same object in other classes , use this
ShareData sd = ShareData.getInstance();
now you will receive same sd.get_numb()
I want to modularize the usage of my class but I have problem in passing function. I want to be able to pass an OnClickListener from 1 activity to this CoachmarkActivity.
I tried 2 different method:
1. Passing an OnClickListener to Intent
2. Passing a class, FollowUpClass, implements Serializable, which has method onClick.
You can see the code below. It is not complete code, but you should be able to comprehend this.
public class CoachmarkActivity extends Activity {
public static final String RES_LAYOUT = "RES-LAYOUT";
public static final String LISTENER = "LISTENER";
public static final String FOLLOW_UP = "FOLLOW-UP";
#Override protected void onCreate(Bundle savedInstance) {
setContentView(getIntent.getIntExtra(RES_LAYOUT, R.layout.activity_default))
Button button1 = (Button) findViewById(R.id.button1);
Button button2 = (Button) findViewById(R.id.button2);
// 1ST ATTEMPT
// I want to modularize this
OnClickListener onClickPassedFromIntent = (OnClickListener) getIntent().getSerializableExtra(LISTENER);
button1.setOnClickListener(onClickPassedFromIntent);
// 2ND ATTEMPT
final FollowUpListener folllowup = (FollowUpListener) getIntent().getSerializableExtra(FOLLOW_UP);
button2.setOnClickListener(new OnClickListener() {
#Override void onClick() {
// !! Here is error, exception thrown
folllowup.onClick();
}
});
}
/**
* Public method to be used in other activity.
* Invocation wanna be:
* CoachmarkActivity.startThisActivity(getActivity(), R.layout.coachmark1, new OnClickListener() {
* #Override void onClick() {
* // Do something
* }
* });
*/
public static void startThisActivity(Context context, int resId, OnClickListener listener) {
Intent intent = new Intent(context, CoachmarkActivity.class);
intent.putExtra(RES_LAYOUT, resId);
// !! Line below is error, onClickListener is not serializable, no method can accomadate below
intent.putExtra(LISTENER, listener);
context.startActivity(intent);
}
/**
* Public method to be used in other activity.
* Invocation wanna be:
* CoachmarkActivity.startThisActivity(getActivity(), R.layout.coachmark1, new FollowUpListener() {
* #Override void onClick() {
* // Do something
* }
* });
*/
public static void startThisActivity(Context context, int resId, FollowUpListener folllowup) {
Intent intent = new Intent(context, CoachmarkActivity.class);
intent.putExtra(RES_LAYOUT, resId);
intent.putExtra(FOLLOW_UP, followup);
context.startActivity(intent);
}
}
The abstract class:
public abstract class FollowUpListener implements Serializable {
public abstract void onClick();
}
The problems are stated in the comment in source code above, with tag "!!" (Just CTRL+F "!!"). What I want to do is like passing a Delegate object (function in form of variable) in C#, but in Android Java.
Any idea? Thanks.
You are trying to add a Serializable extra to your Intent, but OnClickListener does not implement that interface. You can achieve what you want by creating a class that implements both of the interfaces you need.
private class SerializableClickListener implements View.OnClickListener, Serializable {
#Override public void onClick() {
// TODO handle click
}
}
However, just because you can doesn't mean you should. Sending a click listener to another activity is a horrible code smell, and you should really rethink how you could do this via Intents/Broadcasts.
I tried to pass the OnlclickListener and I couldn't. then I tried this solution.
I made a static click listener variable in a GlobalData class
public static View.OnClickListener btn;
Then when I call the startactivity to go to another activity I did this.
GlobalData.btn = new View.OnClickListener() {
#Override
public void onClick(View v) {
//Listern action
}
};
c.startActivity(new Intent(c, DialogActivity.class));
Then in the second activity, I can set the static listener reference which I used to assign a listener object in the first activity.
b1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(GlobalData.btn!=null){
GlobalData.btn1.onClick(v);
}
finish();
}
});
I didn't use it directly as a parameter so I can do other stuff in the second activity listener. this worked for me.
But you have to think more because you are using a static reference. this is not a 100% solution. but it's worth trying.
Sorry if this question might be stupid for you, but I'm new to Android programming and I can't wrap my head around Java syntax.
Can you explain what is happening with this line of code step by step?
View.OnClickListener ourOnClickListener = new View.OnClickListener() {
#Override
public void onClick(View v){
ourMessage.setText(“The button got tapped”);
}
};
There is an interface declared inside View class, and it's OnClickListener, it looks like this in View.java source:
/**
* Interface definition for a callback to be invoked when a view is clicked.
*/
public interface OnClickListener {
/**
* Called when a view has been clicked.
*
* #param v The view that was clicked.
*/
void onClick(View v);
}
Normally you would create a class, and have it implement this interface:
public void MyClass implements View.OnClickListener {
#Override
public void onClick(View view) {
// do stuff
}
}
But sometimes you don't need this class in a separate file. Instead, you can create anonymous inner class, it's like creating new class, which only methods are the one from the interface specified:
new View.OnClickListener() {
#Override
public void onClick(View v){
ourMessage.setText(“The button got tapped”);
}
}
You can then use instance of this class everywhere the View.OnClickListener interface is needed.
What's also worth mentioning is that anonymous inner class will hold a reference to the class in which you're creating it. So this will be legal and valid:
public class MyClass {
private int clicksCount = 0;
private View.OnClickListener listener = new View.OnClickListener() {
#Override
public void onClick(View view) {
clicksCount += 1;
}
}
}
Here you can access clicksCount field, which is field of MyClass even from the inner class that implements OnClickListener. Side note - if you want to access a variable, you need to add final modifier to it:
public void testMethod(final int canAccess, int cantAccess) {
final String test = otherView.getText().toString();
myView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Cannot access cantAccess, because it's not final
if (test.length == 0) { // can access
// do something
}
}
}