Подтвердить что ты не робот

Рекомендации по асинхронному программированию

Недавно я написал свое первое приложение для Android, которое составляло примерно 8 000-10 000 строк кода. Одной вещью, которая постоянно мешала моему использованию обычных шаблонов проектирования, было очень тяжелое использование асинхронных вызовов Android (открытие диалогов, действий и т.д.). Из-за этого мой код очень быстро начал искать "спагетти" вроде, и я в конце концов начал не любить смотреть на определенные классы.

Существуют ли конкретные шаблоны проектирования или методологии программирования, которые предназначены для таких систем, которые каждый мог бы рекомендовать? Есть ли предложения по написанию управляемого асинхронного кода?

4b9b3361

Ответ 1

  • Использовать глобальные переменные

Если вы не хотите испортить свой код с помощью простых вызовов Intent.putExtra() и управлять этими вещами для каждого уникального Activity, вам придется использовать глобальные переменные в приложении. Расширьте Application и сохраните данные, которые вам нужны, пока ваше приложение будет вживую. Чтобы реализовать его, используйте этот отличный ответ. Это приведет к исчезновению зависимостей между действиями. Например, скажите, что вам нужно "имя пользователя" для вашего приложения в течение жизненного цикла приложения - это отличный инструмент для этого. Нет необходимости в грязных вызовах Intent.putExtra().

  • Использовать стили

Одной из распространенных ошибок при создании первого приложения для Android является то, что обычно вы начинаете писать представления XML. Файлы XML (без проблем и очень быстрые) переходят к очень многим строкам кода. Здесь вы можете найти решение, в котором вы просто используете атрибут style для реализации определенного поведения. Например, рассмотрим этот фрагмент кода:

значения/styles.xml:

<style name="TitleText">
    <item name="android:layout_height">wrap_content</item>
    <item name="android:layout_width">wrap_content</item>
    <item name="android:textSize">18sp</item>
    <item name="android:textColor">#000</item>
    <item name="android:textStyle">bold</item>   
</style>

Макет/main.xml:

Теперь, если у вас есть, скажем, два TextView, и оба они должны иметь такое же поведение, чтобы они использовали стиль TitleText. Пример кода:

<!--- ... -->
<TextView
   android:id="@+id/textview_one"
   style="@style/TitleText" 
/>

<TextView
   android:id="@+id/textview_two" 
   style="@style/TitleText" 
/>
<!--- ... -->

Простой и вам не нужно дублировать код. Если вы действительно хотите посмотреть дальше по этому конкретному вопросу, просмотрите Трейки макета: создание многократно используемых компонентов пользовательского интерфейса.

  • Использовать строки

Этот момент короткий, но я думаю, что это важно упомянуть. Еще одна ошибка, которую разработчики могут сделать, - это пропустить файл strings.xml и просто написать UI-сообщения (и имена атрибутов) внутри кода (где он понадобится). Чтобы упростить работу с вашим приложением; просто определите сообщения и атрибуты в файле strings.xml.

  • Создать и использовать глобальный класс инструментов

Когда я писал свое первое приложение, я просто писал (и дублировал) методы, где мне это нужно. Результат? Много методов, которые имели одинаковое поведение между различными видами деятельности. То, что я узнал, - это сделать класс инструмента. Например, скажем, вы должны делать веб-запросы во всех своих действиях. В этом случае пропустите определение их внутри фактического Activity и сделайте для него статический метод. Пример кода:

public final class Tools {

    private Tools() {
    }

    public static final void sendData(String url, 
              String user, String pass) {
        // URLConnections, HttpClients, etc...
    }

}

Теперь вы можете просто использовать этот код ниже в своем Activity, который должен отправлять данные по серверу:

Tools.sendData("www.www.www", "user", "pass");

Однако вы понимаете. Используйте этот "шаблон" там, где он вам нужен, это не позволит вам испортить ваш код.

  • Пусть пользовательские классы определяют поведение, в котором пользователю необходимо взаимодействовать с вашим приложением

Это, наверное, самый полезный момент. Чтобы просто определить, "где пользователь должен взаимодействовать с вашим приложением", скажем, у вас есть Menu, какое поведение очень длинное с точки зрения строк, почему мы сохраняем вычисления Menu в одном классе? Каждый маленький предмет сделает ваш Activity класс болезненным фрагментом кода дольше - ваш код выглядит как "спагетти". Например, вместо того, чтобы иметь что-то вроде этого:

