FindViewById cannot be referenced from static context - java

I am trying to access a method, that changes a text field in the UI, of an Activity from another Java file.
In Game.java (normal Java file in the background) I have some static variables that get changed over time. I want the changes in these variables to be reflected in the actual UI. Hence, I am trying to access the method "changeName" in DisplayMessageActivity.java which would reflect the corresponding changes (display_message_activity.xml).
This is the method in DisplayMessageActivity.java that I am trying to call from Game.java
public void changeName() {
TextView text = (TextView) findViewById(R.id.petname);
text.setText("" + Game.name);
}
To call DisplayMessageActivity.changeName() from Game.java, I have to change it to a static method.
public static void changeName() {
TextView text = (TextView) findViewById(R.id.petname);
text.setText("" + Game.name);
}
But doing that gives me an error "non-static method cannot be accessed from static context" for "findViewByID".
I even tried making an instance of DisplayMessageActivity.java in Game.java to access the "changeName" method without making it static. However that throws a nullPointerException at TextView text = (TextView) findViewById(R.id.petname);
How can I resolve this issue?

Create a static reference to DisplayMessageActivity in itself and initialize it in the onCreate().
public class DisplayMessageActivity {
DisplayMessageActivity instance;
#Override
public void onCreate() {
...
instance = this;
...
}
}
Then from Game.java you can access the non-static method using:
DisplayMessageActivity.instance.changeName();
EDIT: Btw, your NPE is being thrown because you created a new instance of DisplayMessageActivity which is not the one you are actually using.

Related

Change TextView text from another class using interface

I'm trying to make some utils functions to use in a bigger app later(download file from url, upload file to url etc)
So in MainActivity I have only 2 buttons that on click call static methods from Utils class.
However, I want on MainActivity to have some indicators of how things working on download/upload methods(connecting, connection success/fail, percent of download etc) so I put on MainActivity a TextView that will show that. I made an interface ICallback that contains void setConnectionStatus(String status) and from Utils class I use this to send to MainActivity the status.
Here are some parts of the code :
public class MainActivity extends AppCompatActivity implements ICallback {
Button btnDownloadDB, btnUploadDB, btnUploadPics;
TextView txtStatus;
ProgressBar pb;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Initialize stuffs
initViews();
//Setting listeners
btnDownloadDB.setOnClickListener(v -> {
txtStatus.setText(R.string.connecting);
pb.setVisibility(View.VISIBLE);
Utils.downloadFile(DOWNLOAD_DB, DB_FILE_NAME);
});
}
#Override
public void setConnectionStatus(String status) {
Log.d("MIHAI", status);
txtStatus.setText(status);
}
The interface :
public interface ICallback {
void setConnectionStatus(String status); }
And the Utils class :
public class Utils {
static ICallback callback= new MainActivity();
public static void downloadFile(String downloadURL, String fileName) {
IFileTransferClient client = ServiceGenerator.createService(IFileTransferClient.class);
Call<ResponseBody> responseBodyCall = client.downloadFile(downloadURL);
responseBodyCall.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Log.d("MIHAI", "connection ok");
callback.setConnectionStatus("Connection successful");
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d("MIHAI", "err...fail");
callback.setConnectionStatus("Connection failed. Check internet connection.");
}
});
}
The problem appear on MainActivity, when I try to set text of the txtStatus TextView getting a null reference error even if the txtStatus is initialized on initViews() method.
The Logs are working fine so I get the right status in MainActivity. I tried to initialize the TextView again in that function before seting the text and im getting : "java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.pm.ApplicationInfo android.content.Context.getApplicationInfo()' on a null object reference
at android.content.ContextWrapper.getApplicationInfo(ContextWrapper.java:183)"
Is there any chance to make this work?
Thank you for reading.
Kind regards,
Mihai
There are multiple problems with your solution but the main one is this line:
static ICallback callback= new MainActivity();
First of all, never hold a static reference to Activity, Fragment, Context or any Context related classes. These classes are either bound to a Context or represent the Context itself. You may leak memory this way. But that is the other problem.
What is the actual problem in your code is that new MainActivity() in Utils class creates an absolutely different instance of MainActivity that has nothing to do with MainActivity that is responsible for displaying your UI in the runtime.
What you should do instead is pass an instance of ICallback to the function as an argument:
public static void downloadFile(String downloadURL, String fileName, ICallback callback) {
...
}
And remove static ICallback callback= new MainActivity();.
Note: when you pass a callback object to a function make sure when it is called your Activity is not in a finished state.

