A collection of subtle but important details I noticed while reading the Android developer documentation.
FragmentTransaction: Using the replace Method#
replace() removes all existing fragments in the container before adding the new one. Combined with addToBackStack(), the user can navigate back to the previous fragment.
1
2
3
4
| FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
transaction.commit();
|
Note: addToBackStack(null) pushes the entire transaction (not a single fragment) onto the back stack. Pressing back reverses all operations in the transaction.
Reference: FragmentTransaction API
BaseColumns in Database Contract Classes#
Table contract inner classes should implement BaseColumns to automatically include the _ID and _COUNT constants.
1
2
3
4
5
6
7
8
| /* Inner class that defines the table contents */
public static abstract class FeedEntry implements BaseColumns {
public static final String TABLE_NAME = "entry";
public static final String COLUMN_NAME_ENTRY_ID = "entryid";
public static final String COLUMN_NAME_TITLE = "title";
public static final String COLUMN_NAME_SUBTITLE = "subtitle";
...
}
|
Reference: BaseColumns API
Validating Implicit Intents Before Launching#
Always verify that at least one activity can handle an implicit Intent, or the app will crash with ActivityNotFoundException.
1
2
3
4
5
6
7
8
9
10
| PackageManager packageManager = getPackageManager();
List activities = packageManager.queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
boolean isIntentSafe = activities.size() > 0;
// Using a Chooser
Intent chooser = Intent.createChooser(intent, title);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(chooser);
}
|
Key differences:
queryIntentActivities() returns all matching activitiesresolveActivity() returns the best matching activity (or Chooser)
Reference: Intents and Intent Filters
Exposing an Activity to Third-Party Apps#
Declare intent-filters in the Manifest for other apps to call your Activity:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| <activity android:name="ShareActivity">
<!-- Handle sending SMS -->
<intent-filter>
<action android:name="android.intent.action.SENDTO"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="sms" />
<data android:scheme="smsto" />
</intent-filter>
<!-- Handle sharing text/images -->
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="image/*"/>
<data android:mimeType="text/plain"/>
</intent-filter>
</activity>
|
Handle the incoming intent based on type:
1
2
3
4
5
6
7
8
9
10
11
12
| @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
Uri data = intent.getData();
if (intent.getType().indexOf("image/") != -1) {
// Handle image data
} else if (intent.getType().equals("text/plain")) {
// Handle text
}
}
|
Return results to the caller:
1
2
3
4
| Intent result = new Intent("com.example.RESULT_ACTION",
Uri.parse("content://result_uri"));
setResult(Activity.RESULT_OK, result);
finish();
|
Correct Handler Usage#
If you create a Handler with new Handler() in an outer class, its Looper depends on the current thread. Without specifying a Looper, there’s no guarantee post(Runnable) runs on the main thread.
Recommended singleton pattern:
1
| private static Handler INSTANCE = new Handler(Looper.getMainLooper());
|
Always use Looper.getMainLooper() to explicitly target the main thread.
Reference: Handler API
WebView Automatically Requests Favicon on Every Page Load#
WebView sends these requests regardless of whether the page has a favicon (even from iframes):
1
2
3
| "GET /favicon.ico HTTP/1.1" 404 183
"GET /apple-touch-icon-precomposed.png HTTP/1.1" 404 197
"GET /apple-touch-icon.png HTTP/1.1" 404 189
|
Workaround#
Use a data URI to avoid unnecessary network requests:
1
| <link rel="icon" href="data:;base64,iVBORw0KGgo=">
|
This works across Safari, Chrome, and Firefox.
Background: Browsers request favicons after page load by default. Android WebView, being based on Chromium, exhibits the same behavior.
References: