在基于Android的应用程序中,我的静态onClick Listener
中有一个匿名函数,即InnerClass
,它可以从OuterClass
访问视图。问题是我尝试访问时从所需位置的特定视图指出从静态角度不能访问非静态成员...当我从OuterClass使视图静态时,它可以工作,但这是一个好习惯吗?不会导致任何形式的内存泄漏吗?在这种情况下可以做什么?
public class OuterClass extends CustomAppCompatActiivity {
static EditText city_et;
public static class InnerClass extends DialogFragment {
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
okBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//the view to access
city_et.setText("");
}
getDialog().dismiss();
}
});
}
}
}
答案 0 :(得分:0)
在不了解全部上下文的情况下很难回答。 EditText city_et
很可能不是 static ,而是仅用于编译代码。 (OuterClass
的所有实例都具有相同的city_et
吗?我不这样认为。)
您可以将city_et
作为参数传递给RecyclerDialogFragment
构造函数,并将其存储为实例变量,以使您拥有静态的嵌套类而不是内部类。
答案 1 :(得分:0)
静态嵌套类InnerClass
无法访问封闭实例的成员,因为InnerClass
的实例可能不归OuterClass
所有。想象一下:
public class Outer {
public String out = "out";
public static class StaticInner {
public void printEnclosing() {
System.out.println(Outer.this.out); // Let's say this compiles
}
}
}
public class Test {
public static void main(String[] args) {
StaticInner si = new StaticInner();
si.printEnclosing();
}
}
请注意,从未创建Outer
的实例。那么如何打印out
的值?
您需要的是内部类。除了封闭类或其子类之外,任何其他人都无法实例化内部类。这样可以确保只有在已有外部类实例的情况下,才能实例化内部类。
public class Outer {
public String out = "out";
public Inner inner = new Inner();
public class Inner {
public void printEnclosing() {
System.out.println(Outer.this.out); // "out" can be safely referenced
}
}
}
public class Test {
public static void main(String[] args) {
Inner inner = new Inner(); // Compile-time error
Outer out = new Outer();
out.inner.printEnclosing(); // This works, because you are calling method of the Inner class instance owned by Outer class.
}
}
因此,这就是您的代码的样子:
public class OuterClass extends CustomAppCompatActiivity {
private EditText city_et;
private final InnerClass inner = new InnerClass();
public class InnerClass extends DialogFragment {
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
okBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//the view to access
city_et.setText("");
getDialog().dismiss();
}
});
}
}
public InnerClass getInnerClass() {
return inner;
}
}
出于对内存泄漏的关注,我认为问题是:InnerClass
和OuterClass
的作用是什么。每当您有一个新的InnerClass
时,您就可以每次创建一个InnerClass
实例(或OuterClass
实例的集合)。 InnerClass
需要引用OuterClass
才能调用setText()
。
因此,此处的合同为:InnerClass
不能没有OuterClass
,并且InnerClass
始终具有InnerClass
。 InnerClass
将与OuterClass
一起被垃圾回收。
如果InnerClass
和OuterClass
之间的关系是InnerClass
可以在没有OuterClass
的情况下运行,而您所需的只是EditText city_et
引用,那么您应该传递该引用。由于InnerClass
现在独立于OuterClass
,因此您可以使用静态嵌套类,也可以将其移动到另一个单独的类中。
public class OuterClass extends CustomAppCompatActiivity {
private EditText city_et;
public static class InnerClass extends DialogFragment {
private EditText city_et;
public InnerClass(EditText city_et) { // Pass a reference in
this.city_et = city_et;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
okBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//the view to access
city_et.setText("");
getDialog().dismiss();
}
});
}
}
}
通过这种方式,只要有资格OuterClass
,就可以独立于InnerClass
进行垃圾回收。唯一不能被垃圾收集的引用是该EditText
实例。
EJP指出“内部类不能被封闭类或其子类之外的任何人实例化”是错误的,并且在签出后,他是对的。最重要的是,“内部类”一词是“非静态嵌套类”的正式术语。
但是,如果您认为DialogFragment
子类的生存期可能长于封闭类,则仍然应该使用静态嵌套类或单独的类。