findViewById in non activity class - android

I know there are some topics in StackOverFlow asking this But all of them are answering in special cases No one answers this question generally.
Can anyone say how to use findViewById in non activity classes?
For Example in my case I want to define a webview:
WebView view=(WebView)findViewById(R.id.webview);
But I can't and I really don't understand why android makes everything complicated.Why you can use everything in main activity but you can't use many of them in non activity class :(
UPDATE
I can't extend my class as activity cause it extends sth else.
UPDATE
This is the class:
class DownloadTask extends AsyncTask<String, Void, Void> {
protected Void doInBackground(String... sUrl) {
...
WebView view=(WebView)findViewById(R.id.webview);
final Snackbar snackbar = Snackbar.make(view,"message",Snackbar.LENGTH_LONG);
...
}
}
I'm gonna use the webview in a Snackbar.

Can anyone say how to use findViewById in non activity classes?
Pass the activity into the method you are calling on the non-activity class.
Or, pass the activity into the constructor of the non-activity class.
Or, call findViewById() in the activity and pass the WebView to the non-activity class.
Plenty of other patterns exist. You need to be careful that you do not try using the activity or WebView longer than you should (e.g., after the user rotates the screen, presses BACK, or otherwise causes the activity to be destroyed).
I'm gonna use the webview in a Snackbar.
Using a Snackbar is fine. Using one from an AsyncTask is not, unless you do so very carefully. In particular:
Only try doing this from the main application thread (i.e., not doInBackground())
Make sure that you are handling configuration changes, BACK presses, and the like properly. In particular, you cannot show a Snackbar on a destroyed activity

1-in non activity class:
public Context con;
public NonAct(Activity c){//NonAct = your non activity class name
this.con = c;
}
//in your class or function do this:
WebView view=(WebView)con.findViewById(R.id.webview);
2-call non activity class with sending context argumant:
NonAct n = new NonAct(YourActivity.this);

