Posts Tagged ‘Android’
[KotlinConf2025] Code Quality at Scale: Future Proof Your Android Codebase with KtLint and Detekt
Managing a large, multi-team codebase is a monumental task, especially when it has evolved over many years. Introducing architectural changes and maintaining consistency across autonomous teams adds another layer of complexity. In a comprehensive discussion, Tristan Hamilton, a distinguished member of the HubSpot team, presented a strategic approach to future-proofing Android codebases by leveraging static analysis tools like KtLint and Detekt.
Tristan began by framing the challenges inherent in a codebase that has grown and changed for over eight years. He emphasized that without robust systems, technical debt can accumulate, and architectural principles can erode as different teams introduce their own patterns. The solution, he proposed, lies in integrating automated guardrails directly into the continuous integration (CI) pipeline. This proactive approach ensures a consistent level of code quality and helps prevent the introduction of new technical debt.
He then delved into the specifics of two powerful static analysis tools: KtLint and Detekt. KtLint, as a code linter, focuses on enforcing consistent formatting and style, ensuring that the codebase adheres to a single, readable standard. Detekt, on the other hand, is a more powerful static analysis tool that goes beyond simple style checks. Tristan highlighted its ability to perform advanced analysis, including type resolution, which allows it to enforce architectural patterns and detect complex code smells that a simple linter might miss. He shared practical examples of how Detekt can be used to identify and refactor anti-patterns, such as excessive class size or complex methods, thereby improving the overall health of the codebase.
A significant part of the talk was dedicated to a specific, and crucial, application of these tools: safely enabling R8, the code shrinker and optimizer, in a multi-module Android application. The process is notoriously difficult and can often lead to runtime crashes if not handled correctly. Tristan showcased how custom Detekt rules could be created to enforce specific architectural principles at build time. For instance, a custom rule could ensure that certain classes are not obfuscated or that specific dependencies are correctly handled, effectively creating automated safety nets. This approach allowed the HubSpot team to gain confidence in their R8 configuration and ship with greater speed and reliability.
Tristan concluded by offering a set of key takeaways for developers and teams. He underscored the importance of moving beyond traditional static analysis and embracing tools that can codify architectural patterns. By automating the enforcement of these patterns, teams can ensure the integrity of their codebase, even as it grows and evolves. This strategy not only reduces technical debt but also prepares the codebase for future changes, including the integration of new technologies and methodologies, such as Large Language Model (LLM) generated code. It is a powerful method for building robust, maintainable, and future-ready software.
Links:
[KotlinConf2023] Transforming Farmers’ Lives in Kenya: Apollo Agriculture’s Android Apps with Harun Wangereka
Harun Wangereka, a Software Engineer at Apollo Agriculture and a Google Developer Expert for Android, delivered an inspiring presentation at KotlinConf’23 about how his company is leveraging Android technology to change the lives of farmers in Kenya. His talk detailed Apollo Agriculture’s two core Android applications, built entirely in Kotlin, which are offline-first and utilize server-driven UI (SDUI) with Jetpack Compose to cater to the unique challenges of their user base. Harun is also active in Droidcon Kenya.
Apollo Agriculture’s mission is to empower small-scale farmers by bundling financing, high-quality farm inputs, agronomic advice, insurance, and market access. Their tech-based approach uses satellite data and machine learning for credit decisions and automated operations to maintain low costs and scalability. The customer journey involves signup via agents or SMS/USSD, kyc data collection (including GPS farm outlines), automated credit decisions (often within minutes), input pickup from agro-dealers, digital advice via voice trainings, and loan repayment post-harvest.
Addressing Unique Challenges in the Kenyan Context
Harun highlighted several critical challenges that shaped their app development strategy:
* Low-Memory Devices: Many agents and farmers use entry-level Android devices with limited RAM and storage. The apps need to be lightweight and performant.
* Low/Intermittent Internet Bandwidth: Internet connectivity can be unreliable and expensive. An offline-first approach is crucial, allowing agents to perform tasks without constant internet access and sync data later.
* Diverse User Needs and Rapid Iteration: The agricultural domain requires frequent updates to forms, workflows, and information provided to farmers and agents. A flexible UI system that can be updated without frequent app releases is essential.
These challenges led Apollo Agriculture to adopt a server-driven UI (SDUI) approach. Initially implemented with Anko (a deprecated Kotlin library for Android UI), they later rewrote this system entirely using Jetpack Compose.
Server-Driven UI with Jetpack Compose
The core of their SDUI system relies on JSON responses from the server that define the UI components, their properties, validations, and conditional logic.
Key aspects of their implementation include:
* Task-Based Structure: The app presents tasks to agents (e.g., onboarding a farmer, collecting survey data). Each task is represented by a JSON schema from the server.
* Dynamic Form Rendering: The JSON schema defines various UI elements like text inputs, number inputs, date pickers, location pickers (with map integration for capturing farm boundaries), image inputs (with compression), and more. These are dynamically rendered using Jetpack Compose.
* Stateful Composable Components: Harun detailed their approach to building stateful UI components in Compose. Each question or input field manages its own state (value, errors, visibility) using remember and mutableStateOf. Validation logic (e.g., required fields, min/max length) is also defined in the JSON and applied dynamically.
* Triggers and Conditionals: The JSON schema supports triggers (e.g., “on save”) and complex conditional logic using an internal tool called “Choice Expressions” and an implementation of JSON Schema. This allows UI elements or entire sections to be shown/hidden or enabled/disabled based on user input or other conditions, enabling dynamic and context-aware forms.
* Offline First: Task schemas and user data are stored locally, allowing full offline functionality. Data is synced with the server when connectivity is available.
* Testing: They extensively test their dynamic UI components and state logic in isolation, verifying state changes, validation behavior, and conditional rendering.
Harun shared examples of the JSON structure for defining UI elements, properties (like labels, hints, input types), validators, and conditional expressions. He walked through how a simple text input composable would manage its state, handle user input, and apply validation rules based on the server-provided schema.
Learnings and Future Considerations
The journey involved migrating from Anko to Jetpack Compose for their SDUI renderer, which Compose’s reactive DSL made more manageable and maintainable. They found Compose to be well-suited for building dynamic, stateful UIs.
Challenges encountered included handling keyboard interactions smoothly with scrolling content and managing the complexity of deeply nested conditional UIs.
When asked about open-sourcing their powerful form-rendering engine, Harun mentioned it’s a possibility they are considering, as the core logic is already modularized, and community input could be valuable. He also noted that while some pricing information is dynamic (e.g., based on farm size), they try to standardize core package prices to avoid confusion for farmers.
Harun Wangereka’s talk provided a compelling case study of how Kotlin and Jetpack Compose can be used to build sophisticated, resilient, and impactful Android applications that address real-world challenges in demanding environments.
Links:
[KotlinConf2019] Simplifying Async APIs with Kotlin Coroutines
Tom Hanley, a senior software engineer at Toast, enthralled KotlinConf2019 with a case study on using Kotlin coroutines to tame a complex asynchronous API for an Android card reader. Drawing from his work integrating a third-party USB-connected card reader, Tom shared how coroutines transformed callback-heavy code into clean, sequential logic. His practical insights on error handling, debugging, and testing offered a roadmap for developers grappling with legacy async APIs.
Escaping Callback Hell
Asynchronous APIs often lead to callback hell, where nested callbacks make code unreadable and error-prone. Tom described the challenge of working with a third-party Android SDK for a card reader, which relied on void methods and listener interfaces for data retrieval. A naive implementation to fetch device info involved mutable variables and blocking loops, risking infinite loops and thread-safety issues. Such approaches, common with legacy APIs, complicate maintenance and scalability. Tom emphasized that coroutines offer a lifeline, allowing developers to wrap messy APIs in a clean, non-blocking interface that reads like sequential code, preserving the benefits of asynchrony.
Wrapping the Card Reader API with Coroutines
To streamline the card reader API, Tom developed a Kotlin extension that replaced callback-based interactions with suspend functions. The original API required a controller to send commands and a listener to receive asynchronous responses, such as device info or errors. By introducing a suspend getDeviceInfo function, Tom enabled callers to await results directly. This extension ensured referential transparency, where functions clearly return their results, and allowed callers to control asynchrony—waiting for completion or running tasks concurrently. The approach also enforced sequential execution for dependent operations, critical for the card reader’s connection and transaction workflows.
Communicating with Channels
Effective inter-thread communication was key to the extension’s success. Rather than relying on shared mutable variables, Tom used Kotlin channels to pass events and errors between coroutines. When the listener received device info, it sent the data to a public channel; errors were handled similarly. The controller extension used a select expression to await the first event from either the device info or error channel, throwing errors or returning results as needed. Channels, with their suspending send and receive operations, provided a thread-safe alternative to blocking queues. Despite their experimental status in Kotlin 1.3, Tom found them production-ready, supported by smooth IDE migration paths.
Mastering Exception Handling
Exception handling in coroutines requires careful design, as Tom learned through structured concurrency introduced in Kotlin 1.3. This feature enforces a parent-child relationship, where canceling a parent coroutine cancels its children. However, Tom discovered that a child’s failure propagates upward, potentially crashing the app in launch coroutines if uncaught. For async coroutines, exceptions are deferred until await is called, allowing try-catch blocks to handle them. To isolate failures, Tom used supervisorJob to prevent child cancellations from affecting siblings and coroutineScope blocks to group all-or-nothing operations, ensuring robust error recovery for the card reader’s unreliable USB connection.
Debugging and Testing Coroutines
Debugging coroutines posed initial challenges, but Tom leveraged powerful tools to simplify the process. Enabling debug mode via system properties assigns unique names to coroutines, appending them to thread names and enhancing stack traces with creation details. The debug agent, a JVM tool released post-project, tracks live coroutines and dumps their state, aiding deadlock diagnosis. For testing, Tom wrapped suspend functions in runBlocking blocks, enabling straightforward unit tests. He advised using launch and async only when concurrency is needed, marking functions as suspend to simplify testing by allowing callers to control execution context.
Moving Beyond Exceptions with Sealed Classes
Reflecting on exception handling’s complexity, Tom shifted to sealed classes for error handling. Initially, errors from the card reader were wrapped in exceptions, but frequent USB failures made catching them cumbersome. Exceptions also obscured control flow and hindered functional purity. Inspired by arguments likening exceptions to goto statements, Tom adopted domain-specific sealed classes (e.g., Success, Failure, Timeout) for each controller command’s result. This approach enforced explicit error handling via when statements, improved readability, and allowed result types to evolve independently, aligning with the card reader’s diverse error scenarios.
Links:
[DevoxxBE2013] Architecting Android Applications with Dagger
Jake Wharton, an Android engineering luminary at Square, champions Dagger, a compile-time dependency injector revolutionizing Java and Android modularity. Creator of Retrofit and Butter Knife, Jake elucidates Dagger’s divergence from reflection-heavy alternatives like Guice, emphasizing its speed and testability. His session overviews injection principles, Android-specific scoping, and advanced utilities like Lazy and Assisted Injection, arming developers with patterns for clean, verifiable code.
Dagger, Jake stresses, decouples class behaviors from dependencies, fostering reusable, injectable components. Through live examples, he builds a Twitter client, showcasing modules for API wrappers and HTTP clients, ensuring seamless integration.
Dependency Injection Fundamentals
Jake defines injection as externalizing object wiring, promoting loose coupling. He contrasts manual factories with Dagger’s annotation-driven graphs, where @Inject fields auto-resolve dependencies.
This pattern, Jake demonstrates, simplifies testing—mock modules swap implementations effortlessly, isolating units.
Dagger in Android Contexts
Android’s lifecycle demands scoping, Jake explains: @Singleton for app-wide instances, activity-bound for UI components. He constructs an app graph, injecting Twitter services into activities.
Fragments and services, he notes, inherit parent scopes, minimizing boilerplate while preserving encapsulation.
Advanced Features and Utilities
Dagger’s extras shine: @Lazy defers creation, @Assisted blends factories with injection for parameterized objects. Jake demos provider methods in modules, binding interfaces dynamically.
JSR-330 compliance, augmented by @Module, ensures portability, though Jake clarifies Dagger’s compile-time limits preclude Guice’s AOP dynamism.
Testing and Production Tips
Unit tests leverage Mockito for mocks, Jake illustrates, verifying injections without runtime costs. Production graphs, he advises, tier via subcomponents, optimizing memory.
Dagger’s reflection-free speed, Jake concludes, suits resource-constrained Android, with Square’s hiring call underscoring real-world impact.
Links:
Conférence Devoxx: Introduction aux Google Glass
J’ai eu la chance d’assister à l’édition 2014 de Devoxx FR.
La première conférence que j’ai suivie était “Introduction aux Google Glass”, par Alain Régnier (@AltoLabs, +AlainRegnier), dont voici un résumé:
Alain fait partie d’un programme, les Google Glass Explorers, c’est-à-dire les heureux élus qui ont pu se procurer des paires de lunettes Google Glass. Théoriquement, seuls les résidents nord-américains peuvent souscrire au programme ; néanmoins, l’estimation du nombre de Google Glass circulant en France oscille entre 30 et 50 paires.
A mi-chemin entre des lunettes Star Trek et des scouters de Dragon Ball, les Google Glass ressemblent à des lunettes classiques dont l’une des branche est plus épaisse et dont un verre est surmonté d’un prisme et d’une mini-webcam. Le petit bijou de technologie embarque, sous le capot, de nombreux capteurs et connecteurs: visuel, sonore, bluetooth, wifi, et même infrarouge.
Les Google Glass affichent par défaut des informations de quatre types: texte, image, vidéo et une version limitée d’HTML. Elles sont contrôlables de plusieurs façons: à la voix (en lançant le mot magique “OK Glass!”), via un trackpad, une application “web” MyGlassWeb ou enfin une appli Android MyGlassMobile.
En tant qu’outil de développement, un Android Screen Monitor (un simple client ADB) permet d’afficher sur l’écran du PC ce qui est visible par la personne portant les Google Glass: en d’autres termes, le flux de la webcam sur lequel est superposé l’affichage du prisme.
Concernant le développement proprement dit, trois méthodes sont disponibles:
- Mirror API: les Glass communiquent avec un serveur hébergé par Google, qui redirige vers un serveur concret
- GDK: il s’agit d’un kit de développement similaire à celui d’Android
- WearScript: c’est une librairie, non-officielle, permettant de programmer les Glass en JavaScript
Alain a réalisé une démonstration d’utilisation des Glass. Avouons-le: c’est bluffant… En tant que développeur, les perspectives ouvertes par un tel objet connecté sont très enthousiasmantes! Le plus dur va encore être d’attendre que les Glass soient officiellement disponibles dans nos contrées européennes…
[DevoxxFR2013] NFC: Facilitating Mobile Interactions with the Environment
Lecturer
Romain Menetrier is a developer passionate about internet and mobile platforms. He co-organizes the Paris Android User Group and founded Macala for mobile solutions. Previously CTO at Connecthings, a European NFC leader, he now serves as NFC solutions architect at Orange.
Abstract
Romain Menetrier’s talk introduces Near Field Communication (NFC), tracing its RFID and smart card roots while focusing on mobile implementations, especially Android. He demonstrates practical uses like payments and data exchange, explaining standards, tag types, and Android APIs. Through live examples, he highlights NFC’s security via proximity and contextual potential, advocating its adoption for simplified interactions.
Origins and Fundamentals: From RFID to NFC Standards
Menetrier traces NFC to RFID and contactless cards, operating via magnetic field modulation at under 10cm for security—requiring physical presence. An antenna induces power in passive tags, enabling data return without batteries.
Standards: ISO 14443 (cards), 15693 (tags), with modes like reader/writer (phone reads/writes tags), peer-to-peer (device-to-device), and card emulation (phone as card). Frequencies at 13.56MHz allow small antennas in phones.
Tag types vary: Type 1-4 differ in capacity (48B to 32KB), speed, and protocols. NDEF (NFC Data Exchange Format) standardizes data as records with type, ID, payload—e.g., URLs, text, MIME.
Android drives diffusion: since Gingerbread, APIs handle intents on tag discovery, enabling apps to read/write without foreground requirements via tech-lists.
Practical Implementations: Android Apps for Tag Interaction and Peer-to-Peer
Menetrier demos Android apps: reading tags dispatches intents; apps filter via manifests for specific techs (e.g., NfcA). Reading parses NDEF messages into records, extracting payloads like URLs for browser launch.
Writing: create NDEF records (e.g., URI), form messages, write via NfcAdapter. Locking tags prevents overwrites.
Peer-to-peer uses Android Beam (SNEP protocol): share data by touching devices. Implement via CreateNdefMessageCallback for message creation, OnNdefPushCompleteCallback for confirmation.
Code snippet:
NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);
adapter.setNdefPushMessageCallback(new CreateNdefMessageCallback() {
@Override
public NdefMessage createNdefMessage(NfcEvent event) {
return new NdefMessage(new NdefRecord[]{createUriRecord("http://example.com")});
}
}, this);
This enables URL sharing.
Security: short range thwarts remote attacks; presence confirms intent. Contexts from tag locations enhance applications, like venue-specific info.
Everyday Applications and Future Prospects: Payments, Access, and Tracking
Common uses: payments (e.g., Cityzi in France, emulating cards via SIM-secured elements), transport (Navigo integration), access control (badges). Tags in ads track interactions, gauging interest beyond views.
Enterprise: unified NFC cards for canteen, entry—multiple IDs on one chip. Phones emulate cards, even off (via SIM linkage), blockable remotely.
Challenges: ecosystem fragmentation (operators control SIM), but growing adoption. Menetrier sees NFC simplifying interactions, with Android pivotal.
In summary, NFC’s proximity fosters secure, contextual mobile-environment links, poised for widespread use.
Relevant Links and Hashtags
Links:
[DevoxxFR2012] Android Lifecycle Mastery: Advanced Techniques for Services, Providers, and Optimization
Lecturer
Mathias Seguy founded Android2EE, specializing in Android training, expertise, and consulting. Holding a PhD in Fundamental Mathematics and an engineering degree from ENSEEIHT, he transitioned from critical J2EE projects—serving as technical expert, manager, project leader, and technical director—to focus on Android. Mathias authored multiple books on Android development, available via Android2ee.com, and contributes articles to Developpez.com.
Abstract
This article explores Mathias Seguy’s in-depth coverage of Android’s advanced components, focusing on service modes, content provider implementations, and optimization strategies. It examines unbound/bound services, URI-based data operations, and tools like Hierarchy Viewer for performance tuning. Within Android’s multitasking framework, the analysis reviews methodologies for lifecycle alignment, asynchronous execution, and resource handling. Through practical code and debugging insights, it evaluates impacts on battery efficiency, data security, and UI responsiveness. This segment underscores patterns for robust architectures, aiding developers in crafting seamless, power-efficient mobile experiences.
Differentiating Service Modes and Lifecycle Integration
Services bifurcate into unbound (autonomous post-start) and bound (interactive via binding). Mathias illustrates unbound for ongoing tasks like music playback:
startService(new Intent(this, MyService.class));
Bound for client-service dialogue:
private ServiceConnection connection = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder service) {
myService = ((MyBinder) service).getService();
}
public void onServiceDisconnected(ComponentName name) {
myService = null;
}
};
bindService(new Intent(this, MyBoundService.class), connection, BIND_AUTO_CREATE);
Lifecycle syncing uses flags: isRunning/isPaused toggle with onStartCommand()/onDestroy(), ensuring tasks halt on service termination, averting leaks.
Constructing Efficient Content Providers
Providers facilitate inter-app data exchange via URIs. Define via extension, with UriMatcher for parsing:
private static final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
matcher.addURI(AUTHORITY, TABLE, COLLECTION);
matcher.addURI(AUTHORITY, TABLE + "/#", ITEM);
}
Implement insert():
@Override
public Uri insert(Uri uri, ContentValues values) {
long rowId = db.insert(DBHelper.MY_TABLE, null, values);
if (rowId > 0) {
Uri result = ContentUris.withAppendedId(CONTENT_URI, rowId);
getContext().getContentResolver().notifyChange(result, null);
return result;
}
throw new SQLException("Failed to insert row into " + uri);
}
Manifest exposure with authorities/permissions secures access.
Asynchronous Enhancements and Resource Strategies
AsyncTasks/Handlers offload UI: Extend for doInBackground(), ensuring UI updates in onPostExecute().
Resource qualifiers adapt to locales/densities: values-fr/strings.xml for French.
Databases: SQLiteOpenHelper with onCreate() for schema.
Debugging and Performance Tools
Hierarchy Viewer inspects UI hierarchies, identifying overdraws. DDMS monitors threads, heaps; LogCat filters logs.
Permissions: Declare in manifest for features like internet.
Architectural Patterns for Resilience
Retain threads across rotations; synchronize for integrity.
Implications: These techniques optimize for constraints, enhancing longevity and usability in diverse hardware landscapes.
Mathias’s guidance refines development, promoting sustainable mobile solutions.
Links:
[DevoxxFR2012] Advanced Android Patterns: Mastering Services, Content Providers, and Asynchronous Operations
Lecturer
Mathias Seguy founded Android2EE, specializing in Android training, expertise, and consulting. Holding a PhD in Fundamental Mathematics and an engineering degree from ENSEEIHT, he transitioned from critical J2EE projects—serving as technical expert, manager, project leader, and technical director—to focus on Android. Mathias authored multiple books on Android development, available via Android2ee.com, and contributes articles to Developpez.com.
Abstract
This article delves into Mathias Seguy’s continuation of essential Android development concepts, emphasizing services for background tasks, content providers for data sharing, and patterns for lifecycle synchronization. Building on foundational elements, it analyzes implementation strategies for bound/unbound services, CRUD operations in providers, and thread management with handlers/AsyncTasks. Within Android’s resource-constrained environment, the discussion evaluates techniques for internationalization, resource optimization, and database integration. Through detailed code examples, it assesses implications for application responsiveness, data integrity, and cross-app interoperability, guiding developers toward efficient, maintainable architectures.
Implementing Services for Background Processing
Services enable persistent operations independent of UI, running in the application’s main thread—necessitating offloading to avoid ANRs. Mathias distinguishes unbound (started via startService(), autonomous) from bound (via bindService(), allowing communication).
Lifecycle binding is critical: Align service states with calling components using booleans for running/pausing. Code for an unbound service:
public class MyService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Start task
return START_STICKY; // Restart if killed
}
@Override
public void onDestroy() {
// Cleanup
}
}
Bound services use Binder for IPC:
public class MyBoundService extends Service {
private final IBinder binder = new LocalBinder();
public class LocalBinder extends Binder {
MyBoundService getService() {
return MyBoundService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return binder;
}
}
These ensure tasks like downloads persist, enhancing user experience without freezing interfaces.
Crafting Content Providers for Data Exposure
Content providers standardize data access across apps, using URIs for queries. Mathias outlines creation: Extend ContentProvider, define URIs via UriMatcher.
CRUD implementation:
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables(DBHelper.MY_TABLE);
if (matcher.match(uri) == ITEM) {
qb.appendWhere(DBHelper.ID + "=" + uri.getLastPathSegment());
}
return db.query(qb.getTables(), projection, qb.getWhere(), selectionArgs, null, null, sortOrder);
}
Manifest declaration:
<provider
android:name=".MyProvider"
android:authorities="com.example.provider"
android:exported="true"
android:readPermission="com.example.READ"
android:writePermission="com.example.WRITE" />
This facilitates secure sharing, like contacts or media, promoting modular ecosystems.
Asynchronous Patterns and Resource Management
Asynchrony prevents UI blocks: Handlers for UI updates, AsyncTasks for background work. Pattern: Bind threads to activity lifecycles with flags.
onRetainNonConfigurationInstance() passes objects across rotations (pre-Fragments):
@Override
public Object onRetainNonConfigurationInstance() {
return myThread;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myThread = (MyThread) getLastNonConfigurationInstance();
if (myThread == null) {
myThread = new MyThread();
}
}
Resources: Externalize strings in values/strings.xml for localization; use qualifiers like values-fr for French.
These patterns optimize for device variability, ensuring fluid performance.
Database Integration and Permissions
SQLite via SQLiteOpenHelper manages schemas:
public class DBHelper extends SQLiteOpenHelper {
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + MY_TABLE + " (_id INTEGER PRIMARY KEY, name TEXT);");
}
}
Permissions in manifest control access, balancing security with functionality.
Testing and Project Management Strategies
Unit tests with JUnit; instrumentation via AndroidJUnitRunner. Maven for builds, Hudson/Jenkins for CI.
Implications: These foster reliable apps, mitigating fragmentation. In enterprise mobility, they enable scalable, secure solutions.
Mathias’s methodical breakdown equips developers for real-world challenges.
Links:
Move AVD default location on Windows
Two days ago, I twitted this:
Windows I hate you “PANIC: Could not open AVD config file”
Indeed, I tried to run an AVD (Android Virtual Device) from IntelliJ IDEA, in order to test my Android application. So far, I always ran AVD from KUbuntu, but a specific need I had to run on Windows Seven. The emulator could not start, because it was searching the actual AVD img file in the default folder, eg C:\Documents and Settings\<yourLogin>\.android\avd on Windows XP. Unfortunately, the folder could not be retrieved (a story of French special characters, such as ‘é’, ‘è’, ‘ç’, etc.).
Therefore, the question is: on Windows, how to change AVD default location?
I tried many more or less tricky solutions, but the simplest is the following:
- close IDEA and AVD Manager
- create an environment variable
ANDROID_SDK_HOME(keys Windows + Pause), pointing to your target folder, eg:D:\workarea\honeycomb-sdk - create a
.androidsubfolder, eg:D:\workarea\honeycomb-sdk\.android- if Windows does not allow you to create a folder of which name starts with a dot, then create it through Cygwin’s
mkdir.
- if Windows does not allow you to create a folder of which name starts with a dot, then create it through Cygwin’s
- startup IDEA
Restore GingerBread on a Nexus S “bricked” by CyanoGen
Case
After rooting my Nexus S, I tried to flash the ROM, in order to replace the genuine GingerBread with a CyanoGen ehanced version. This worked pretty well, but for a amazing reason I do not know, I missed the so-called “GApps”: GMail, GMaps, etc., this way a Nexus S (or any other Android-driven mobile device) losing any interest. Then, it was the worst catastrophic epiphenomenon I might fear: the Nexus was “bricked”. Indeed, the splash screen, with the Android robot on a skate, did not stop from looping…
Brick, Block and Pitfall
I tried to restore CyanoGen, wipe the memory, etc., but nothing efficient. At last I decided to restore a genuine Gingerbread version.
Here is the puzzling block that stands on the road: a Nexus S does not contain an actual (I mean physical) SD memory card. The “virtual” SD card must be mounted via ADB. But ADB does not recognize the device, since the Nexus is “bricked”. The only access to the Nexus appears to be FastBoot… which does not recognize the /sdcard folder. And the circle is complete.
As you understand, the key is to be able to mount /sdcard, which is sufficient to copy a ROM, and then apply it as a regular update.
Fix
Here we assume you have a minimal knownledge on how to use ADB and FastBoot:
- Download
recovery-clockwork-3.0.2.4-crespo.img - Download GingerBread original ROM:
da8206299fe6.signed-soju-ota-121341.da820629.zip - Switch on your Nexus in recovery mode (sound up and on/off buttons at the same time)
- Select “
recovery“ - Connect it to your PC
- On the PC:
fastboot boot ~/recovery-clockwork-3.0.2.4-crespo.img - Your phone reboots with a yellow on black console.
- Select “mounts and storage” > “mount usb storage”
- Now your PC detects the phone as a regular mass storage device.
- Copy GingerBread ROM to /sdcard folder.
- Rename it as
update.zip(optionnal, easier for the next step)
- On the PC:
fastboot boot ~/recovery-clockwork-3.0.2.4-crespo.img - On the phone,
- select the option “
apply update“ - select
update.zip
- select the option “
- Restart the phone
- If the phone freezes a long time, shut it down and switch it on again
- Now the regular Nexus splash screen should be OK
