Исходя из патча, с которым связан pjcunningham, поскольку wtforms еще не выпустил это обновление, я пошел вперед и создал свою собственную monkeypatch:
import wtforms_sqlalchemy.fields as f
def get_pk_from_identity(obj):
cls, key = f.identity_key(instance=obj)[:2]
return ':'.join(f.text_type(x) for x in key)
f.get_pk_from_identity = get_pk_from_identity
Plopping, что в моей кодовой базе достаточно, чтобы работать пока они не сократят выпуск, который работает с новейшей версией SQLAlchemy.
Вы не можете инициализировать View
за пределами метода, подобного этому
CheckBox cb1 = (CheckBox) findViewById(R.id.cb1);
CheckBox cb2 = (CheckBox) findViewById(R.id.cb2);
, поскольку это будет означать, что эти строки работают до onCreate()
, что приводит к тому, что эти переменные являются null
и бросьте NPE
при попытке вызвать методы для этих переменных. Это происходит потому, что вы вызываете setContentView(R.layout.your_layout)
внутри onCreate()
и ваш Views
«живой» внутри этого layout
. Это означает, что они не могут быть инициализированы до тех пор, пока ваш layout
не будет inflated
, вызвав setContentView()
. Вы должны вызвать setContentView()
, прежде чем пытаться инициализировать свой Views
.
Что некоторые люди могут сделать, это создать отдельную функцию, которая инициализирует эти переменные сразу после вызова setContentView()
. Что-то вроде этого
public class MyActivity
// declare your Views so they are global to the class
TextView tv;
// more views
@Override
public void onCreat(stuff)
{
// super call
setContentView(R.layout.my_layout);
init();
, затем в вашей функции init()
инициализируйте все Views
, которые вы объявили
private void init()
{
tv = (TextView) findViewById(R.id.myTextView);
// more initializations
}
, но вы можете просто инициализировать их в onCreate()
, onResume()
или где бы то ни было, если это после setContentView()
Объявление и инициализация их таким образом гарантирует, что все они доступны для других функций, слушателей, внутренних классов и т. д. из Activity
. И если у вас много Views
, это может немного уменьшить «беспорядок».
Когда вы перемещаете объявления в начало класса, вы меняете локальные переменные на поля. Эти поля инициализируются при создании экземпляра, что означает, что они инициализируются «прямо перед», когда выполняется конструктор.
Теперь вы не можете вызывать методы экземпляра (например, findViewById
) до завершения неявного вызова super()
.
Переместите их в конструктор, и все должно получиться.
findViewById - это метод, который может быть запущен из активности (или любой группы представлений) после того, как представление было завышено. Чтобы раздуть вид уровня активности, вы обычно вызываете setContentView.
Поскольку setContentView еще не вызван, к действию не добавляются представления.
Вот как это сделать
public class MyClass extends Activity implements View.OnClickListener {
CheckBox cb1;
CheckBox cb2;
public void onCreate(Bundle sis) {
super.onCreate(sis);
setContentView(R.layout.whatever);
cb1 = (CheckBox) findViewById(R.id.cb1);
cb2 = (CheckBox) findViewById(R.id.cb2);
}
public void checkboth(View view) {
cb1.setchecked(true);
cb2.setchecked(true);
}
@Override
public void onClick(View v) {
}
}
Вы не можете вызывать метод (findViewById) здесь и ожидать непустого значения. Представления создаются только в андроиде после вызова setContentView (R.layout.my_layout). Что вам нужно сделать, так это:
public class MyClass extends Activity implements View.OnClickListener {
CheckBox cb1 = null;
CheckBox cb2 = null;
//leaving out most code like onCreate. Just pretend it's there.
public void onCreate(Bundle savedInstanceState)
{
super.onCreate();
setContentView(R.layout.my_layout);
cb1 = (CheckBox) findViewById(R.id.cb1);
cb2 = (CheckBox) findViewById(R.id.cb2);
}
public void checkboth(View view) {
cb1.setchecked(true);
cb2.setchecked(true);
}
@Override
public void onClick(View v) {
}
}