Android Контекст без активности? И другое программирование без активности?

Я постараюсь сделать это очень сложно, чтобы превратить это в один всеобъемлющий вопрос:

Я пишу метод для получения строки, содержащей имя города Android-устройства, как определено LocationManager и getLastKnownLocation(), и все это.

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

Но я столкнулся с проблемами, которые меня смущают. Например, если я создаю этот класс (LocationFinder), должен ли он расширять Activity, даже если он никогда не визуализируется? Весь этот класс будет иметь множество геттеров вроде getLastKnownCity() или getCurrentCity() и возвращать строки. Я предположил, что не будет расширять класс Activity, поскольку он действительно не является активностью.

Но тогда какой контекст я использую для:

Geocoder geocoder = new Geocoder(Context context, Locale locale)

?

Это заставило меня предположить, что он ДОЛЖЕН быть активным. Поэтому я расширил Activity и заменил конструктор на

@Override
protected void onCreate(..............

но по какой-то причине, которая никогда не заканчивается вызовом, даже когда я помещаю

String city = new LocationFinder().getLastKnownCity();

Моя первая строка LocationFinder onCreate() -

System.out.println("HEY!")

и это даже не доходит до этого. Я получаю нулевой указатель на android.internal.os.LoggingPrintStream.println() и другие вещи.

Кроме того, существует множество системных констант, которые поступают из классов Activity. Например, мне нужно получить LOCATION_SERVICE, который является строкой, которую я не могу получить без расширения Activity. Конечно, я мог бы обмануть и просто вставить буквальную строку, но это неправильно.

Ответ 1

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

public class LocationFinder {
     private Context myContext;
     private Geocoder geocoder;

     public LocationFinder(Context context)
     {
         myContext = context;
         geocoder = new Geocoder(myContext);
     }

}

И затем, когда вы попытаетесь получить доступ к этому классу, убедитесь, что вы инициализируете его следующим образом:

public class TestActivity extends Activity {
     protected void onCreate(Bundle savedInstanceState)
     {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.main);
          LocationFinder lFinder = new LocationFinder(getApplication());
     }
}

Конечно, вы не можете получить доступ к контексту из каждого класса, в котором будете работать. Поэтому может быть достаточно ссылки на представление.

LocationFinder lFinder = new LocationFinder(anyView.getApplication());

Ответ 2

EDIT: если возможно, используйте ответ frogmanx. Это следует использовать только тогда, когда его ответ невозможно использовать. (т.е. синглетоны, которым нужен контекст с места в карьер).

Похоже, вы должны расширить Application, а не активность.

Сделайте свое приложение примерно так:

public class MyApplication extends Application {
    private static MyApplication instance;

    public MyApplication() {
        instance = this;
    }

    public static MyApplication getInstance() {
         return instance;
    }

Затем добавьте этот атрибут в тег приложения манифеста:

 <application android:name=".your.package.MyApplication" ... />

После всего этого вы можете получить контекст, вызывая MyApplication.getInstance() из любого места.

Ответ 3

should it extend Activity, even though it is never actually visualized?

Нет. От Android docs

Активность - это единая целенаправленная вещь, которую пользователь может сделать. Почти все действия взаимодействуют с пользователем, поэтому класс Activity забота о создании окна для вас, в котором вы можете разместить свой пользовательский интерфейс с помощью setContentView (View)

Подумайте об активности как экране, который видит пользователь.

Но тогда какой контекст я использую для     Геокодер geocoder = новый геокодер (контекст контекста, локаль локали)

Класс Activity расширяет Context, как и многие другие классы, включая Application. Контекст предоставляет доступ к ресурсам, связанным с классом, который расширяет контекст.

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

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

Если вы посмотрите на конструктор для Geocoder, вы увидите, что он принимает контекст как аргумент, как вы знаете. Существует подсказка, почему в описании необходим контекст:

     Geocoder(Context context, Locale locale)
Constructs a Geocoder whose responses will be localized for the given Locale.  [1]: 

Причина, по которой требуется Контекст, - получить доступ к системной информации о локалях платформы и текущей языковой системе системы.

Итак, в вашем примере вы можете просто передать контекст приложения в конструктор, с которым вы можете получить ссылку с помощью getApplicationContext()

Например, мне нужно получить LOCATION_SERVICE, который является строкой, которую я не могу получить без расширения Activity

Вы можете получить его из контекста приложения.