Android. Mad Activity — баг статической инициализации

в 19:49, , рубрики: Песочница, метки: ,

Если вы что-то знаете об основах Java и имеете представление о структуре Android-приложения, то без труда предскажете результат работы такой программки:

public class MainActivity extends ActionBarActivity {
	public static String msg = "Hello, mad Activity";
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
		msg = "WTF?!";
		finish();
	}
// и что-то там ещё ...
}

Если не знаете/не имеете, подскажу — на экране появится сообщение:

Android. Mad Activity — баг статической инициализации - 1

На первый взгляд, вопрос «что мы увидим, если запустим приложение ещё раз?» выглядит идиотским. Ан нет! С огромной (близкой к 100%) вероятностью экран будет выглядеть так:

Android. Mad Activity — баг статической инициализации - 2

Так будет продолжаться, пока OS смартфона не «забудет» текущее состояние статических полей.
(Как вариант, можно вручную остановить выполнение программы из диспетчера приложений.)

И вывод: ни в коем случае не используйте статическую инициализацию в Android-приложениях!

В этом месте можно поставить точку, для особо заинтересовавшихся немного подробностей под катом.

Надо отметить, что с учётом специфики программного стека Android, такое поведение можно предположить, но как жаш Java Language and Virtual Machine Specifications (https://docs.oracle.com/javase/specs/)?

К тому же, глядя на приведённый код, в котором зафиксирована квинтэссенция бага, я бы мог спинным мозгом почувствовать неладное. Но у меня проблемы возникли в сложном проекте — несколько тредов, интенсивное взаимодействие между ними, обработка сообщений от сервера… короче, плодородное поле для недоразумений. И, в последнюю очередь, я бы стал грешить на глюк Android. Зацепился за странности в поведении Singleton, классическую реализацию которого, кстати, сам Android Studio ненавязчиво предлагает в качестве template:

public class Singleton {
	private static Singleton ourInstance = new Singleton();
	public static Singleton getInstance() { return ourInstance; }
	private Singleton() { }
}

Это, безусловно, рабочий код. Но! если в процессе выполнения не изменять значение ourInstance
(на вопрос — «а на фига оно нужно?», — просто искал источник проблем).

И вот, пара статических полей, проинициализированных аналогично, вносили лёгкое разнообразие в монотонную жизнь приложения.

Да и мне было весело.

Я не могу предвидеть реакции Google, но, очевидно, что освоение процесса создания Android-apps нужно начинать с предупреждения — «не используйте статическую инициализацию!»

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js