@Override
public boolean onPrepareOptionsMenu(Menu menu) {
    MenuItem item;
    item = menu.findItem(R.id.menu_id_one);
    if (aBooleanVariable) {
        item.setEnabled(true);
    } else {
        item.setEnabled(false);
    }
    // More code...
    return super.onPrepareOptionsMenu(menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem i) {
    // Code, calculations...
    // ...
    // ...
    return super.onOptionsItemSelected(i);
}

переработайте его примерно так:

private MyCustomMenuInstance mMenuInstance;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);        
    setContentView(R.layout.main);

    mMenuInstance = new MyCustomMenuInstance();
}  

@Override
public boolean onPrepareOptionsMenu(Menu menu) {
    mMenuInstance.onPrepareOptionsMenu(menu);
    return super.onPrepareOptionsMenu(menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem i) {
    mMenuInstance.onOptionsItemSelected(i);
    return super.onOptionsItemSelected(i);
}

Например, MyCustomMenuInstance:

public class MyCustomMenuInstance { 

    // Member fields..

    public MyCustomMenuInstance() {
        // Init stuff.
    }

    public void onPrepareOptionsMenu(Menu menu) {
        // Do things..
        // Maybe you want to modify a variable in the Activity 
        // class? Well, pass an instance as an argument and create
        // a method for it in your Activity class.
    }

    public void onOptionsItemSelected(MenuItem i) {
        // Do things..
        // Maybe you want to modify a variable in the Activity 
        // class? Well, pass an instance as an argument and create
        // a method for it in your Activity class.
    }

}

Вы видите, где это происходит. Вы можете применить это ко многим вещам, например. onClick, onClickListener, onCreateOptionsMenu, список длинный. Чтобы узнать больше "лучших практик", вы можете увидеть некоторые примеры приложений из Google здесь. Посмотрите, как они реализовали вещи красивым и правильным способом.

Последнее слово; сохраните свой код в чистоте, назовите свои переменные и методы логичным образом и особенно правильно. Всегда, всегда понимайте, где вы находитесь в своем коде - это очень важно.

Ответ 2

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

  • Переосмыслите свои классы, чтобы лучше описать ваши объекты,
  • сохранить код в каждом методе до минимума,
  • избегать зависимостей от статических переменных в любом месте,
  • использовать потоки для дорогостоящих задач, не использовать их для быстрых процедур,
  • отделите интерфейс от логики приложения (сохраните его в своих классах),
  • сохранить личные поля в любом месте: это будет полезно, если вы захотите изменить свой класс,
  • итерации через них, пока вам не понравится код

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

Как указывает OceanBlue, из этого может быть неясно, что переменные final static не создают никакой опасности, а общедоступные статические переменные, которые могут измениться. Это не проблема с самой статикой, но с понятием, что они будут иметь значение, а затем узнают, что значение изменилось. Возможно, будет трудно определить, где проблема. Типичными примерами будут счетчик кликов или значение таймера, когда может быть более одного просмотренного изображения или более одного таймера.

Надеюсь, вы получите предложения от людей с гораздо большим опытом, чем я. Удачи!

Ответ 3

При обращении к пользовательскому интерфейсу ваша самая большая проблема, тогда вы захотите освоить кодирование, управляемое событиями. Идеи, связанные с кодированием, управляемым событиями, стоят за всеми современными системами пользовательского интерфейса и полезны во всех вещах (а не только в пользовательском интерфейсе).

Самый простой способ подумать об этом, когда учиться, - это просто рассматривать каждый компонент и событие, как если бы он был самодостаточным. Все, о чем вам нужно беспокоиться, - это объект события, переданный в ваш метод событий. Если вы привыкли писать приложения, которые работают в основном от начала до конца, это немного сдвиг ума, но практика заставит вас там довольно быстро.

Ответ 4

Как насчет использования шаблона контроллера Model View?

По крайней мере, вам нужно изолировать в "модели" (объект или набор объектов) все государство и его логическое управление, и отдельный класс (возможно, класс Activity) все, что связано с представлениями, слушателями, обратными вызовами...)