Contents

Android Development Notes

Table of Contents

Basics

  1. Layout is typically defined in XML, whereas activities are in Java class.

  2. The Android operating system is a multi-user Linux system in which each app is a different user.

App Resources

  1. String array: android:entries="@array/foo".

    1
    2
    3
    4
    
    <string-array name="foo">
        <item>bar1</item>
        <item>bar2</item>
    </string-array>
    
  2. Creating alias resources:

    1
    2
    3
    4
    
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <drawable name="icon">@drawable/icon_ca</drawable>
    </resources>
    
  3. Styles and Themes

  4. Referencing style attributes: android:textColor="?android:textColorSecondary

  5. Support different pixel densities

  6. Declare restricted screen support

Permissions

  1. Request App Permissions

  2. Use an intent instead

Gradle

  1. compileSdkVersion vs targetSdkVersion vs minSdkVersion:
    • compileSdkVersion: The app can use all the API features from this version and lower.
    • targetSdkVersion: The version we’ve tested our app.
    • minSdkVersion: The minimum version the app can support.

Layout

  1. <EditText> is an editable text field:

    • android:hint="@string/hint": normally “Enter a message”, telling the user what to type;
    • android:ems="10": 10-M space.
  2. android:layout_weight="number" makes a view stretch.

    • If a has the weight of 1 and b has 2, a’ll have 1/3 and b’ll have 2/3 of the screen.
    • We usually have android:layout_height="0dp" (for vertical layout) above layout_weight.
  3. android:gravity="top" moves the CONTENT of a view to the top of the view, whereas android:layout_gravity="end" moves the placement of the VIEW itself to the end.

  4. <FrameLayout></FrameLayout> allows views to overlap. Ues it when we need to replace the fragments and add the changes to the back stack.

  5. Surround LinearLayout/FrameLayout with <ScrollView></ScrollView> to get a vertical scrollbar. (HorizontalScrollView for the horizontal scrollbar.)

  6. A CoordinatorLayout allows the behavior of one view to affect the behavior of another.

  7. AdapterView:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
        android.R.layout.simple_list_item_1, myStringArray);
    ListView listView = (ListView) findViewById(R.id.listview);
    listView.setAdapter(adapter)
    // Create a message handling object as an anonymous class.
    private OnItemClickListener messageClickedHandler = new OnItemClickListener() {
        public void onItemClick(AdapterView parent, View v, int position, long id) {
        // Do something in response to the click
        }
    };
    
    listView.setOnItemClickListener(messageClickedHandler);
    
  8. Create a List with RecyclerView

  9. Re-using layouts with include: <merge></merge> <include layout="@layout/foo"/>

  10. Spinners:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    
    Spinner s1 = (Spinner) findViewById(R.id.spinner1);
    ArrayAdapter adapter = ArrayAdapter.createFromResource(
    this, R.array.colors, android.R.layout.simple_spinner_item);
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    s1.setAdapter(adapter);
    s1.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            // TODO
        }
    
        @Override
        public void onNothingSelected(AdapterView<?> parent) {
           // sometimes you need nothing here
        }
    });
    
  11. Buttons Set onClick programmatically:

    1
    2
    3
    4
    5
    6
    
    Button button = (Button) findViewById(R.id.button_send);
    button.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            // Do something in response to button click
        }
    });
    
    1
    2
    3
    4
    5
    6
    7
    
    findViewById(R.id.button_send).setOnClickListener {
        foo(it)
    }
    // or
    findViewById(R.id.button_send).setOnClickListener { view ->
        //...
    }
    
  12. Checkboxes

  13. Radio Buttons

  14. Switch Buttons

    1
    2
    3
    
    android:checked="true"
    android:textOff="OFF"
    android:textOn="ON
    
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    Switch sw = (Switch) findViewById(R.id.switch1);
    sw.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            if (isChecked) {
                // The toggle is enabled
            } else {
                // The toggle is disabled
            }
        }
    });
    
  15. Pickers (Time/Date Pickers)

  16. Centralized onClick events:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    
    public class ActivityA extends Activity implements View.OnClickListener {
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            findViewById(R.id.first).setOnClickListener(this);
            findViewById(R.id.second).setOnClickListener(this);
            findViewById(R.id.third).setOnClickListener(this);
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.first:
                    // Manage click.
                    break;
    
                case R.id.second:
                    // Manage click.
                    break;
    
                case R.id.third:
                    // Manage click.
                    break;
            }
        }
    }
    
  17. App bar:

    • Set up the app bar (Use Toolbar instead of the native ActionBar) and Add an up action

      1
      
      android:theme="@style/Theme.AppCompat.Light.NoActionBar"
      
      1
      2
      3
      4
      5
      6
      7
      8
      
      <android.support.v7.widget.Toolbar
          android:id="@+id/my_toolbar"
          android:layout_width="match_parent"
          android:layout_height="?attr/actionBarSize"
          android:background="?attr/colorPrimary"
          android:elevation="4dp"
          android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
          app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
      
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      
          <!-- A child of the main activity -->
      <activity
         android:name="com.example.myfirstapp.MyChildActivity"
         android:label="@string/title_activity_child"
         android:parentActivityName="com.example.myfirstapp.MainActivity" >
      
      <!-- Parent activity meta-data to support 4.0 and lower -->
          <meta-data
              android:name="android.support.PARENT_ACTIVITY"
              android:value="com.example.myfirstapp.MainActivity" />
      </activity>
      
      1
      2
      3
      4
      5
      6
      7
      8
      
      // OnCreate
      Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
      setSupportActionBar(myToolbar);
          // Get a support ActionBar corresponding to this toolbar
      ActionBar ab = getSupportActionBar();
      
      // Enable the Up button
      ab.setDisplayHomeAsUpEnabled(true);
      
    • Add and handle actions

  18. Toasts: Toast toast = Toast.makeText(this, "hello world", Toast.LENGTH_SHORT); toast.show();

