<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Eduardo Soares on Medium]]></title>
        <description><![CDATA[Stories by Eduardo Soares on Medium]]></description>
        <link>https://medium.com/@eduardosoares_88255?source=rss-27347c716bc1------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*1qiEV5jB816EYVyOpgmFFw.png</url>
            <title>Stories by Eduardo Soares on Medium</title>
            <link>https://medium.com/@eduardosoares_88255?source=rss-27347c716bc1------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 06:17:00 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@eduardosoares_88255/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Rebuilding my first Android app part 2.]]></title>
            <link>https://medium.com/@eduardosoares_88255/rebuilding-my-first-android-app-part-2-05b1b0f6fed2?source=rss-27347c716bc1------2</link>
            <guid isPermaLink="false">https://medium.com/p/05b1b0f6fed2</guid>
            <category><![CDATA[clean-architecture]]></category>
            <category><![CDATA[kotlin]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[android]]></category>
            <dc:creator><![CDATA[Eduardo Soares]]></dc:creator>
            <pubDate>Wed, 29 May 2024 11:27:11 GMT</pubDate>
            <atom:updated>2024-05-29T11:27:11.452Z</atom:updated>
            <content:encoded><![CDATA[<p>New app modeling and core module implementation</p><p>In the last article I described in detail how I designed and implemented my first Android app. In this article I’ll show the new app features and the core implementation.</p><p>First of all, I passed through play store comments and got a lot of feedback on the first version, and I’ll implement them in this version.</p><p>In this new version, I changed a little how the task are grouped. In the previous version, the user must create a task list before create new tasks. Now you can create single tasks, without need to nested it in a list, but the list features will be available.</p><h3>New features</h3><p>This new version will have some new features. I describe them bellow:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/965/1*TrRMwemIDnlRWTPQqEgfxg.jpeg" /><figcaption>new app sketch</figcaption></figure><h4>Tasks</h4><p>In the previous versions, the concept of tasks were a named list contained other tasks nested on it. In this new versions, the task is considered an atomic entity, that can be included in a list or not.</p><h4>Task Lists</h4><p>This features is the same of the earlier version but now it&#39;s optional. On tasks list, the user can split a single task in another tasks.</p><h4>Check lists</h4><p>In the newer version, a task can contain a simple list of items than can be marked/unmarked as completed.</p><h4>Archive tasks</h4><p>if the user wants, he/she can archive a task to make it unshown on the screen, but without deleting the item.</p><h3>Core implementation</h3><p>After showing the app feature, let&#39;s explore the implementation. After analyzing the features, I chose clean architecture to implement the new version of the app. In clean architecture, the core features are placed in the most inner layer, and it must be platform independent. If correctly implemented, they can be used in any platform without any change.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*iQCbF8mB_5JOvawRXZVSnA.png" /><figcaption>clean architecture layers</figcaption></figure><p>The first step were creating a new Android Project, then, I added a new module called <strong>CoreApplication. </strong>In this module, I created the packages <strong>data</strong> and <strong>domain. </strong>The data layer is self-explained. It contains the entities and the classes definitions to manager the data. The domain package contain the <strong>Use Cases</strong>, here all rules will be implemented<strong>.</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/980/1*RZfsFwM29RcihDLRCX-hSw.png" /><figcaption>Overview of Core Application module</figcaption></figure><h4>Data layer</h4><p>In data layer I created the entities and repositories. The entities package contains the classes Task and TaskList. Task is a single task with all it&#39;s properties, and TaskList represents an Item with tasks nested.</p><p>Task:</p><pre>data class Task(<br>    val id:String,<br>    var name:String,<br>    var completed: Boolean,<br>    var createdDate:Date,<br>    var notificationDate: Date?,<br>    var description:String?,<br>    var archived: Boolean = false,<br>    var checkList: List&lt;TaskChecklist&gt;?<br>)<br><br><br>fun Task.hasToNotify():Boolean{<br>    return notificationDate != null<br>}</pre><p>Task List:</p><pre>data class TaskList(<br>    val id:String,<br>    var name: String,<br>    var tasks: List&lt;Task&gt;?<br>)</pre><p>In the other packaged, we have the repositories. They are interfaces with the definition of the classes that can manage task storage.</p><pre>interface TaskRepository {<br><br>    /**<br>     * Get a list of tasks matching the following arguments.<br>     * If no arguments are passed, it will returns all task,<br>     * (completed or not) that wasn&#39;t archived<br>     * @author Eduardo<br>     * @param includeCompleted: if true all tasks will be listened. If false,<br>     * only retrieved uncompleted tasks<br>     * @param includeArchived: if true, archivedTasks will be included,otherwise not<br>     * @param betweenDates: pair of dates, indicating to returns the tasks created between<br>     * the period passed<br>     */<br>    fun listTasks(<br>        includeCompleted:Boolean = true,<br>        includeArchived:Boolean = false,<br>        betweenDates:Pair&lt;Date,Date&gt;? = null): List&lt;Task&gt;<br><br>    /**<br>     * Retrieve single task<br>     * @author Eduardo<br>     * @param id: the task id<br>     * @return the task found or null<br>     */<br>    fun getTask(id:String): Task?<br><br>    /**<br>     * @author Eduardo<br>     * stores a new Task<br>     * @param task Task do create<br>     * @return true if task was successfully created<br>     */<br>    fun createNewTask(task: Task): Boolean<br><br>    /**<br>     * @author Eduardo<br>     * edit the Task passed as parameter<br>     * @param task Task do create<br>     * @return true if task was successfully edited<br>     */<br>    fun editTask(task: Task): Boolean<br><br>    /**<br>     * @author Eduardo<br>     * delete the Task passed as parameter<br>     * @param task Task do delete<br>     * @return true if task was successfully deleted<br>     */<br>    fun deleteTask(task: Task): Boolean<br>}</pre><p>These methods are pretty easy to understand. Probably the must complex is listTask because it&#39;s bunch of arguments.</p><h4>Domain layer</h4><p>In this layer, all the core feature are implemented. According clean architecture the use cases must have just one rule implementation, unlikely the previous versions that contains a single service class with a lot rules on it. The approach of clean architecture gives us the possibility of add new features, without have to know or editing the previous rules. Let&#39;s see some in detail bellow.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/748/1*3FtBVKftUqPvw-BnGlRQAA.png" /><figcaption>the domain package</figcaption></figure><p>The first class to see is the simplest, List Task Use Case. This just receive some arguments and search in repository for the tasks matching the criteria. All search parameters is marked with nullable and with default values.</p><pre>class ListTasksUseCase(private val repository: TaskRepository) {<br>    /**<br>     * List all tasks<br>     * @param completed: if has to include the completed tasks<br>     * @param archived: if include archived tasks<br>     * @param initialDate: first date of range to search items<br>     * @param finalDate: last date of range to search items<br>     * @return the list of tasks matching parameter<br>     */<br>    fun listAllTasks(<br>        completed: Boolean = true,<br>        archived: Boolean = false,<br>        initialDate: Date? = null,<br>        finalDate: Date? = null<br>    ): List&lt;Task&gt; {<br>        val dateRange =<br>            if (initialDate != null &amp;&amp; finalDate != null)<br>                Pair(initialDate, finalDate)<br>            else<br>                null<br>        return repository.listTasks(completed, archived, dateRange)<br>    }<br>}</pre><p>The CreateTaskUseCase is where a new tasks are created. Different from the following use cases, this specific don&#39;t receive a task object. Instead it receive fewer arguments, to avoid other layers and classes to deal with specific rules or insert inconsistent data, for example create a task with invalid creation date, or duplicated ids.</p><pre>class CreateTaskUseCase(<br>    private val repository: TaskRepository,<br>    private val notificationService: NotificationService) {<br><br>    /**<br>     * Create a new task<br>     * @param name: the task names<br>     * @param description: the task descriptions<br>     * @param notificationDate: when this tasks should be notified to user<br>     * @param checkListItems: optional list of items to complete this task<br>     * @return true if task was successfully created<br>     */<br>    fun createNewTask(<br>        name: String,<br>        description: String?,<br>        notificationDate: Date?,<br>        checkListItems: List&lt;String&gt; = emptyList()):Boolean {<br><br>        val task = Task(<br>            id = newId(),<br>            name = name,<br>            completed = false,<br>            createdDate = Date(),<br>            notificationDate = notificationDate,<br>            description = description,<br>            archived = false,<br>            checkList = checkListItems.map { TaskChecklist(newId(), it, false) }<br>        )<br>        return repository.createNewTask(task).also { successfullySaved -&gt;<br>            if(task.hasToNotify() &amp;&amp; successfullySaved) {<br>                notificationService.scheduleNotification(task)<br>            }<br>        }<br>    }<br>}</pre><p>The final step is scheduling notification to this task, if the user marked the notification option. The Edit and Delete are very similar, the just to their operations on repository and then deal with notification</p><pre>class DeleteTaskUseCase(<br>    private val repository: TaskRepository,<br>    private val notificationService: NotificationService) {<br><br>    fun deleteTask(task: Task): Boolean{<br>        return repository.deleteTask(task).also { successfullyDeleted -&gt;<br>            if(task.hasToNotify() &amp;&amp; successfullyDeleted){<br>                notificationService.cancelNotification(task)<br>            }<br>        }<br>    }<br>}<br><br>class EditTaskUseCase (<br>    private val repository: TaskRepository,<br>    private val notificationService: NotificationService) {<br><br>    fun editTask(task: Task): Boolean{<br>        return repository.editTask(task).also {<br>            if(task.hasToNotify()){<br>                notificationService.scheduleNotification(task)<br>            }else{<br>                notificationService.cancelNotification(task)<br>            }<br>        }<br>    }<br>}</pre><p>To avoid been too long, the last classes I wanna show is CompleteTaskUseCase. As shown bellow, this feature just edit the task, setting the property &quot;completed&quot; to true.</p><pre>class CompleteTaskUseCase(<br>    private val repository: TaskRepository,<br>    private val notificationService: NotificationService) {<br><br>    fun completeTask(task: Task): Boolean{<br>        val taskToComplete = repository.getTask(task.id)<br>        if(taskToComplete != null) {<br>            taskToComplete.completed = true<br>            return repository.editTask(taskToComplete).also {<br>                notificationService.cancelNotification(task)<br>            }<br>        }else{<br>            return false<br>        }<br>    }<br>}</pre><p>But why not just setting this property explicit and use &quot;EditTaskUseCase&quot; to update the task, it would works equally. This is true, but it breaks the concept of abstraction. We don&#39;t want that the presentation layer cares about the features implementation, for example.</p><p>I&#39;m finish for now to avoid become so extensive, in the next article I&#39;ll show the implementation of the Repositories. You can check out all the source code on my <a href="https://github.com/eduardossampaio/MyTasksMobileApp">github</a>.</p><p>See you soon.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=05b1b0f6fed2" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Rebuilding my first Android app]]></title>
            <link>https://medium.com/@eduardosoares_88255/rebuilding-my-first-android-app-14c6f4cac2f0?source=rss-27347c716bc1------2</link>
            <guid isPermaLink="false">https://medium.com/p/14c6f4cac2f0</guid>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[legacy-code]]></category>
            <category><![CDATA[android]]></category>
            <dc:creator><![CDATA[Eduardo Soares]]></dc:creator>
            <pubDate>Wed, 22 May 2024 13:49:53 GMT</pubDate>
            <atom:updated>2024-05-29T11:28:52.745Z</atom:updated>
            <content:encoded><![CDATA[<p>bring my first published app from 2016 to 2024</p><p>Until the year of 2015 I was working as a Java developer, but I was desiring to try new things. I always been so curious in terms of trying and building new technologies, and I decided to learn Android development, just because I had and Android phone and I wanted to build some app to integrate with my Arduino projects. In that time, the Android developer roadmap was kind of: learn Java, then learn the basics of Android SDK( Activity and it’s lifecycle, Fragments, resources, Broadcast receivers and etc), then build your apps and upload them to Google Play store (if you want). Since I currently know how to programming with Java, the learning curve was much easier.</p><p>After a lot of tutorials, videos, sample apps and so one, I was finally prepared to start my new journey, and for that I needed some portfolio to show my abilities to the world. I decided to build my first app and submit it to the store. I needed something that wasn’t too simple as a tutorial or exercise, nor so complex for a single beginner developer. After some brainstorm on my sketch book, I finally reached the first prototype, and something I realized that I’m not as creative as I thought. The chosen app was a… to-do task manager. This is very “uncreative” idea, but I decided to build this because it’s small enough to don’t take a lot of time to finish, and because there is no need for backend. But, no more talk, let’s see the app and the code.</p><h3>The app features</h3><p>The concept of the app was plenty easy. First you create your tasks, for example, “Cleaning the house” and then you split this task in another small tasks, like “Cleaning the kitchen”, “Organize the room” and how much you needed. After complete one task, you should mark it as completed, and the app shows to you how many tasks are reaming. I model the app in this way, instead of just simple list of random tasks, because this is the way I used to organize myself. Some other features was add date and time to some task, notify the user in some task in specific time, and backup your items to local storage.</p><p>The entire app were designed following the material design recommendations like toolbar, navigations menu, floating button and floating action button. This design was very beautiful in the past, but today it’s too simple and your app will look to basic. Bellow you can check some screenshots.</p><figure><img alt="The picture contains 3 screens. On first, the app is creating a task named “Medium Article”. On second the app is creating a subtask called “First article” with description “show the current project status”. The 3rd show a list of subtasks" src="https://cdn-images-1.medium.com/max/1024/1*1FFiDfric6AquGEX75-IyA.png" /><figcaption>the basic task creation workflow</figcaption></figure><p>In addition, you have the option to add a reminder to your subtasks, and been notified some time before. On the settings screen, you can configure the option to manually backup your tasks and configure the order that task are showed.</p><figure><img alt="3 Screens. The 1st show the screen. The second is the configuration of how much time the user want to be notified before the task time. the 3rd is how user wants the task list been displayed" src="https://cdn-images-1.medium.com/max/1024/1*bLmstzvD0b_YIOrdBWFTsg.png" /><figcaption>Configuration settings</figcaption></figure><h3>Building the app</h3><p>Since this app is to outdated, it’s no longer available on Google play store, because it’s not following the latests store requirements. The only option is getting this from the github.</p><p>After cloning from repository and trying to open in Android Studio, I got a several errors on Logcat. The whole projects was so outdated that I had to remake almost all configurations. The most important changes was update the gradle version from 2.10 to 8.6, the compile sdk version from 22 to 34 and the minimum sdk version from 16 to 25, and finally the java version from 7 to 17.</p><p>Some other adjustments are required, as adding <strong>android:exported=”true”</strong> tag in each activity and broadcast receiver on manifest file.</p><pre>&lt;activity<br>  android:exported=&quot;true&quot;<br>  android:name=&quot;.view.activity.ListTasksActivity&quot;<br>  android:theme=&quot;@style/AppTheme&quot;&gt;<br>  &lt;intent-filter&gt;<br>      &lt;action android:name=&quot;android.intent.action.MAIN&quot; /&gt;<br>      &lt;category android:name=&quot;android.intent.category.LAUNCHER&quot; /&gt;<br>  &lt;/intent-filter&gt;<br>&lt;/activity&gt;<br><br>...<br><br>&lt;receiver android:exported=&quot;true&quot; android:name=&quot;.legacy.receives.StartupReceive&quot;&gt;<br>    &lt;intent-filter&gt;<br>        &lt;action android:name=&quot;android.intent.action.BOOT_COMPLETED&quot; /&gt;<br><br>        &lt;category android:name=&quot;android.intent.category.DEFAULT&quot; /&gt;<br>    &lt;/intent-filter&gt;<br>&lt;/receiver&gt;</pre><p>And add <strong>PendingIntent.FLAG_IMMUTABLE </strong>to all <strong>PendingIntents</strong></p><pre>private boolean alarmUp(){<br>  return(PendingIntent.getBroadcast(context, 0,<br>          notificationIntent,<br>         PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE) != null);<br>}</pre><p>As expected, all dependencies are deprecated.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1012/1*qvKKfUvTFxB4y5CNFtqNqA.png" /><figcaption>project dependencies</figcaption></figure><p>After 3 hours of adjustments, the app finally builds. The app is not working entirely, but the core features are woking well and I could navigate in it’s implementation.</p><h3>The app overview</h3><p>The app were built in the MVC architecture, witch was very common in 2015 but today we have a lot of better options. The main project structure was divided into the layers <strong>core</strong>, <strong>entities</strong>, <strong>persistence</strong> and <strong>views.</strong> Some other packages is wrongly placed in same hierarch.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/964/1*OVBcSkbEyTLhSkwW5RLi1w.png" /><figcaption>The app in inside “legacy” package, because I attempted to update this in the past.</figcaption></figure><h3>Core layer</h3><p>The core app contains the <strong>packages</strong>, <strong>backup</strong>, <strong>entities</strong>, <strong>utils</strong> and the feature classes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/966/1*SqDA-wVHsQPPgleCWe-10Q.png" /></figure><p>The <strong>backups</strong> package contain just some Gson annotations, and it’s name was badly chosen. The <strong>entities</strong> and <strong>utils</strong> packages are self explained. The main classes are that in the root package. Lets see in details.</p><p>The first is the Backup class. This class contains methods to backup and restore Tasks. The implementation was basically, serialize all data in json format and save to the storage. After looking at the class I found the first big mistake: store reference to Context. It’s highly recommended that you don’t to this, because you can have several memory leaks.</p><pre>public class Backup {<br>    private Context context;<br>    public Backup(Context context){<br>        this.context =context;<br>    }<br>//...</pre><p>The Constants class just contains constants and the File class just methods to read and write files. The <strong>Settings</strong> class is simple, this just read/write some user preferences in <strong>SharedPreferences</strong> class, but I committed another newbie mistake, use hard coded strings.</p><pre><br>    private Context context;<br>    public static Settings getInstance(Context context){<br>        return  new Settings(context);<br>    }<br><br>    public Settings(Context context){<br>        this.context = context;<br>    }<br>    public boolean capitalizeFirst(){<br>        return getBoolPref(&quot;preference_capitalize_first&quot;,false);<br>    }<br><br>    public boolean vibrate(){<br>        return getBoolPref(&quot;preference_vibrate&quot;,true);<br>    }<br>    public boolean notifyAllTasks(){<br>        return getBoolPref(&quot;preference_notify_all&quot;,true);<br>    }<br>    public boolean manualBackup(){<br>        return getBoolPref(&quot;preference_enable_manual_backup&quot;,false);<br>    }</pre><p>And then, the real app core, the <strong>Tasks</strong> class. This class contains all the main features of the application. And the main class contains the worse mistake: directly instantiates it’s dependencies. This is terrible because, the main features aren’t testable. Not only that, it’s also highly coupled with the storage layer.</p><pre>package com.apps.esampaio.legacy;<br><br>import android.content.Context;<br><br>import com.apps.esampaio.legacy.entities.Subtask;<br>import com.apps.esampaio.legacy.entities.Task;<br>import com.apps.esampaio.legacy.persistence.DAO.Impl.SubtaskDAOImpl;<br>import com.apps.esampaio.legacy.persistence.DAO.Impl.TaskDAOImpl;<br>import com.apps.esampaio.legacy.persistence.DAO.SubtaskDAO;<br>import com.apps.esampaio.legacy.persistence.DAO.TaskDAO;<br><br>import java.util.List;<br><br>/**<br> * Created by eduardo on 28/06/2016.<br> */<br><br>public class Tasks {<br>    private static TaskDAO taskDAO = null;<br>    private static SubtaskDAO subtaskDAO = null;<br><br>    public Tasks(Context context){<br>        if(taskDAO == null)<br>            taskDAO= new TaskDAOImpl(context);<br>        if(subtaskDAO == null)<br>            subtaskDAO = new SubtaskDAOImpl(context);<br><br>    }<br><br>    public List&lt;Task&gt; getTasks(){<br>        List&lt;Task&gt; tasks = taskDAO.getTasks();<br>        for (Task task: tasks) {<br>            task.setSubtasks(subtaskDAO.getSubTasks(task.getId()));<br>        }<br>        return tasks;<br>    }<br><br>    public void addTask(Task task){<br>        taskDAO.addTask(task);<br>        for (Subtask subtask: task.getSubtasks()) {<br>            subtaskDAO.addSubtask(subtask);<br>        }<br>    }<br><br><br>    public void saveOrUpdateTask(Task item) {<br>        if(item.getId() == -1){<br>            addTask(item);<br>        }else{<br>            updateTask(item);<br>        }<br>    }<br>    public void updateTask(Task item) {<br>        taskDAO.updateTask(item);<br>        for (Subtask subtask: item.getSubtasks()) {<br>            subtaskDAO.addOrUpdate(subtask);<br>        }<br>    }<br><br>    public void delete(Task item) {<br>        taskDAO.deleteTask(item);<br>        for (Subtask subtask: item.getSubtasks()) {<br>            deleteSubtask(subtask);<br>        }<br>    }<br><br>    public void deleteSubtask(Subtask subtask){<br>        subtaskDAO.deleteSubtask(subtask);<br>    }<br><br>    public Task getTask(int id) {<br>        Task task = taskDAO.getTask(id);<br>        task.setSubtasks(subtaskDAO.getSubTasks(task.getId()));<br>        return task;<br>    }<br>}</pre><h3>Persistence layer</h3><p>There isn’t much to talk about the persistence layer. It was modeled and built thinking about the Sqlite, so again, it’s very couple to this api.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/860/1*WBllJ7hUisf1vo2D_AZtkw.png" /><figcaption>persistance layer</figcaption></figure><p>Today, we have a lot of better solutions for storage, and even better apis to manipulate the Android’s Sqlite. Probably, if I had researched a bit more, I could found better options, and avoided some painful tasks, like write SQL instructions on my code.</p><pre>public class SubtaskEntity implements Entity {<br><br>    private static final String createTableSql =<br>            &quot; create table subtask (&quot; +<br>                    &quot; id integer not null primary key autoincrement,&quot; +<br>                    &quot; task_id integer not null ,&quot; +<br>                    &quot; name varchar(100) not null,&quot; +<br>                    &quot; task_date date,&quot; +<br>                    &quot; task_time date,&quot; +<br>                    &quot; description varchar(1000),&quot; +<br>                    &quot; completed int, &quot; +<br>                    &quot; FOREIGN KEY(task_id) REFERENCES task(id)&quot; +<br>                    &quot;);&quot;;<br>//...</pre><h3>The view layer</h3><p>Finally the view layer, contains all Android related stuffs, like Activities, Fragments, Dialogs, Notifications, Broadcast receivers, adapters and so more. There is no need to go deeply in this package, because it contains so many classes and this is not the goal of this article.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/894/1*qqQfUME3MxGyXtaD9AQCog.png" /><figcaption>The “view” layer</figcaption></figure><p>You can download the legacy version on my <a href="https://github.com/eduardossampaio/tarefas">Github</a> (this is now buildable).</p><h3>The newer version</h3><p>Once this project is so legacy, it will be a madness try to refactor this. Instead, I will create a new project from scratch, with the same package id, using modern technologies and techniques and replace the old version on Play Store.</p><p>In first moments, this will be the main changes (but can changes during the development):</p><ul><li>From <strong>MVC</strong> to <strong>MVVM</strong> or <strong>Clean Architecture</strong></li><li>From <strong>Java</strong> to <strong>Kotlin</strong></li><li>From <strong>Multi Activity</strong> app to <strong>Single Activity</strong> App</li><li>From <strong>XML</strong> View to <strong>Jetpack Compose</strong></li><li>From <strong>Sqlite DAO</strong> to <strong>persistence libray</strong></li><li>From <strong>No tests</strong> to at least <strong>Unit Test</strong></li><li>From <strong>Material Desgin 1 </strong>to <strong>Material Design 3 or Custom Layout</strong></li><li>From <strong>Single Theme</strong> to <strong>Light/Dark Theme</strong></li></ul><p>In the next article, I’ll show the skeleton of the new version, with the new architecture, the key features and the reason why I chosen it. Se you soon.</p><p>checkout the part 2: <a href="https://medium.com/@eduardosoares_88255/rebuilding-my-first-android-app-part-2-05b1b0f6fed2">https://medium.com/@eduardosoares_88255/rebuilding-my-first-android-app-part-2-05b1b0f6fed2</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=14c6f4cac2f0" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Hello World]]></title>
            <link>https://medium.com/@eduardosoares_88255/hello-world-8a937feac5fd?source=rss-27347c716bc1------2</link>
            <guid isPermaLink="false">https://medium.com/p/8a937feac5fd</guid>
            <dc:creator><![CDATA[Eduardo Soares]]></dc:creator>
            <pubDate>Tue, 28 Jan 2020 11:47:20 GMT</pubDate>
            <atom:updated>2020-01-28T11:47:20.337Z</atom:updated>
            <content:encoded><![CDATA[<p>Olá Mundo!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8a937feac5fd" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>