Androidアプリケーションの開発時のいくつかの問題とその解決方法

この記事では、Androidアプリケーションの開発時に遭遇したいくつかの問題と、それらの解決方法について説明します。



静的コンテキスト



問題:静的コンテキストからいくつかのContextメソッドを呼び出せるようにしたい(しゃれはごめんなさい)。



解決策: stackoverflowを使用して、静的Applicationクラスを作成するというソリューションを利用しました。

ここでは、注意する必要があります-そしてそれを賢く使用してください。 たとえば、リソースを取得するには-翻訳、写真、スタイル。

使用できない場合: GUI要素を使用する場合や、たとえばLayoutInflatorを使用する場合(例外がスローされます)。



実際には、次のようになります。



public class ApplicationContext extends android.app.Application { @NotNull private static ApplicationContext instance; public ApplicationContext() { instance = this; } @NotNull public static ApplicationContext getInstance() { return instance; } }
      
      







そして



AndroidManifest.xml:



 <manifest xmlns:a="http://schemas.android.com/apk/res/android"> <application a:name=".ApplicationContext"> // ... </application> </manifest>
      
      







低レベルのアプリケーションで高レベルのAndroid APIを使用する



問題:高レベルAPIで使用可能な機能(GUI要素-ビューなど)を使用したい。



解決策: Androidはオープンプラットフォームであるため、ソースコードが利用可能です。 はい、利用できないクラスをライブラリに転送します。 当然、このアプローチには欠点があります。転送されたクラスの操作性を確認し、このレベルのAPIでサポートされていない依存関係を編集する必要があります(幸運です)。



例: NumberPickerはレベル11からのみ使用可能ですが、プロジェクトに転送してレベル4で使用します: githubを見てください



XML APIを使用する



問題: Javaオブジェクトをxml表現に変換することがしばしば必要です(たとえば、サービス間でオブジェクトを転送したり、永続化状態で保存したりするため)。

通常、このような場合はJAXBが使用されますが、AndroidプラットフォームではJAXBは使用できません。



解決策:別のライブラリーを使用してください。 たとえば、シンプル(XMLシリアル化) simple.sourceforge.netを使用しました



使い方は?



最初に、ライブラリをプロジェクトに接続します。



 <dependency> <groupId>org.simpleframework</groupId> <artifactId>simple-xml</artifactId> <version>2.6.1</version> <exclusions> <exclusion> <artifactId>stax-api</artifactId> <groupId>stax</groupId> </exclusion> </exclusions> </dependency>
      
      







注:除外はstax-apiに設定されています-そうでない場合、プロジェクトはビルドされません(Android APIはサポートされていません)



必要な注釈(@ Root、 TransientElement )でオブジェクトをマークします。

 @Root public class Var implements IConstant { @Transient private Integer id; @Element @NotNull private String name; @Element(required = false) @Nullable private String value; //... private Var() { } }
      
      







オブジェクトをxmlで保存します。

 final StringWriter sw = new StringWriter(); final Serializer serializer = new Persister(); try { serializer.write(vars, sw); } catch (Exception e) { throw new RuntimeException(e); }
      
      







xmlからオブジェクトを取得します。

 final String value = getVarString(); final Serializer serializer = new Persister(); try { final Vars vars = serializer.read(Vars.class, value); // ... } catch (Exception e) { throw new RuntimeException(e); }
      
      







転送のストレージ(Rクラスの依存関係を残す)



問題: Androidには、クラスRフィールド識別子によって翻訳を受信するためのメカニズムがあり、この翻訳を使用する場合はどこでも、このクラスに依存する必要があります。



解決策:翻訳を名前と言語で保存するアプリケーションレベルの翻訳キャッシュ。 変換は静的コンテキストから取得されます。



コード例:

 public enum TranslationsCache { instance; // first map: key: language id, value: map of captions and translations // second mal: key: caption id, value: translation private final Map<String, Map<String, String>> captions = new HashMap<String, Map<String, String>>(); private Class<?> resourceClass; private Context context; /** * Method load captions for default locale using android R class * @param context STATIC CONTEXT * @param resourceClass class of captions in android (SUBCLASS of R class) */ public void initCaptions(@NotNull Context context, @NotNull Class<?> resourceClass) { initCaptions(context, resourceClass, Locale.getDefault()); } /** * Method load captions for specified locale using android R class * @param context STATIC CONTEXT * @param resourceClass class of captions in android (SUBCLASS of R class) * @param locale language to be used for translation */ public void initCaptions(@NotNull Context context, @NotNull Class<?> resourceClass, @NotNull Locale locale) { assert this.resourceClass == null || this.resourceClass.equals(resourceClass); this.context = context; this.resourceClass = resourceClass; if (!initialized(locale)) { final Map<String, String> captionsByLanguage = new HashMap<String, String>(); for (Field field : resourceClass.getDeclaredFields()) { int modifiers = field.getModifiers(); if (Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers)) { try { int captionId = field.getInt(resourceClass); captionsByLanguage.put(field.getName(), context.getString(captionId)); } catch (IllegalAccessException e) { Log.e(ResourceCache.class.getName(), e.getMessage()); } } } captions.put(locale.getLanguage(), captionsByLanguage); } } private boolean initialized(@NotNull Locale locale) { return captions.containsKey(locale.getLanguage()); } /** * @param captionId id of caption to be translated * @return translation by caption id in default language, null if no translation in default language present */ @Nullable public String getCaption(@NotNull String captionId) { return getCaption(captionId, Locale.getDefault()); } /** * @param captionId id of caption to be translated * @param locale language to be used for translation * @return translation by caption id in specified language, null if no translation in specified language present */ @Nullable public String getCaption(@NotNull String captionId, @NotNull final Locale locale) { Map<String, String> captionsByLanguage = captions.get(locale.getLanguage()); if (captionsByLanguage != null) { return captionsByLanguage.get(captionId); } else { assert resourceClass != null && context != null; initCaptions(context, resourceClass, locale); captionsByLanguage = captions.get(locale.getLanguage()); if (captionsByLanguage != null) { return captionsByLanguage.get(captionId); } } return null; } }
      
      







その後、たとえば次のように使用できます。

 try{ //... } catch ( SomeException e ) { TranslationsCache.instance.getCaption(e.getMesageId()); }
      
      







おわりに



上記のすべてが実際に適用されました。



ソースコードはgithub.comで入手できます。



android.marketで動作するアプリケーション。



ご清聴ありがとうございました!



All Articles