Best Practices - Orange168/NotesOnReading GitHub Wiki

Best Practices

Gradle configuration

General structure. Follow Google's guide on Gradle for Android gradle.properties

KEYSTORE_PASSWORD=password123
KEY_PASSWORD=password789
signingConfigs {
    release {
        try {
            storeFile file("myapp.keystore")
            storePassword KEYSTORE_PASSWORD
            keyAlias "thekey"
            keyPassword KEY_PASSWORD
        }
        catch (ex) {
            throw new InvalidUserDataException("You should define KEYSTORE_PASSWORD and KEY_PASSWORD in gradle.properties.")
        }
    }
}

Retrolambda

dependencies {
    classpath 'me.tatarka:gradle-retrolambda:2.4.+'
}
apply plugin: 'retrolambda'

android {
    compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}

retrolambda {
    jdk System.getenv("JAVA8_HOME")
    oldJdk System.getenv("JAVA7_HOME")
    javaVersion JavaVersion.VERSION_1_7
}

Activities and Fragments

Square even has a library for building architectures mostly with Views,

  • Avoid using nested fragments extensively,because matryoshka bugs can occur;
  • Avoid putting too much code in activities.

Java packages architecture

com.futurice.project
├─ network
├─ models
├─ managers
├─ utils
├─ fragments
└─ views
   ├─ adapters
   ├─ actionbar
   ├─ widgets
   └─ notifications

Resources

Naming:

fragment_contact_details.xml
view_primary_button.xml
activity_main.xml

Organizing layout XMLs.

  • android:id as the first attribute always
  • android:layout_** attribute at the top
  • style attribute at the bottom
  • Tag closer /> on its own line.
  • Rather then hard coding android:text,using Designtime attributes

#####Designtime attributes

These are attributes which are used when the layout is rendered in the tool,but have no impact on the runtime.

How to use it

  1. Add xmlns:tools="http://schemas.android.com/tools" to root layout
  2. Use the tools: namespace rather than the android: namespace:
  3. In general, you can set any Android framework attribute as a designtime attribute;

tools:layout

<fragment android:name="com.example.master.ItemListFragment" tools:layout="@android:layout/list_content" />

tools:listitem / listheader / listfooter

<ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:listitem="@android:layout/simple_list_item_2"
		/>

tools:showIn Can look the effect in the parent activity_main

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:text="@string/hello_world"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    tools:showIn="@layout/activity_main" />

tools:menu

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:menu="menu1,menu2" />

Use styles

  • Note to accumulate common use Style
  • Split a large style file into other files
styles_home.xml
styles_item_details.xml
styles_forms.xml

Colors.xml colors.xml than just a mapping from a color name to an RGBA value.Names such as "brand_primary", "brand_secondary", "brand_negative" are totally acceptable as well. Formatting colors as such will make it easy to change or refactor colors

  • Bad
<resources>
    <color name="button_foreground">#FFFFFF</color>
    <color name="button_background">#2A91BD</color>
    <color name="comment_background_inactive">#5F5F5F</color>
    <color name="comment_background_active">#939393</color>
  • Good
 <!-- basic colors -->
    <color name="green">#27D34D</color>
    <color name="blue">#2A91BD</color>
    <color name="orange">#FF9D2F</color>
    <color name="red">#FF432F</color>

Treat dimens.xml like colors.xml.

<resources>
    <!-- font sizes -->
    <dimen name="font_larger">22sp</dimen>
    <dimen name="font_large">18sp</dimen>
    <dimen name="font_normal">15sp</dimen>
    <dimen name="font_small">12sp</dimen>

    <!-- typical spacing between two views -->
    <dimen name="spacing_huge">40dp</dimen>
    <dimen name="spacing_large">24dp</dimen>
    <dimen name="spacing_normal">14dp</dimen>
    <dimen name="spacing_small">10dp</dimen>
    <dimen name="spacing_tiny">4dp</dimen>

    <!-- typical sizes of views -->
    <dimen name="button_height_tall">60dp</dimen>
    <dimen name="button_height_normal">40dp</dimen>
    <dimen name="button_height_short">32dp</dimen>
</resources>

Strings.xml

  • Name your strings with keys that resemble namespaces, and don't be afraid of repeating a value for two or more keys. Languages are complex, so namespaces are necessary to bring context and break ambiguity.
    Bad
<string name="network_error">Network error</string>
<string name="call_failed">Call failed</string>
<string name="map_failed">Map loading failed</string>

**Good **

<string name="error.message.network">Network error</string>
<string name="error.message.call">Call failed</string>
<string name="error.message.map">Map loading failed</string>
  • Don't write string values in all uppercase.
    Bad
<string name="error.message.call">CALL FAILED</string>

Good

<string name="error.message.call">Call failed</string>

Use <merge>Tag

<merge xmlns:android="http://schemas.android.com/apk/res/android">
    <ImageView
        android:id="@+id/imgLoader"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:layout_centerInParent="true"
        android:src="@drawable/ico_loader" />
</merge>

Beware of problems related to WebViews. WebViews can also leak memory

public class TestActivity extends Activity {
    private FrameLayout mWebContainer;
    private WebView mWebView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.your_layout);

        mWebContainer = (FrameLayout) findViewById(R.id.web_container);
        mWebView = new WebView(getApplicationContext());
        mWebContainer.addView(mWebView);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mWebContainer.removeAllViews();
        mWebView.destroy();
    }
}

Test frameworks

ProGuard can cause application crash when thd build command is succeeded : ClassNotFoundException, NoSuchFieldException, similar etc.

**What's you can do **

  • See the ProGuard remove app/build/outputs/proguard/release/usage.txt
  • See the ProGuard obfuscated: app/build/outputs/proguard/release/usage.txt

Common configure To prevent ProGuard from

  • stripping classes or class members,

-keep class com.futurice.project.MyClass { *; }

  • obfuscating classes or class members,

-keepnames class com.futurice.project.MyClass { *; }

Tips.

  • Save the mapping.txt ==> when app crash you can see the obuscated stack trace.

Data storage

SharedPreferences There are two reasons why you might not want to use ShareP

  • Data is complex, or a lot of
  • Multiple processes accessing the data:

ContentProviders

ContentProviders are fast and process safe. to generate the ContentProvider by using a library such as schematic .

Using an ORM

  • Not recommend, unless you have unusually complex data and you have a dire need.
  • They tend to be complex and require time to learn.
  • whether or not it is process safe if your application requires it
⚠️ **GitHub.com Fallback** ⚠️