updating UI thread while in asynctask - java

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.

Related

How to create an instance variable in one activity Android?

So this seems like an odd question, but there's something I'm not understanding about Android Studio (I just started working with it).
If I want to create a variable in an activity, and then access it within different methods in my activity, I should be able to do that, right?
For instance, consider the following code:
public class bakers extends AppCompatActivity {
private Bunz bunz;
BigDecimal baker1Cost = BigDecimal.valueOf(20); //cost of baker1
BigDecimal baker1Bunz = BigDecimal.valueOf(.1); //number of bunz produced by each baker1
TextView baker1CostText = (TextView) findViewById(R.id.baker1Cost);
TextView baker1Owned = (TextView) findViewById(R.id.baker1Owned);
TextView baker1BunzText = (TextView) findViewById(R.id.baker1Bunz);
TextView bunzCount = (TextView) findViewById(R.id.bunzCount3);
TextView moneyCount = (TextView) findViewById(R.id.moneyCount3);
#Override
protected void onResume() {
super.onResume();
setContentView(R.layout.activity_bakers);
bunz = Bunz.getInstance();
bunzCount.setText("Bunz: " + bunz.getBunz());
moneyCount.setText("Money: " + bunz.getMoney());
baker1BunzText.setText(baker1Bunz.toPlainString());
baker1CostText.setText("Cost: " + (baker1Cost));
baker1Owned.setText("Owned: " + bunz.getBaker1());
}
...
In this code, I try to declare and initialize a bunch of variable before my onResume() method, but this doesn't work. I've found that I can declare variables before the onResume() method, but then for instance if I want to update the value of these variables in the onResume() method, that's fine, but if I want to access that variable in another method, such as onClick, I can't do that, and have to redefine the variables.
Is there something I'm doing wrong here? In essence, my question boils down to this: I want to have an instance variable for one activity (not throughout all activities) that I can access and modify anywhere within the activity.
EDIT: It seems as thought initializing and declaring variables before the onResume method works with things like ints, but I can only declare things like Buttons and Textviews - is there any way I can get around this?
Thanks
Why not initialize your variables in the onCreate method of your Activity? Here you can get an unterstanding of the activity lifecycle.

Android: Updating textviews in multiple activities

I need some pointers on doing the following:
lets say i have 10/20 (number doesn't matter) of activities.
each of these activities has a textview that should work like a counter.
each of these activities has a button to go to the next activity.
this counter starts when the app is launched, and increment itself every second.
So what i did so far is:
have in my main activity a method that instantiate a class that extends Thread.
In that class in the run() method, i increment a variable when a second passes.
Now i'm stuck on what i should do next. Any pointers would be appreciated thanks.
Edit: i need a way to communicate from inside the run method, to whichever activity is now currently on screen, to update its textview.
Just a bit of theory here for standard Object Oriented Programming : stick to the recommended principles like Loose Coupling which makes your project code less tied to each other. You can read more on that later.
Now, using Events, you can setup a system that is synonymous with the natural Publisher/Subscriber design pattern. Like this:
The activity that needs to notify the other activities is called Publisher and the other activities that need to be notified are called Subscribers.
From here:
There are already built and tested libraries to do Events in android. Like my favorite EventBus.
Step 1 Add this line to your app-level build.gradle file:
compile 'org.greenrobot:eventbus:3.0.0'
Then create a simple Plain Old Java Object aka POJO class like this:
public class UpdateTextViewEvent{
private String textToShow;
public UpdateTextViewEvent(String text){
this.textToShow = text;
}
//add your public getters and setters here
}
Step 2 Notify others:
When you want to notify anyone of the changes, you simply called this method:
EventBus.getDefault().post(new UpdateTextViewEvent("Some new Text"));
Step 3 Receive notifications
For those who want to be notified of this event, simply do this:
#Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
#Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
NOTE: to actually handle the event:
#Subscribe
public void onEvent(UpdateTextViewEvent event){
String text = event.getTextToShow();
//now you can show by setting accordingly on the TextView;
}
This is so much easier to do, do decouple your code by eliminating static references in your different activities
I hope this helps! Good luck!
make that Textview in second class as
public static Textview text;
and call it in main activity as
SecondActivity obj=new SecondActivity();
obj.text.settext("");
You can create one another activity e.g. BaseActivity extend with Activity class and your all 10/20 activity extends with created BaseActivity Class.
You can use your textview with protected access specifiers.
What you need to do is inside the counter class, create an a method and passed in a TextView as the parameter. Then create an int variable and set the counter as the instance:
Like this
public static class Counter extends Thread{
private static int x;
#Override
public void run(){
x = counter;
}
public void setCounter(TextView tv){
tv.setText(String.valueOf(x));
}
}
Now call this method setCounter(TextView) in all the activity's onCreate() method you'll like to display the counter, and passed in your the layout TextView as the argument. Like this
...
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState):
....
TextView cTextView = (TextView)findViewById(R.id.texT1);
Counter c = new Counter();
c.setCounter(cTextView);
}

FindViewById cannot be referenced from static context

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.

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