Activities

  1. All activities have to extend the Activity class or its subclass.

  2. R is a special Java class that enables you to retrieve references to resources. TextView foo = findViewById(R.id.foo)

  3. Use Intent to call another activity (can be from other apps):

    • Explicit intent:

      1
      2
      3
      4
      5
      
      public void onSendMessage(View view) {
          Intent intent = new Intent(this, FooActivity.class); // explicit intent
          intent.putExtra("message", value); // message is the name of the extra
          startActivity(intent);
      }
      
      1
      2
      3
      
      ...
      Intent intent = getIntent();
      String string = intent.getStringExtra("message");
      
    • Implicit intent: (with actions to allow users to choose which app to run)

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      
      Intent intent = new Intent(Intent.ACTION_SEND); // ACTION_DIAL/ACTION_WEB_SEARCH
      intent.setType("text/plain");
      intent.putExtra(Intent.EXTRA_TEXT, messageText);
      String chooserTitle = getString(R.string.chooser);
      // Ensure that the user always get the chance to choose an activity
      Intent chosenIntent = Intent.createChooser(intent, chooserTitle);
      
      // Start an activity if it's safe
      if (intent.resolveActivity(getPackageManager()) != null) {
          startActivity(chosenIntent);
      }
      
    • Common Intents

  4. Save the instance state:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
    // Either in onCreate savedInstanceState != null or use the method below
    public void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        seconds = savedInstanceState.getInt("seconds");
        running = savedInstanceState.getBoolean("running");
    }
    
    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        super.onSaveInstanceState(savedInstanceState);
        savedInstanceState.putInt("seconds", seconds);
        savedInstanceState.putBoolean("running", running);
    }
    
  5. Activity lifecycle:

    • When we implement them (onCreate(), onStart(), onResume(), onPause(), onStop(), onRestart(), onDestroy()), we must call the super class methods.
    • onResume() is called when the activity is started OR resumed; onPause() is called when the activity is paused OR stopped.
    • /images/activity_lifecycle.png
  6. Defining launch modes (singleTop, singleTask, etc.)

Fragments

  1. Fragment lifecycle:

    /images/fragment_lifecycle.png

  2. Example:

    1
    2
    3
    4
    5
    6
    7
    8
    
    public static class ExampleFragment extends Fragment {
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            // Inflate the layout for this fragment
            return inflater.inflate(R.layout.example_fragment, container, false);
            // In this case, this is false because the system is already inserting the inflated layout into the container
        }
    }
    
  3. Add the fragment programmatically:

    1
    2
    3
    4
    5
    
    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
    ExampleFragment fragment = new ExampleFragment();
    fragmentTransaction.add(R.id.fragment_container, fragment);
    fragmentTransaction.commit();
    
  4. Fragment transactions:

    • Example:

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      
      // Create new fragment and transaction
      Fragment newFragment = new ExampleFragment();
      FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
      
      // Replace whatever is in the fragment_container view with this fragment,
      // and add the transaction to the back stack
      transaction.replace(R.id.fragment_container, newFragment);
      transaction.addToBackStack(null);
      
      // Commit the transaction
      transaction.commit();
      
  5. For dynamic fragments, use FrameLayout instead of Fragment and use FragmentTransaction.

Notifications

  1. Create a Notification

Android Studio Tips

  1. Improve code inspection with annotations (@Nullable, @NonNull…)

  2. Find sample code

  3. Tools attributes reference (tools:text="foo", tools:itemCount="3"...)

  4. Debug your app ( private static final String TAG = "MyActivity"; Log.d(TAG, "foo");)

  5. Write and View Logs with Logcat (e (error), w (warning), i (information), d (debug), v (verbose))

  6. Debug Your layout with Layout Inspector

  7. Manage your app’s UI resources with Resource Manager

  8. Create app icons with Image Asset Studio

  9. Create resizable bitmaps (9-Patch files)

  10. Add Android App Links

Miscellaneous

  1. Android builds the back stack to keep track of the activity/fragment transactions.

  2. Create Deep Links to App Content:

    1
    2
    3
    4
    5
    
    <intent-filter>
      ...
      <data android:scheme="https" android:host="www.example.com" />
      <data android:scheme="app" android:host="open.my.app" />
    </intent-filter>
    
  3. Verify Android App Links

  4. Adding Swipe-to-Refresh To Your App (Add SwipeRefreshLayout as the parent of a single ListView or GridView.) (android.support.v4.widget.SwipeRefreshLayout)

  5. Responding to Refresh Request

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    mySwipeRefreshLayout.setOnRefreshListener(
        new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                Log.i(LOG_TAG, "onRefresh called from SwipeRefreshLayout");
    
                // This method performs the actual data-refresh operation.
                // The method calls setRefreshing(false) when it's finished.
                myUpdateOperation();
            }
        }
    );
    
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    // For refreshing in the app bar
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
    
            // Check if user triggered a refresh:
            case R.id.menu_refresh:
                Log.i(LOG_TAG, "Refresh menu item selected");
    
                // Signal SwipeRefreshLayout to start the progress indicator
                mySwipeRefreshLayout.setRefreshing(true);
    
                // Start the refresh background task.
                // This method calls setRefreshing(false) when it's finished.
                myUpdateOperation();
    
                return true;
        }
    
        // User didn't trigger a refresh, let the superclass handle this action
        return super.onOptionsItemSelected(item);
    }
    

Resources