I often have to deal with this kind an error when programming in Java on Android.
For example I have a class where I set a flag.
public class ViewActivity extends Activity {
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
...
}
In another class I want to reset the FLAG_KEEP_SCREEN_ON
class DrawOnTop extends View {
...
if (condition) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
but this doesn't work, since I get "The method getWindow is undefined for the type DrawOnTop".
So I try to define a clearFlags method in ViewActivity class
void clearFlags() {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
and to call it from the DrawOnTop class:
if (condition) {
ViewActivity.clearFlags();
}
This doesn't work as well: I get "Cannot make a static reference to the non-static method clearFlags() from the type ViewActivity".
Well, let's make it static then.
static void clearFlags() {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
and then I get "Cannot make a static reference to the non-static method getWindow from the type Activity"
How could I execute such a statement?
If your DrawOnTop class is nested within the ViewActivity you can create a local Context variable and use it to call the getWindow(). If that's not the case then create a receiver in your activity class then from DawOnTop send an intent with your trigger to do whatever the job is. Do not instantiate your activity class, bad idea!
You can send getWindow() as parameter into clearFlags method.
Call clearFlags(Window window) from your activity: WindowHelper.getInstance().clearFlags(getWindow());
Helper class:
public class WindowHelper {
public static final WindowHelper instance = new WindowHelper();
public static WindowHelper getInstance() {
return instance;
}
public void clearFlags(Window window) {
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
}
I tried to implement the solutions suggested by Aksaçlı and this turned out to be very simple:
In the ViewActivity class DrawonTop is called this way:
mDrawOnTop = new DrawOnTop(this);
The constructor of the second class contains this:
public DrawOnTop(Context context) {
super(context);
Therefore ViewActivity.clearFlags(); has simply to be rewritten as ((ViewActivity)getContext()).clearFlags();
Perhaps you should refer to an initialised object in your static method. So instead of:
void clearFlags() {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
you should create a static instance variable of your window:
private static staticWindowInstance;
void clearFlags() {
getStaticWindowInstance().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
For more information, you should check out the Singleton design pattern.
Related
I have a BaseActivity, in which I am trying to retrieve the instance of a subclass in order to inject it with dagger.
I've been trying to figure out a way to not check manually the object passed on is an instance of every single Activity, but if there is a more optimal way of doing it.
F.i., if the component is as such:
AppComponent
#Singleton
#Component(modules = {AppModule.class})
public class AppComponent {
public void inject(FooActivity fooActivity);
public void inject(BarActivity barActivity);
public void inject(…);
}
Each activity extends BaseActivity and we have something like:
FooActivity
public class FooActivity extends BaseActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.inject(this);
}
}
Last, the issue comes when handling the BaseActivity.
BaseActivity
current implementation
...
public void inject(FooActivity fooActivity) {
DaggerAppComponent.create().inject(fooActivity)
}
public void inject(BarActivity barActivity) {
DaggerAppComponent.create().inject(barActivity)
}
...
However, I am looking for a more optimal way that reduces boilerplate, so I have been thinking something like the following:
BaseActivity
...
public void inject(Object activity) {
// retrieve the instance of the activity
// if possible and handle it so then we can:
DaggerAppComponent.create().inject(activity)
}
...
But since I am required to find its instance, instead of having a series of if statements with instanceof, which I will need to update for every new activity, is there a way to handle it in a more automated way?
Given the following code:
public interface Selectable {
public void select();
}
public class Container implements Selectable {
public void select() {
...
}
public void createAnonymousClass() {
Selectable s = new Selectable() {
public void select() {
//see comment below.
}
};
}
}
I want to access Container.select() from within my anonymous class' select() method. However, this.select() would again call the anonymous class' select() method.
My suggestion would be:
Introduce a field into Container, e.g.
private Container self = this;
Now I can access Container.select() by calling self.select() from within the anonymous class.
Is this a reasonable way? Or are there any better ways?
Container.this.select();
You can write Container.this.select() to distinct from the inner class !
I'm currently using an 3rd-party library to load images,data asynchronously.
I pass a listener to that method and when the loading\download completed an event is passed to my listener and I start to use him. for example:
getMainDownloader.getImagesLoader().loadImages(new IListener() {
#Override
public void loadingCompleted() {
//calling methods that uses this asset
method1();
method2();
}
}, ImagesList.get(0), ImagesList.get(3),ImagesList.get(5));
the listener Interface:
public static interface IListener {
public void loadingCompleted();
}
In my code I have a lot of places where I should download those assets above, and call to different methods - method5(),method12()... on loadingCompleted(), so I copy the code above and each time change the methods what create a duplicated code.
Is there a technic to set one method for loading those assets and some how to pass the methods (method1()...) I want to be called in loadingCompleted() ?
Instead of using an anonymous class you could use a "real" or nested class:
private static class MultiImagesListener implements IListener() {
private final String imageId;
public MultiImagesListener (String imageId) {
this.imageId = imageId;
}
#Override
public void loadingCompleted() {
// use this.imageId to decide which methods to call...
if (IMG_ID1.equals(imageId)) {
method1();
method13();
method27();
// ...
}
}
Every time you pass an instance of your listener to the loadImages-method, you should pass a different argument to the constructor in order to distinguish the listener-instances:
getMainDownloader.getImagesLoader().loadImages(new MultiImagesListener(IMG_ID1);
getMainDownloader.getImagesLoader().loadImages(new MultiImagesListener(IMG_ID2);
I included the library Swipeable-Cards in my android project. In MainActvitiy.java the onCreate method includes something like that:
SimpleCardStackAdapter adapter = new SimpleCardStackAdapter(this);
//This should also be done on an event in the library class:
adapter.add(new CardModel("Title2", "Description2 goes here", r.getDrawable(R.drawable.picture2)));
Now, in the CardContainer.java (which belongs to the swipeable cards library) there is an event on which I want a new item added to the adapteradapter.add(...). The adapter was defined in the MainActvitiy.java as you can see above.
How can I achieve this?
I first thought about defining a new method in MainActivity and then calling it from my library-class, like that:
public void callfromlibrary() {
adapter.add(...);
}
However then the method and the adapter need to be defined static, additionally I don't know how to make this method of MainActivity available in CardContainer.java.
I believe I need to create kind of a listener to check in the MainActivity what happens in CardContainer.java? I don't know how to do this.
Any help is appreciated!
To allow CardContainer to communicate up to the MainActivity, you define an interface in CardContainer and implement it in MainActivity. When the event occurs in CardContainer, it can then call Interface method in order to add the CardModel to the adapater.
public class CardContainer extends ... {
CardContainerEventListener mCallback;
// Define a interface
public interface CardContainerEventListener {
public void addToAdapter();
}
// Method to register callback
void registerCallback(Activity callback) {
mCallback = (CardContainerEventListener) callback;
}
void someFunction() {
// Event got generated, invoke callback method
mCallback.addToAdapter();
}
}
public class MainActivity extends Activity implements CardContainer.CardContainerEventListener {
// Ensure you register MainActivity with CardContainer, by calling
// cardContainer.registerCallback(this)
public void addToAdapter() {
adapter.add(...);
}
}
please use a Java Interface for achieving this..
declare an interface in the cardcontainer class
public interface yourInterface{
public void callfromlibrary();
}
and intialize the object for calling the function
yourInterface object = (yourInterface) MainActivity;
and implement the interface in your main activity like
Class MainActivity extends activity implements yourInterface
and implement callfromlibrary() method
call this method from cardcontainer class whenever you needed using the object you have created ..
object.callfromlibrary()
public class RootActivity extends Activity
{
static LiLa superLayout;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
main();
setContentView(superLayout);
}
private void main()
{
// LiLa is a class which extends LinearLayout
superLayout = new LiLa(this);
//DownloadData is an AsyncTask
DownloadData mDownloadData = new DownloadData(this);
mDownloadData.execute();
}
}
So the AsyncTask change some parts of the superLayout, for now in the AsyncTak, I do :
RootActivity.superLayout.tv.setText("hello");
Would it be better to change :
static LiLa superLayout;
to
LiLa superLayout;
and :
DownloadData mDownloadData = new DownloadData(this);
to
DownloadData mDownloadData = new DownloadData(this, superLayout);
So that it would be possible to do in the AsyncTask :
superLayout.tv.setText("hello");
So question is : is it better to access this kind of parameters (TextView tv for example) or a method to change this TextView through static way or via parameter ?
Thanks for reading me.
EDIT : btw in my code it is a bit more messy it could be more like
RootActivity.superLayout.class1.class2.tv.setText("hello");
It would be better to avoid using a static in this case, and if that means that you need to pass the value as a parameter, that's fine too. (Statics are not O-O, and are generally a bad idea in an O-O design. They also present problems in unit testing.)
It is also generally a good idea to declare all instance variables and provide getter and/or setter methods if that is required.
I don't think static access to a layout is the best way of doing it.
A better solution would be to save the layout as a private variable and then add your AsyncTask as an inner class of your activity:
public class RootActivity extends Activity
{
private LiLa superLayout;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
main();
setContentView(superLayout);
}
private void main()
{
// LiLa is a class which extends LinearLayout
superLayout = new LiLa(this);
//DownloadData is an AsyncTask
new DownloadData().execute();
}
private class DownloadData extends AsyncTask<..., ..., ...> {
//You can reference the variable superLayout here.
//If you need the context, use RootActivity.this
}
}
I think access view in parameter is better way. SO we don't have to make any static reference for the class or activity.
Read the "A public static field/method" part of this link:
http://developer.android.com/resources/faq/framework.html#3
I hope this will help.