понедельник, 25 ноября 2013 г.

Баги/фичи в Delphi XE5 на Android #1

В процессе изучения и практики в разработке приложений для Android, я наткнулся на несколько интересных багов (или фич). Я писал об этих багах/фичах на форуме сообщества (https://forums.embarcadero.com/index.jspa), но похоже разработчики и представители из Embarcadero не читают его…

Upd (23.04.14). Проверено на Delphi XE6, исправили ещё и третий баг.

Поехали…

1) Этот баг есть точно в TabItem1, TLabel, TEdit, TMemo, TButton, TSpeedButton и думаю во всех остальных компонентах…
Для примера: Создаём TabControl1, в нём TabItem1 и меняем свойство Text на (например) "Настройки", сохраняем приложение и компилируем под Android. Вместо буквы «й», видим подскочившую букву «и» (смена шрифта не помогает).
Скриншот и исходник приложения для теста:
Решение пока не нашёл.

2) Компонент TMediaPlayer, а конкретно свойства CurrentTime и Duration.
Приведу пример:
Мы пишем mp3 плеер и нам нужно автоматически переключать трек, если закончился текущий. Для этого мы всегда (для Windows) писали:
  if MediaPlayer1.CurrentTime = MediaPlayer1.Duration then
    PlayNextClick(Self);

Если вы используете Delphi XE5 FMX для разработки под Android, то этот код не будет работать, точнее работать-то будет, но не правильно.
Пример на видео(звук можно сразу выключить) и скриншотах ниже:

Если трек длится 188272 мс, то MediaPlayer1.Duration и TrackBar1.Max будут равны этому значению. Самое интересное начинается, когда мы касаемся MediaPlayer1.CurrentTime. CurrentTime отражает текущее время воспроизведения трека, а значит код выше сработает если это время будет равно Duration. Но на Android значение CurrentTime в конце трека почему-то всегда разное, оно может быть как больше значения в Duration, так и меньше.
Решение (костыль):
  if (Round((MediaPlayer1.CurrentTime/MediaPlayer1.Duration)*100) = 100) then
  begin
    PlayNextClick(Self);
  end;

3) Компонент TMemo. На Windows’е работает всё хорошо, а вот с Android’ом опять проблемы…
Писал я приложение для работы с азбукой Морзе, просто так, чтобы посмотреть на возможности Delphi XE5. Обнаружил баг с переносом (исчезновением) символов, а конкретно символы "\ / []. - * ()". Строка может состоять только из них или же эти символы будут в тексте, баг всё равно есть. 
Если в строке только эти символы, то также перестают работать выделение и кнопки копировать/вырезать.
Пример на скриншотах и в исходнике:

Как должно быть:
Как на самом деле(Android):
Как должно быть:
Как на самом деле(Android):

Решение (костыль) – свой код для переноса:
uses
System.Math;
 
procedure TForm1.Button1Click(Sender: TObject);
var
  a: string;
  posit, g: Extended;
begin
  Canvas.Font.Family := Memo1.Font.Family;
  Canvas.Font.Size := Memo1.Font.Size;
 
  //a := '[•−•] [−−−] [−−] [•] [•−•] [•−•−] [•] [−−] [•−−•] [•] [•−•] [•] [−•] [−−−] [•••] [•••] [••] [−−] [•−−] [−−−] [•−••] [−−−] [•−−] [−•] [•−] [−••] [•−••] [••] [−•] [−•] [−−−] [−−] [−•−] [−−−] [−••] [•] [−−] [−−−] [•−•] [−−••] [•] [••••••]';
  a :='[−−•] [•−•] [•] [•] [−] [••] [−•] [−−•] [•••] [••••••] [−] [••••] [••] [•••] [••] [•••] [−] [••••] [•] [−] [•] [−••−] [−] [−] [−−−] [−•−•] [••••] [•] [−•−•] [−•−] [••••] [−•−−] [•−−•] [••••] [•] [−•] [•−] [−] [••] [−−−] [−•] [••••••] ';
 
  if Canvas.TextWidth(a)>Memo1.Width then begin
    g := RoundTo((Canvas.TextWidth(a) / Memo1.Width), -1);
    posit := (Length(a) / g) - 3;
    a := WrapText(a, Round(posit));
    Memo1.Text := a;
  end;
 
end;

4) Обновление приложения и SQLite (dbExpress).
Предположим, у нас есть приложение использующее базу данных SQLite (dbExpress). Т.е. в наш apk файл мы задеплоили файл ".\assets\internal\test.s3db", который содержит 100 записей и установили приложение на устройство.
Через некоторое время мы выпускаем новую версию приложения с изменённым (добавили новый записи, удалили старые) файлом ".\assets\internal\test.s3db", который теперь содержит 110 записей. 
Мы закидываем новый apk файл на устройство и начинаем установку. После установки запускаем приложение и видим, что база не обновилась, т.е. приложение продолжает видеть только 100 записей!

