Проблемы, возникающие при разработке андроид приложений

в 17:28, , рубрики: Google API, java, Программирование, Проектирование и рефакторинг, Разработка под android

Введение

Доброго времени суток.В этой статье вы узнаете о том, какие проблемы могут возникнуть при разработке android приложений. На написание этой статьи меня побудили комментарии из прошлой статьи, кстати вот она:
Моя первая статья
Спасибо за советы! Ну пора начинать…

Проблема 1

Разрабатывая свои приложения мне хотелось сделать их как можно удобнее и красивее.Этому мешали стандартные диалоговые окна. Мне хотелось, чтобы фон в диалоге совпадал с основным фоном приложения.

Решение

В манифесте нужно выбрать собственную тему, за это отвечает атрибут

 android:theme="@style/AppTheme">

Заходим в values/styles.xml:
Проблемы, возникающие при разработке андроид приложений - 1
В этом файле находится тема приложения. Сначала я сделал приложение во весь экран, через наследование темы — android:Theme.Black.NoTitleBar.Fullscreen, потом изменил стиль диалоговых окон таким образом:

<item name="android:alertDialogStyle">@style/alertStyle</item>

, но такой вариант не работает… За стиль диалоговых окон отвечает именно такой атрибут:


<item name="android:alertDialogTheme">@style/alertStyle</item>

Теперь уже можно определить сам стиль в том же файле


    <style name="alertStyle" parent="android:Theme.Dialog">
        <item name="android:layout_gravity">center</item>
        <item name="android:background">#64abcdf5</item>
    </style>

Весь файл


<resources>
    <style name="AppTheme" parent="android:Theme.Black.NoTitleBar.Fullscreen">
        <item name="android:alertDialogTheme">@style/alertStyle</item>
    </style>

    <style name="alertStyle" parent="android:Theme.Dialog">
        <item name="android:layout_gravity">center</item>
        <item name="android:background">#64abcdf5</item>
    </style>
</resources>

В результате получаем:

Красивое диалоговое окно

Проблемы, возникающие при разработке андроид приложений - 2

Проблема 2

Эта проблема связана с сохранением данных.Сначала я находил решения связанные с созданием баз данных, но это для меня было чем-то страшным.Я искал вариант проще.Наконец набрёл в официальной документации на класс SharedPreferences. С помощью него очень легко сохранять данные.Рассмотрим на примере сохранение времени.

SaveObjectRating

public final class SaveObjectRating {
    private Date[] convertedTime;
    private SharedPreferences sharedPref;
    private long[] time;

    SaveObjectRating(Context context) {
        time = new long[10];
        convertedTime = new Date[10];
        sharedPref = context.getSharedPreferences("RatFile", MODE_PRIVATE);
        load();
    }

    public Date[] getConvertedTime() {
        return convertedTime;
    }

    public void setNewTimeOnIndex(long a, int index) {
        if (a < time[index] && a != 0) {
            time[index] = a;

        }
    }
      //метод сохранения данных
    public void save() {
        SharedPreferences.Editor editor = sharedPref.edit();
        for (int i = 0; i < 10; i++) {
            editor.putLong("key" + i, time[i]);
        }
        editor.apply();
    }

    //метод загрузки данных из хранилища
    private void load() {
        for (int i = 0; i < 10; i++) {
            time[i] = sharedPref.getLong("key" + i, 3599);
        }
    }
    //Метод преобразования 
    void createConvertedTime() {
        for (int i = 0; i < 10; i++) {
            convertedTime[i] = new Date();
            long min = time[i] / 60;
            long sec = time[i] % 60;
            convertedTime[i].setMinutes((int) min);
            convertedTime[i].setSeconds((int) sec);
        }
    }
}

Данный класс используется для сохранения потраченного игроком времени на прохождение уровня.При создании объектов этого класса в них будут уже загруженные данные, потому что в конструкторе класса вызывается метод load().
Новое потраченное время можно задать методом:
setNewTimeOnIndex(long a, int index)
Он изменяет данные только в том случае, если пользователь потратил на прохождение меньше времени.Чтобы сохранить данные нужно вызвать метод save().
И проблема сохранения данных решена без создания баз данных.

Проблема 3

Всё начиналось с много-экранных приложений. Экраны нужно менять, но как. Первое решение которым я долгое время пользовался — это создание для каждого экрана своей активности. Если бы у меня был мощный телефон, как у моего друга, я бы даже не заметил минусов этого решения, но это не так. При переходе на другой экран создавалась ещё одна активность и визуально на слабом телефоне это очень заметно. После осмысления я наконец понял, что активности не самый лучший вариант для переходов между экранами приложения. Нужно было использовать фрагменты.
Это даёт нормальный визуальный эффект — совсем не заметно смены экрана.

Проблема 4