findViewById throws null when called through an object

I have a function in main.java that uses some UI elements like spinner to textview.
public void updateNearByPeople() {
reportEventPeopleAroundSpinner = (Spinner) findViewById(R.id.peopleAround);
…
}
When I call this function from within class, it works fine.
But when I call this function from another class2.java through an object findViewById throws java.lang.NullPointerException
If I make the function and all variables in it static than it also works fine while calling from class2.java but it doesn’t work with object calls.
How can I solve this and made of object aware of the context?
In main.java:
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_view);
mainAppContext = this;
Main mainObj=new Main();
gMapObj.initiateMap(mainAppContext,mainObj, mapFrag);
}
In class2.java:
public boolean initiateMap(Context appContext, Main mainObj, MapFragment mapFrag) {
mainAppContext = appContext;
mainAppObject = mainObj;
…
mainAppObject.updateNearByPeople();
}
Main mainObj=new Main();
you can't do that. The activity needs to go through its lifecycle, to build up its view hierarchy. If you just instantiate it through the new operator, neither its onAttach or onCreate method will be called. It means that you can not access resources and views as well

updating UI thread while in asynctask

as the title states, im trying to update something in my UI thread while running an asynctask.. i've read quite a bit on asynctask and it seems i should be able to change a
variable from the onPostExecute() method. obviously this is not the case.
Here is my sample code:
TextView tv = (TextView) findViewById(R.id.thingsThatNeedToBeUpdated);
Login login = new Login();
login.execute(userName, password);
and here the the login class
public class Login extends AsyncTask<String, void, String>{
public String doInBackground(String... params){
logMeIn(params[0], params[1]);
}
public void onPostExecute(String update){
tv.setText(result); //this is not working!!
}
whats actually happening is tv is underlined red and eclipse says i need to create a local variable.. but i thought the onPostExecute is ran from the UI thread? confused :?
im trying to do what i found at this website. I'm not entirly sure what i'm doing and i would love a point in the right direction! thanks in advance.
This line here
TextView tv = (TextView) findViewById(R.id.thingsThatNeedToBeUpdated);
is obviously declared either
Outside of a method -which would result in tv being null or
In a method that isn't part of the AsyncTask- which would mean the
task doesn't have access to it
You should define it as a member variable (outside of a method)
TextView tv;
then initialize it inside of a method
tv = (TextView) findViewById(R.id.thingsThatNeedToBeUpdated);
This will give your task access to it as well as the rest of your class.
If your AsyncTask is a separate file than your Activity then you will want to see this answer on using an interface and create a callback to update the TextView in your Activity.
Place TextView tv; into the scope of the class and outside of the function. Leave tv = (TextView) findViewById(R.id.thingsThatNeedToBeUpdated); where it is. You should then be able to access tv from onPostExecute().
This is because the TextView variable tv is defined in another class that does not have Login as an inner class. If Login is an inner class of the class containing the variable tv, it should be able to see the variable tv.
An easy way to solve this would be to make your AsyncTask an inner class of your main class.
To bring your TextView instance into scope, pass your tv variable into your Login instance constructor and add the constructor and variable in as below.
public class Login extends AsyncTask<String, void, String>{
private TextView tv;
public Login(TextView tv){
this.tv = tv;
}
public String doInBackground(String... params){
logMeIn(params[0], params[1]);
}
public void onPostExecute(String update){
tv.setText(result); //this should work
}
}
You have to pass the variable to this instance, otherwise it is out of scope. You won't be able to access it unless you declare and instantiate a new variable within the Login class.

How to call non static method from main class

I just ran into this problem while coding android. If I have a non-static method (It has to be non-static for the code inside to work) in my main class, how am i supposed to call it from within another class, because obviously I can't create another instance of my main class without starting a new instance of the program?
public class MainActivity extends FragmentActivity {
public static String starttime = "";
public static String startdate = "";
public static String endtime = "";
public static String enddate = "";
public static boolean start = false;
}
public void setDateText() {
EditText TextStart = (EditText)findViewById(R.id.txt_start);
TextStart.setText(startdate + " at " + starttime, TextView.BufferType.NORMAL);
EditText TextEnd = (EditText)findViewById(R.id.txt_end);
TextEnd.setText(enddate + " at " + endtime, TextView.BufferType.NORMAL);
}
Any help on how to call the setDateText() method from another class?
Thanks in advance
Normally you can't call a non static method from a static type, so you would do:
MainActivity m = new MainActivity(); // No constructor needed in class def.
m.setDateText();
But, when the program starts, you're not giving your JVM anything to call at the start, so you need to add:
#Override
//the function called when activity is created
public void onCreate(Bundle savedInstanceState) {
//call the create fct. Of the base class
super.onCreate(savedInstanceState);
//load the layout specified in the layout.xml
setContentView(R.layout.main);
MainActivity m = new MainActivity();
m.setDateText();
}
This will be called when the activity is created.
Go to Android - A beginner's guide for more information.
Also watch your syntax, your method def is outside of your class def.
Without knowing which other class is trying to access the MainActivity instance, you will need to pass a reference of this instance to your other objects, probably by passing this into a constructor or method.
For example
public class MainActivity extends FragmentActivity {
public void someMethod() {
SomeClass someClass = new SomeClass(this); // pass this for callbacks
// ~ more
}
}
where SomeClass is a class where you need to call the MainActivity's setDateText method.
I am trying to understand the need for you to call the function from another activity. Your main activity is anyway not on the foreground, so if you call this function from there, date will not be shown. Once you finish the 2nd activity and you will be back to MainActivity, then only you need this function to be called.
If that is so, then you can use startActivityForResult() to start 2nd activity, and then pass the date information back to MainActivity through onActivityResult(). You can call this function in MainActivity itself.
If you have to invoke setDate() at the activity's launch, you can pass the date in the Intent when you launch the activity and pull the date in MainActivity's onCreate method.
If you have to invoke setDate() at a different time other than launch, you can send a broadcast from other activity/component and make MainActivity listen to the Broadcast and pull the date from the intent's data.

Android: Referring to a string resource when defining a log name

In my Android app, I want to use a single variable for the log name in multiple files. At the moment, I'm specifying it separately in each file, e.g.
public final String LOG_NAME = "LogName";
Log.d(LOG_NAME, "Logged output);
I've tried this:
public final String LOG_NAME = (String) getText(R.string.app_name_nospaces);
And while this works in generally most of my files, Eclipse complains about one of them:
The method getText(int) is undefined
for the type DatabaseManager
I've made sure I'm definitely importing android.content.Context in that file. If I tell it exactly where to find getText:
Multiple markers at this line
- Cannot make a static reference to the non-static method getText(int)
from the type Context
- The method getText(int) is undefined for the type DatabaseManager
I'm sure I've committed a glaringly obvious n00b error, but I just can't see it! Thanks for all help: if any other code snippets would help, let me know.
That's because getText is a method of Context. It does not matter if you import the Context class; what matters is that you invoke that method from a Context (for instance, the Activity class is a Context (it inherits Context)).
In that case, what I'd recommend, is creating a Application class that returns the context you want. Here I explain how to do it. After that you can do something like:
public final String LOG_NAME = (String) App.getContext().getText(R.string.app_name_nospaces);
Depending on what sort of 'files' you are using, you can define a TAG that is used.
For example, when I create an app, I like to create a base class for my Activity classes...
Suppose my app is called 'Wibble', and my package is com.mydomain.Wibble...I create my base Activity like so...
package com.mydomain.Wibble
public class WibbleActivity extends Activity {
final protected String TAG = this.getClass().getName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// I'll explain how this next line works later
android.util.Log.d(TAG, "Entered onCreate()...");
}
}
Now suppose I derive an activity as follows...
package com.mydomain.Wibble
public class SomeActivity extends WibbleActivity {
#Override
protexted void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Don't Log "Entered onCreate()..." - WibbleActivity does it for me
android.util.Log.d(TAG, "SomeText");
}
}
Then I derive another Activity...
package com.mydomain.Wibble
public class SomeOtherActivity extends WibbleActivity {
#Override
protexted void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Don't Log "Entered onCreate()..." - WibbleActivity does it for me
android.util.Log.d(TAG, "SomeOtherText");
}
When onCreate() is called for SomeActivity, the output will be...
com.mydomain.Wibble.SomeActivity Entered onCreate()...
com.mydomain.Wibble.SomeActivity SomeText
...when onCreate() is called for SomeOtherActivity however, the output will be...
com.mydomain.Wibble.SomeOtherActivity Entered onCreate()...
com.mydomain.Wibble.SomeOtherActivity SomeOtherText
Neither activity needs to know specifics through an explicit string and the package name is prefixed. Obviously it will only work in certain situations but I find it useful.

Categories