Если вы идете в "Диспетчер приложений", выбираете наше приложение и нажимаете на "Clear Data", то при запуске, приложение начинает видеть новый файл базы данных(110 записей). Похоже есть какое-то кеширование…
Я выяснил такую фишку: приложение хранит (использует) копию файла базы данных тут /data/data/com.embarcadero.name_app/files/test.s3db
Если удалить этот файл: DeleteFile(TPath.GetHomePath + PathDelim + 'test.s3db'); , то приложение всё равно продолжает отображать старые данные и вы не можете с ними работать (т.к. выскакивает ошибка). После перезапуска приложения, всё становится на свои места, и приложение видит новый файл бд.

Решение я так и не нашёл…
Также интересно как вы работаете с базой, как отслеживаете обновления (изменения в бд) пользователем и сохраняете их при обновлении приложения.


Я очень надеюсь, что ребята из Embarcadero поправят эти баги, особенно первый.

Если вы тоже нашли какой-то баг, отписывайтесь в комментах (с примером и желательно с решением), добавлю в список.

p.s. Проверено в Delphi XE5 + Update 1

UPD. Наконец-то я смог зайти в QualityCentral (раньше не пускало…) и отрапортовать о багах.
UPD.2. Как оказалось, не только с русским языком проблемы в первом пункте. В общем уже сообщили, что проблему похожую они решали. Когда только теперь ждать обновления...
UPD(28.11.13). Итог: 1 и 3-й пункты - баги, а вот 2-ой пункт похоже фича

6 комментариев:

  1. Использую в Android-приложении связку SQLite+FireDAC - при обновлении база обновляется нормально, в Deploy указываю путь к базе .\assets\internal\
    А вот вопрос, как не портить базу пользователя при обновления приложения остаётся открытым

    ОтветитьУдалить
    Ответы
    1. Честно говоря, я даже и забыл про последний 4-й баг, а ведь написал пару игр из категории головоломок, но публиковать не стал из-за бага… На днях обязательно перепроверю этот баг на Delphi XE5 Update 2. По поводу «как не портить базу пользователя при обновлении приложения», я думаю надо сравнивать версии двух файлов БД (старого и нового соответственно) и если версия выше, то сравниваем две базы и переносим все изменения из старой версии в новую (это первое, что приходит в голову).

      Удалить
    2. Проверил на Delphi XE5 Update 2. База всё также не хочет обновляться, т.е. видит старый файл базы, пока в диспетчере приложений не нажмёшь Clear Data. :( Я даже не знаю, что и думать… Либо я что-то упускаю из внимания, либо это БАГ.

      Вот ситуация, предположим, я не собираюсь выкладывать приложение в маркет, т.е. пользоваться им будет ограниченный круг лиц. Я обновляю базу, деплою новую версию базы в проект, компилю и раздаю ограниченному кругу лиц новый .APK файл. Но после установки, они не видят новые данные.

      Вопрос: Как обновить базу? (Может знающие люди подскажут…) Как узнать версию базы?

      Удалить
  2. Мы тут обнаружили более страшную "особенность" http://qc.embarcadero.com/wc/qcmain.aspx?d=121702, делающую ,бессмысленной всю дальнейшую работу на Delphi по направлению Android. Увы. Повторяемость "особенности" -100%, в том числе на разных устройствах. Вы не встречались с этим ? Если нет - попробуйте.

    ОтветитьУдалить
    Ответы
    1. Пару раз было дело, но я как-то даже не обратил особого внимания… Сейчас воспроизвёл баг у себя. Я бы не сказал, что «вся дальнейшая работа на Delphi по направлению Android бессмысленна», т.к. приложение просто не может запуститься на второй (иногда на третий) раз, но потом опять всё нормально запускается, так что это скорее временно.
      В QualityCentral за баг проголосовал(5 баллов), думаю, ребята из embarcadero исправят его максимально оперативно.

      Удалить
    2. Спасибо за голос :-)
      К сожалению всё более чем серьезно, поскольку "простые" (небольшие по размеру, без SQLite+FireDAC) только "мигают". Противно, но не страшно. А что-то более серьезное с SQLite... просто тупо виснет. И я не могу объяснить пользователям, что это не моё, что это особенность, что если перед запуском "очистить память", то запустится точно.
      Кстати, приложения этот эффект проявляется и в http://cc.embarcadero.com/Item/29682

      Удалить