Could someone explain the best way to achieve the following, I think it's a fairly simple question but I'd like to know the best way, as it can be achieved several different ways.
Let's say I wanted a class which updated a TextView's text to "Test". Of course this isn't what my real problem is, but I'm trying to make this question as simple as possible. Let's also say this will accept any text view.
The class it calls does not inherit Activity.
The ways I see to do this are as follows, please explain why and why not these methods should or shouldn't be used.
Pass the TextView as a reference and update the text.
public class Test
public void updateText(TextView tv)
{
tv.setText("Test");
}
The other option is to pass the Activity, and call findViewById, but the problem here is if the ID does not match that that the Test class expects, the view will return null and won't update the TextView.
public class Test
public void updateText(Activity act)
{
TextView tv = (TextView) act.findViewById(R.id.i_must_exist);
tv.setText("Test");
}
Another choice would be to use getters/setters.
public class Test
private TextView mTvToUpdate;
public void setTextView(TextView tv)
{
mTvToUpdate = tv;
}
public void updateText(Activity act)
{
mTvToUpdate.setText("Test");
}
I guess the real question is it wrong to pass an objects reference as a parameter, is Activity the preferred way? Why? It is more likely to experience memory leaks, are both solutions OK? Is it down to preference?
Please don't reply with "Why would you want to do this?" as in this example I obviously wouldn't want to do what I am asking, but the question behind it still applies.
Thanks in advance.
I wouldn't go with the last way without a good reason because when you hold a reference to an UI element, you may leak memory more easily. When you hold a reference to a Widget, you hold a reference to the Activity either, so you have to make sure that you don't hold the reference to the Widget if the Activity is destroyed (possibly with a WeakReference). This is described in the article Avoiding Memory Leaks.
Besides that there's no real difference.
The object which "owns" the textfield should be the one who actually calls the setText method. So in most cases, that would be the activity. It seems like in this case, your Test class should only provide a method which will return the text you want to display as a string.
So something like
public class MyActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(...);
Test t = new Test(...);
String testText = t.getTestString();
TextView tv = (TextView)findViewById(R.id.TestTextView);
tv.setText(testText)
}
}
public class Test
{
public String getTestString()
{
return "Test"; // Probably would be more dynamic in your case.
}
}
This will abstract the data knowledge out to the Test class. All your activity needs to know is that someone else is providing a data string, and it can set the text itself.
Related
I have a main activity that extends AppCompatActivity, this activity can easily access to the TextView, than I have another java class that I need to access to the same TextView... I couldn't find it out!
Check the code below:-
In your Activity :-
TextView txtview = (TextView)findviewbyId(R.id.tv);
MyJavaClass jav = new MyJavaClass();
jav.setTextView(txtview);
Now in your Java Class :-
class MyJavaClass {
TextView tv ;
public void setTextView(TextView view){
this.tv = view;
}
}
I think that it would be better to keep Android framework objects (especially those that extend Context (Views, Activities, Fragments, etc.) isolated from the rest of your code whenever possible.
Instead of exposing the TextView to your "plain" java object, it would be better to define an interface, devoid of Android Context, and pass that to your 'plain' java object.
Another effective strategy is to use a message bus (or RxJava subject acting as a bus), to communicate between the Activity containing the TextView and the plain java object. e.g. Let the plain java object tell the Activity to change the TextView's content via a message.
At first , why do you want to access a TextView from another class directly?
Is that class an Activity , Fragment or just a java class?
Although,
You can create a static TextView and you can access it in another class.
But be careful of activity lifecycle, if activity stopped so TextView's reference will be null.
Finally don't use static.
According to OOAD it's better to Don't pass TextView to another class.
Why my answer got -1 ?
Situation
I have a BaseActivity from which I extend other activities. In the BaseActivity I have a findCastedViewById which basicaly casts the view and then returns it.
I do this because I, personaly, find it ugly casting the view all the time.
Question
I was wondering if there is any problem or cons that I could get from using this approach that anybody else using this method had.
Here is BaseActivity:
BaseActivity.java
public class BaseActivity extends Activity{
//Other stuff
private <E extends View> E findCastedViewById(int id){
return (E) findViewById(id);
}
//Other stuff
}
Consider using ButterKnife, it solves the problem of having to continuously cast your views and it saves you a lot of time
Once you go butterknife, there's no way back
Basically you annotate the View variables with
#FindView annotation and it will find the correct view for you when ButterKnife.bind(this) is called
Here's a small snippet of code where ButterKnife is used from the GitHub Page
class ExampleActivity extends Activity {
#FindView(R.id.user) EditText username;
#FindView(R.id.pass) EditText password;
#OnClick(R.id.submit) void submit() {
// TODO call server...
}
#Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_activity);
ButterKnife.bind(this);
// TODO Use fields...
}
}
You can read more about ButterKnife from here
As lukaspp already noted, in SDK 26+ there is no need for vew casting.
They have implemented the same code as in the question, except it is now the default findViewById(). So yes OP, your code is good!
As explained in this answer, if you compileSdk is at least API 26, you don't need to cast the view anymore.
It's not only ugly but also an expensive operation if you repeat it constantly.
If you are sure you will always need that specific derived class, you can freely use it. However, I sometimes find I only need methods from the base class View, e.g. setVisibility(), in such occasions casting would be a waste.
I am making an application presenting a showroom and at this points I have created way too much classes.
The main view is a GridView containing all the series of cars.(Each GridView Item opens a new class, so there are 9 classes with very similar code)
How can I structure it?
To put a bit more flesh on #g00dy, start by creating a class
class BMW {
// Reference codes for every series
public final static int SERIES_1 = 0;
public final static int SERIES_2 = 1;
// etc
public final static int NUMBER_SERIES = 9;
// All the code needed for every car
// eg.
public String giveManufacturuer() {
return "BMW"; // But see #g00dy - use string resources
}
public String giveSeries() {
return XXXXX; // Depends on which approach you choose, see below
}
public String giveModelName() {
return XXXXX; // Depends on which approach you choose, see below
}
}
You can either load all the variations into this class (add in references codes for every car and set up some tables to make indexing easy).
Or you could extend the class using inheritance for each class:
class Series1 extends BMW {
#Override
public String giveSeries {
return "Series 1";
}
}
class Series1M3Door extends Series1 {
#Override
public String giveModelName {
return "3 Door";
}
}
When you then instantiate the final class it will have all three functions working correctly.
This approach is neat, but will still give you a lot of classes. I suspect that for what you are doing, some well thought out information tables (accessed by series and model code) may work better inside a hidden class.
A different, perhaps better approach, might be to structure the code using the information that you are returning as the core classes.
I do not actually have the time to write all this down, mean a unifying class, but here's hint for you. Use a flag, which will indicate the model of the car (Z4,M6 for example), then use it inside the class to determine the tree on which the code should run. Replace the hardcoded values with string resources (just do it, no other remarks are necessary). When instantiating the class and using it's functions, take into account the flag and put it inside an if() condition or inside a switch. If some models require more code than the others, you can always encapsulate it in the part of the code which is responsible for the model. But avoid nesting too much ifs, because it will get messy, like having 100 classes defined which do 99% the same thing as the others. Always try to re-use your code as much as possible. It will reduce the writing (copy/pasting) repetitive stuff, also the size of the application, the memory it will need etc. Conclusion: try combining the common parts of the classes into one class ( to RULE THEM ALL :-) ) and use flags, to let the program knwo what to do there.
How to set value to TextView from class which is out of activity? The value we get at an undetermined time, so it is important to set the value from that class.
All advice would be helpful. Thank you.
P.S.:
For example, in Actvity I have method, which sets the value to a TextView.
public void textViewSetText (String value){
tv.setText(value);
} //how correctly to transfer value from my class to get the desired effect?
If you dont have hold of your Activity, then its not possible because TextView is available in Activity. So when you dont have reference to activity, you cant alter it's contents too. In case you pass your activity reference to a static method, then its possible for that method to do the modifications.
Normally, the content of TextView should only be set inside a activity. Though you can set that value outside of the activity, it is not quite useful.
As for your question, you got the value at an undetermined time, there are some choices.For example, you can register a callback to that class, and when the other class got that value, you can send a message through that callback. But be careful about the threading problem, setting a value to a TextView is a UI operation, which should only be done in a UI thread.
Do not access the Android UI toolkit from outside the UI thread
AsyncTask allows you to perform asynchronous work on your user interface. It performs the blocking operations in a worker thread and then publishes the results on the UI thread, without requiring you to handle threads and/or handlers yourself.
Here is an example:
public void onClick(View v) {
new SomeTask().execute(something);
}
private class SomeTask extends AsyncTask<Something, Void, String> {
/** The system calls this to perform work in a worker thread and
* delivers it the parameters given to AsyncTask.execute() */
protected Bitmap doInBackground(Something something) {
return string; // the TextView's text
}
/** The system calls this to perform work in the UI thread and delivers
* the result from doInBackground() */
protected void onPostExecute(String result) {
textView.setText(result);
}
}
However, if you don't give your case more detailed, no exact answer may satisfy you.
You can use an external Static Class to save the value of the String to modify (and set the value once you return to your TextView_Class), only access to the Static Class to get the value.
You may also save the "this" (Activity) in the Static Class and access to that Activity from everywhere, so you can modify the TextView. (I don't thinks this would be recommended).
Depending the case (you didnt explained enought), the normal thing to do is to Bundle the String if they're parent-child classes.
I m not sure about your question but
try like this may be it will work
((MainActivity) activity).textViewSetText();
public void textViewSetText (String value){
tv.setText(value);
}
but your activity have to extends The MainActivity.
Sorry, I'm a newbie to Java and Android...
I've made an app that has a big main activity, I'm wanting to split it up into some child classes to make things easier to read, edit etc.
From my main class I (think) I am instantiating, and calling the child class, from within OnResume :
SetupButtons SetupButtonsObject = new SetupButtons ();
SetupButtonsObject.buildthem();
And in the child class I do:
class SetupButtons extends main {
void buildthem(){
//a load of things to setup buttons
}
}
The code I am using in buildthem() works fine when used in the main class, but is giving a nullpointer exception when used in the child class.
do I need to pass the main context to the child or something?
Many Thanks
Tom
Anything you use in the childclass that is not set there, but set in the main class, you must in some way get from the main class. So yeah, you need some context.
But before you do that: you might want to divide your app in classes that are logical parts of your sollution, as you can read in any OOP description. So not just chop it up in parts because it makes it smaller, chop it up in logical units that are actual good objects.
A quick type, hope I did not make any mistakes here, but see comments in child class.
class Parent{
public static int foo = 1;
public static int bar = 0;
public function somefunction(){
bar = 1;
myChild = new Child();
}
}
class Child extends Parent{
//you can find foo = 1
//but not bar = 0;
}
The Activity class isn't supposed to be instantiated by developer directly, leave this work to the android. If you wish to split it up why do you extend your main activity? You rather need to divide your app in logical parts as Nanne said.
In same class you can call that method directly. Like buildthem();