Наверное самая сложная проблема, потому что до сих пор каким бы решение я не пользовался приходится ставить куда-нибудь костыль, заключается в том, чтобы реализовать определение текущего фрагмента. Первое, что пришло мне в голову — это использовать статическую переменную. Как вариант сойдёт, но если фрагментов будет очень много, то создаются огромные выборки статической переменной и начитаешь путаться, какое значение отвечает за какой фрагмент. Следующий вариант — это определять на каком мы сейчас фрагменте через его тип (использование ключевого слова языка программирования Java — instanceof). На первый взгляд должно работать, но не работает. Мне до конца так и не удалось разобраться почему это работает не так как надо.(оно работает, но с ошибками...)
Итак, я попробовал ещё один вариант — проверять какой фрагмент виден на экране.Работает так как надо, если использовать его вместе с статической переменной.

MainActivity.class

@Override
    public void onBackPressed() {
        System.out.println("MainActivity:onBackPressed()");
        if (idTheCurrentFragment == 4) {
            finish();
        }
        if (start.isVisible()) {
            System.out.println("Вы нажали назад в главном меню приложения");
            idTheCurrentFragment = -1;
            finish();
        } else if (game1vs1.isVisible() || gameCompany.isVisible()) {
            confirmation(); //Метод создаёт диалоговое окно с выбором.
        } else if (idTheCurrentFragment == -1) {
            System.out.println("Вы нажали кнопку назад");
            super.onBackPressed();
        }
    }

Задача состояла в том, чтобы при нажатии системной кнопки назад игрока спрашивали уверен ли он в том, что хочет покинуть игру.Если игрок соглашается, то вызывается метод экземпляра класса FragmentManager popBackStack("..."), статическая переменная выставлялась в значение 4, при котором при нажатии на кнопку ещё раз приложение завершает работу.Такое решение меня устроило, но было бы интересно как это можно сделать ещё лучше.

Проблема 5

Проблема динамической смены фрагментов. К примеру, есть фрагмент А и при нажатии по кнопке, которая находится в размете этого фрагмента, должен открываться следующий экран, то есть фрагмент B. Я попробовал вариант — в классе активности создал обработчик событий нажатия на все кнопки в приложении. Во всей разметке я для всех кнопок указал в атрибуте android:onClick="..." созданный в активности обработчик событий. Для кнопок обязательно нужно указать id, чтобы обработчик понимал с какой кнопкой он имеет дело.

Код обработчика

public void onClick(View v) {
        int id = v.getId();
        switch (id) {
            case R.id.exit: {
                onBackPressed();
                break;
            }
            case R.id.info: {
                fm.beginTransaction().replace(R.id.fragment_container, infoFragment).addToBackStack(null).commit();
                break;
            }
            case R.id.about_game: {
                fm.beginTransaction().replace(R.id.fragment_container, aboutGameFragment).addToBackStack(null).commit();
                break;
            }
            case R.id.about_authors: {
                fm.beginTransaction().replace(R.id.fragment_container, aboutAuthorsFragment).addToBackStack(null).commit();
                break;
            }
        }

Сами кнопки не создаются в java коде, только в xml.Да, да это работает.В активности есть экземпляр класса FragmentManager, чтобы выполнить транзакцию, то есть поменять текущий фрагмент.
Всё это хорошо, но я не знаю считается ли это правильным, поэтому от этого варианта я быстро отказался, постепенно убирая из выборки по нескольку значений, пока она совсем не опустела.Ещё один вариант, предлагаемый документацией Google — это через объект интерфейса, то есть фрагмент обрабатывает нажатие на свои кнопки и при нажатии создаётся объект интерфейса, который реализует активность таким образом:

                SendingActivity message = (SendingActivity) getActivity();
                message.send(''сообщение для активности'');

В реализации активностью этого интерфейса можно сделать switch — case, в котором уже определять какой фрагмент открывать дальше.

@Override
    public void send(int a) {
        switch (a) {
            case 0: {
                //Открываем фрагмент первого режима игры
                break;
            }
            case 1: {
                //Открываем фрагмент второго режима игры
                break;
            }
            case 2: {
                //Открываем фрагмент третьего режима игры
                break;
            }
            case 3: {
                //Открываем фрагмент четвёртого режима игр
                break;
            }
            case 4: {
                //Закрываем приложение(Кнопка выход)
                finish();
                break;
            }
        }

Проблема 6

Это проблема осталась так не решённой. Я надеюсь найдутся какие-нибудь опытные разработчик, которые смогут поделиться своим опытом в комментариях. Дело в том, что часто бывает нужно импортировать свою картинки svg формата в среду разработки, но делать по одной картинки очень долго, даже если натренироваться… История была такой, я мучился вставлял 80 картинок в среду разработки, а потом оказалось, что их нужно переделывать…

Заключение

Молодцы те, кто дочитал до конца.Итак, я проделал длинный путь обхода этих проблем, чтобы на моих ошибках научились другие и поделился своим опытом с начинающими android разработчиками. Я надеюсь, что моя статья была для вас полезна.
Всем удачи!

Автор: ureneva1999

Источник

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


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