try this
ClassName instance = new ClassName(this);
and starting of your class will look like this
public class ClassName extents to something {
public Activity activity;
//.... other attributes
public ClassName( Activity _activity){
this.activity = _activity;
//other initializations...
you can use findviewby id like this
WebView mywebview = (WebView)this.activity.findViewById(R.id.mywebview);
///// now do whatever u want
i hope this will help u.

just look at this link u have to pass your view inflated to AsyncTask
findviewbyid in asyncTask

Related

Is it okay to extend to MainActivity from a JavaScriptInterface to avoid non-static errors?

I have one activity with a webview in it.
When the user interacts with the webview, it does this through the JavaScriptInterface so both the app and webview can interact with each other.
I believe the class is by default static, so I've found not too much can be done without it extending MainActivity.
public class JSInterface extends MainActivity {
private MainActivity mainActivity;
JSInterface(Context context, MainActivity mActivity) {
mainActivity = mActivity;
}
#JavascriptInterface
public void someMethod() {
mainActivityMethod(webViewData);
}
// other methods
}
In my MainActivity I have:
WebView webView = findViewById(R.id.webView);
JSInterface JSInterface = new JSInterface(this, this);
//other methods called by JSInterface, e.g.
#Override
public void mainActivityMethod(String webViewData) {
// do something with data
}
So I've found by extending to MainActivity from JSInterface, I can call normal (non-static) methods from MainActivity which is very much a necessity.
If I don't extend it to MainActivity, it seems to be a static class and I get this error when trying to call MainActivity methods or reference anything not static:
Non-static method someMethod() cannot be referenced from a static context.
It works as it is, but I feel like this isn't the best way to go about it.
Am I right?
What would be the 'best' way to do this? Or other ways, as best is subjective.
I feel like this isn't the best way to go about it
Never create a subclass of Activity unless you are going to start it with startActivity().
What would be the 'best' way to do this?
One option is simple composition, getting rid of the improper inheritance:
public class JSInterface {
private MainActivity mainActivity;
JSInterface(MainActivity mActivity) {
mainActivity = mActivity;
}
#JavascriptInterface
public void someMethod() {
mainActivity.something(webViewData);
}
// other methods
}
Another is a nested class. In this sample activity, Locater is a nested class inside of my GeoWebOne activity, and therefore Locater can call methods and access fields in GeoWebOne. The simple composition approach is a better answer, though a nested class will work.

How to get activity instance from startActivity() or precisely how to call a method in an activity that we create?

Im trying to figure a way how to call an activity that an adapter has started. Is there a way to get the instance of the activity from startactivity and make a method call into the activity ?
I'ved got an adapter that has a list
public class LanguageDownloadRVAdapter extends RecyclerView.Adapter<LanguageDownloadRVAdapter.DownloadViewHolder>{
And in this adapter, it starts a particular activity called MainActivity
context.startActivity(new Intent(context, MainActivity.class));
((Activity)context).finish();
Here is the MainActivity that it starts
public class MainActivity extends AppCompatActivity implements IabBroadcastListener{
How can I make a call from the adapter to a method in the MainActivity. (im just trying to perform inapp purchase which is implemented in the MainActivity). so how can i do something like this.
mainactivity.perform_inapp_purchase();
Try to use EventBus for passing data between activity and list adapter. You can do it in the same way for passing data between activity and fragment.
This work the same way as storing data in global variable (in a fancier way)
In the adapter:
Add a new Field private Context mContext;
In the adapter Constructor add one more parameter as below, and assign it into class level variable:
public LanguageDownloadRVAdapter(......,Context context){
//your code.
this.mContext=context;
}
In the Adapter where you want to call Activity's perform_inapp_purchase() method:
if(mContext instanceof MainActivity){
((MainActivity) mContext).perform_inapp_purchase();
}
More Generalized Approach:
If you need to use this same adapter for more than one activity then :
Create an Interface
public interface InAppPerchaceInterface{
void perform_inapp_purchase();
}
Implement this interface in activities
Then in Adapter, call like below:
if(mContext instanceof InAppPerchaceInterface){
((InAppPerchaceInterface) mContext).perform_inapp_purchase();
}
You can store the instance in the application class, but you should be careful about the memory leaks.
In the onCreate of your activity
protected void onCreate(Bundle savedInstanceState)
{
// get the instance using this and store it in the application class or in the place that you want to call from it
}
From where will you call your method?
I didn't understand the situation.

Access button reference from other class

I have somthing like that:
public class A()
{
private Button myButton;
public void setMyButton(Button myButton)
{
this.myButton = myButton;
}
public Button getMyButton()
{
return myButton;
}
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
setMyButton(button);
}
public class B()
{
public void exampleMethod()
{
A aObject = new A();
Button button = aObject.getMyButton();
}
}
Button in class B is always null. I tryied that:
In class A
public Button myButton;
In class B
A aObject = new A();
Button button = aObject.myButton;
but it is not working too.
I am sure that first is button initiate, then geting button reference. I checked that using logs.
I don't know what is going on, becasue "getMyButton" in class A work fine. How can I get reference of button from class A in class B?
What is the best way to do that?
Looks like you are creating new java object of your activity on your own. Please try to get existing object of an created activity; so that you will get activity context and activity properties as well.
The button is always null because its set in onCreate, which is not automatically called. Let me guess, A is supposed to be an Activity subclass, based on the signature, right? In that case you're doing things really wrong.
*You cannot create an Activity via new, it won't be properly initialized.
*Accessing views of an Activity like that is really weird. It makes more sense to pass the view into B, as B is likely owned by A. If the Activity A doesn't own B, you're probably doing something really wrong. Pretty much if you need to do this you've probably misarchitected something.
The way that you are doing will only works in JAVA and not in ANDROID.
Its because of ACTIVITY class. Activity class reference will be created only when its life cycle is created and you cannot pass the UI elements of one activity to Another.
As the button is associated with the 'A' Class in your case and if you want this in Class 'B' you have to start Activity and its life cycle and also setContentView(R.layout.activity_main);
Other way is get the data that you want from any class and publish the value in 'A' class itself. this can be done by startActivityForResult();

Is it a good practice to pass an object of Android Activity to a Thread class' constructor?

While writing an Android activity that submits input queries to a web server, I was thinking instead of having an anonymous inner class to define the networking thread, why can't we use a separate class that extends Thread.
While this works as expected, I would like to know whether this belongs any good or bad practice.
public class GreetActivity extends Activity{
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_greet_activity);
}
public void onClickBtn(View v){
Thread t = new WorkerThread("http://10.0.2.2:8080",this);
t.start();
}
}
class WorkerThread extends Thread{
private String targetURL;
private Activity activity;
public WorkerThread(String url, Activity act){
this.activity = act;
this.targetURL = url;
}
public void run(){
TextView tv = (TextView) activity.findViewById(R.id.textview1);
. . . . . .
}
}
Passing an Activity reference to a thread has some caveats. Activity lifecycle is separate from thread lifecycle. Activities can be destroyed and recreated e.g. by orientation change events. If the activity reference is hold in a thread, the resources held by the activity (lots of bitmap assets for example, taking a lot of memory) are not garbage collectible.
An non-static inner class also has the same problem since the reference to the parent is implicit.
A working solution is to clear the activity reference when the activity is destroyed, and supply a new activity reference when the activity is recreated.
You can only touch your UI widgets in the UI thread as mentioned by blackbelt.
For what it's worth, an AsyncTask is easier to work with than a bare-bones Thread.
In your case, no it is not, since only the UI Thread can touch the UI, your code will make your application crashes with
android.view.ViewRoot$CalledFromWrongThreadException

Starting an Android Activity from an Listener defined in an external class file

I have an Activity MyActivity with a Button MyButton.
I want to attach a MySpecialOnClickListener to MyButton.
I write MySpecialOnClickListener in an external class file.
public class MySpecialOnClickListener extends ButtonHandler implements OnClickListener {
public OnClickListenerWithSpeech (Context context)
{ super.context = context; }
#Override
public void onClick(View view) { handleClick(view); }
}
and ButtonHandler looks like this
public abstract class ButtonHandler {
protected Context context;
protected void handleClick (View view){
if (view.getid()==R.id.button_B) {
context.startActivity (new Intent(context, ActivityC.class));
}
}
}
I basically want to store all logic for Buttons in the ButtonHandler.
SO...as I said, I have the MySpecialOnClickListener defined in an external class file.
When I click MyButton I get the following fatal error.
Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
So I can't start an activity normally from within a non-Activity. Fair enough.
However, if I change MySpecialOnClickListener to be an inner class in 'MyActivity' it works fine. Remember 'ButtonHandler' is still an external class file. So it (where ActivityC is ultimately started from) doesn't change.
My question (finally) is: can someone explain the logic of why one is allowed and the other isn't. I presume its a scoping thing or something but I'm a bit confused. It seems the code to start the process of starting an activity has to literally be inside another Activity.
EDIT - PROBLEM SOLVED
See below. The location of the class is irrelevant. I just didn't pass in the context properly.
because the ButtonHandler 'context' field isn´t associated with any activity context. So, when you attach the MySpecialOnClickListener instance to a button you create it passing the context parametener, isn´t???
something like this:
MySpecialOnClickListener listener = new MySpecialOnClickListener(MyActivity.this);
aButton.setOnClickListener( listener );
in this way you´re constructing the Button with the correct context...
It's likely that you are not passing the Activity context to MySpecialOnClickListener. Could you show me the difference in the way you invoke the inner-class approach?
Apologies to those of you who tried to answer. It was my fault (and I didn't include the following info initially for people)
When I was passing in the context to the 'MySpecialOnClickListener' I would do:
view.setOnClickListener(new MySpecialOnClickListener(getApplicationContext()));
when I should have done:
view.setOnClickListener(new MySpecialOnClickListener(this));
So getApplicationContext() doesn't seem to get the "correct" context for the app.
Which leads me to my next question as to what getApplicationContext() actually returns :)

Categories

Resources