Android: Memo Application

This article provides a step by step guidance to develop a simple Memo application. You need to have basic knowledge on Android database and ListView to understand and complete this project. If you are not familiar with them, please visit to the following tutorials:

Step 1:
Create a new Android project “Memo”  with a package name “com.javahelps.memo

Step 2:
Right click on the Java package and create a new class 'Memo'. This class will be used as the model to represent the memos later in this project.
package com.javahelps.memo;

import java.io.Serializable;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Memo implements Serializable {
    private Date date;
    private String text;
    private boolean fullDisplayed;
    private static DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyy 'at' hh:mm aaa");

    public Memo() {
        this.date = new Date();
    }

    public Memo(long time, String text) {
        this.date = new Date(time);
        this.text = text;
    }

    public String getDate() {
        return dateFormat.format(date);
    }

    public long getTime() {
        return date.getTime();
    }

    public void setTime(long time) {
        this.date = new Date(time);
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getText() {
        return this.text;
    }

    public String getShortText() {
        String temp = text.replaceAll("\n", " ");
        if (temp.length() > 25) {
            return temp.substring(0, 25) + "...";
        } else {
            return temp;
        }
    }

    public void setFullDisplayed(boolean fullDisplayed) {
        this.fullDisplayed = fullDisplayed;
    }

    public boolean isFullDisplayed() {
        return this.fullDisplayed;
    }
    @Override
    public String toString() {
        return this.text;
    }
}
The DateFormat is used to format the date when displaying the time of creation of the memo in the application. The fullDisplayed flag is used to define whether the complete memo is displayed to the user or part of the memo only displayed to the user. This property will be used to shrink and expand the memo in the application.

Step 3:
Copy and paste the provided images into the resources folder. These images will be used as the icons for buttons. You can choose any other icons as well, but make sure that they have the same dimension as the provided images.
Download link


Step 4:
Right click on the drawable folder and create a new “Drawable resource file”. Name the file as “memo_background”.
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#fffffacb"/>
    <stroke android:width="1dip" android:color="#ffbe9747" />
    <corners android:radius="10dip"/>
</shape>
This drawable resource is used as the background of individual memos.

Step 5:
Create another “Drawable resource file” and name it as “add_button_background”.
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <shape android:shape="rectangle">
            <corners android:radius="3dip" />
            <stroke android:width="1dip" android:color="#83776b" />
            <gradient android:angle="-90" android:endColor="#cbb59d" android:startColor="#5f4427" />
        </shape>
    </item>
    <item android:state_focused="true">
        <shape android:shape="rectangle">
            <corners android:radius="3dip" />
            <stroke android:width="1dip" android:color="#83776b" />
            <solid android:color="#92806c" />
        </shape>
    </item>
    <item>
        <shape android:shape="rectangle">
            <corners android:radius="3dip" />
            <stroke android:width="1dip" android:color="#83776b" />
            <gradient android:angle="-90" android:endColor="#92806c" android:startColor="#cbb59d" />
        </shape>
    </item>
</selector>
This drawable resource is used as the background of "Add memo" button.

Step 6:
Modify the "activity_main.xml" as given below.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/img_background"
    tools:context=".MainActivity">


    <RelativeLayout
        android:id="@+id/layoutBottom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:padding="5dp">


        <Button
            android:id="@+id/btnAdd"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="Add"
            android:background="@drawable/add_button_background" />

        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:layout_alignParentTop="true"
            android:background="#999" />
    </RelativeLayout>

    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@id/layoutBottom"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:layout_margin="5dp"
        android:divider="@android:color/transparent"
        android:dividerHeight="10dp"
        android:listSelector="@android:color/transparent" />
</RelativeLayout>


Step 7:
Right click on layout folder and select New → XML → Layout XML File. Name the new layout file as “layout_list_item”.


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="10dp"
    android:orientation="vertical"
    android:background="@drawable/memo_background">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <ImageView
            android:id="@+id/btnEdit"
            android:layout_width="16dp"
            android:layout_height="16dp"
            android:layout_alignParentLeft="true"
            android:src="@drawable/edit" />

        <ImageView
            android:id="@+id/btnDelete"
            android:layout_width="16dp"
            android:layout_height="16dp"
            android:layout_alignParentRight="true"
            android:src="@drawable/delete" />

        <TextView
            android:id="@+id/txtDate"
            android:layout_width="match_parent"
            android:layout_height="24dp"
            android:layout_toLeftOf="@id/btnDelete"
            android:textSize="15sp"
            android:layout_toRightOf="@id/btnEdit"
            android:gravity="top|center_horizontal"
            android:text="date"
            android:textAppearance="?android:attr/textAppearanceMedium" />
    </RelativeLayout>

    <TextView
        android:layout_marginTop="10dp"
        android:id="@+id/txtMemo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Medium Text"
        android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>
This layout is used for the customized ListView. For more details about custom ListView, visit to this link.

Step 8:
Right click on the project and create a new Blank Activity named "EditActivity".


Step 9:
Modify the activity_edit.xml as given below.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.javahelps.memo.EditActivity">

    <LinearLayout
        android:id="@+id/linearLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btnSave"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"
            android:layout_weight="1"
            android:text="Save" />

        <Button
            android:id="@+id/btnCancel"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"
            android:layout_weight="1"
            android:text="Cancel" />
    </LinearLayout>

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@id/linearLayout"
        android:layout_alignParentTop="true"
        android:fillViewport="true">

        <EditText
            android:id="@+id/etText"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="top|left" />
    </ScrollView>
</RelativeLayout>


Step 10:
That's all for the user-interfaces, now create a new package “com.javahelps.memo.db” and create “DatabaseOpenHelper” and “DatabaseAccess” classes inside it.

DatabaseOpenHelper:
package com.javahelps.memo.db;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

class DatabaseOpenHelper extends SQLiteOpenHelper {
    public static final String DATABASE = "memos.db";
    public static final String TABLE = "memo";
    public static final int VERSION = 1;

    public DatabaseOpenHelper(Context context) {
        super(context, DATABASE, null, VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE memo(date INTEGER PRIMARY KEY, memo TEXT);");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

DatabaseAccess:
package com.javahelps.memo.db;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.javahelps.memo.Memo;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class DatabaseAccess {
    private SQLiteDatabase database;
    private DatabaseOpenHelper openHelper;
    private static volatile DatabaseAccess instance;

    private DatabaseAccess(Context context) {
        this.openHelper = new DatabaseOpenHelper(context);
    }

    public static synchronized DatabaseAccess getInstance(Context context) {
        if (instance == null) {
            instance = new DatabaseAccess(context);
        }
        return instance;
    }

    public void open() {
        this.database = openHelper.getWritableDatabase();
    }

    public void close() {
        if (database != null) {
            this.database.close();
        }
    }

    public void save(Memo memo) {
        ContentValues values = new ContentValues();
        values.put("date", memo.getTime());
        values.put("memo", memo.getText());
        database.insert(DatabaseOpenHelper.TABLE, null, values);
    }

    public void update(Memo memo) {
        ContentValues values = new ContentValues();
        values.put("date", new Date().getTime());
        values.put("memo", memo.getText());
        String date = Long.toString(memo.getTime());
        database.update(DatabaseOpenHelper.TABLE, values, "date = ?", new String[]{date});
    }

    public void delete(Memo memo) {
        String date = Long.toString(memo.getTime());
        database.delete(DatabaseOpenHelper.TABLE, "date = ?", new String[]{date});
    }

    public List getAllMemos() {
        List memos = new ArrayList<>();
        Cursor cursor = database.rawQuery("SELECT * From memo ORDER BY date DESC", null);
        cursor.moveToFirst();
        while (!cursor.isAfterLast()) {
            long time = cursor.getLong(0);
            String text = cursor.getString(1);
            memos.add(new Memo(time, text));
            cursor.moveToNext();
        }
        cursor.close();
        return memos;
    }
}
These classes are used to access the SQLite database. For more details about database in Android, visit to this tutorial.

Step 11:
Modify the EditActivity.java as shown below.
package com.javahelps.memo;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import com.javahelps.memo.db.DatabaseAccess;

public class EditActivity extends ActionBarActivity {
    private EditText etText;
    private Button btnSave;
    private Button btnCancel;
    private Memo memo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_edit);

        this.etText = (EditText) findViewById(R.id.etText);
        this.btnSave = (Button) findViewById(R.id.btnSave);
        this.btnCancel = (Button) findViewById(R.id.btnCancel);

        Bundle bundle = getIntent().getExtras();
        if(bundle != null) {
            memo = (Memo) bundle.get("MEMO");
            if(memo != null) {
                this.etText.setText(memo.getText());
            }
        }

        this.btnSave.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onSaveClicked();
            }
        });

        this.btnCancel.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onCancelClicked();
            }
        });
    }

    public void onSaveClicked() {
        DatabaseAccess databaseAccess = DatabaseAccess.getInstance(this);
        databaseAccess.open();
        if(memo == null) {
            // Add new memo
            Memo temp = new Memo();
            temp.setText(etText.getText().toString());
            databaseAccess.save(temp);
        } else {
            // Update the memo
            memo.setText(etText.getText().toString());
            databaseAccess.update(memo);
        }
        databaseAccess.close();
        this.finish();
    }

    public void onCancelClicked() {
        this.finish();
    }
}

Step 12:
Modify the MainActivity.java as shown below.
package com.javahelps.memo;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import com.javahelps.memo.db.DatabaseAccess;

import java.util.List;


public class MainActivity extends ActionBarActivity {
    private ListView listView;
    private Button btnAdd;
    private DatabaseAccess databaseAccess;
    private List<Memo> memos;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        this.databaseAccess = DatabaseAccess.getInstance(this);

        this.listView = (ListView) findViewById(R.id.listView);
        this.btnAdd = (Button) findViewById(R.id.btnAdd);

        this.btnAdd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onAddClicked();
            }
        });

        this.listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Memo memo = memos.get(position);
                TextView txtMemo = (TextView) view.findViewById(R.id.txtMemo);
                if (memo.isFullDisplayed()) {
                    txtMemo.setText(memo.getShortText());
                    memo.setFullDisplayed(false);
                } else {
                    txtMemo.setText(memo.getText());
                    memo.setFullDisplayed(true);
                }
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        databaseAccess.open();
        this.memos = databaseAccess.getAllMemos();
        databaseAccess.close();
        MemoAdapter adapter = new MemoAdapter(this, memos);
        this.listView.setAdapter(adapter);
    }

    public void onAddClicked() {
        Intent intent = new Intent(this, EditActivity.class);
        startActivity(intent);
    }

    public void onDeleteClicked(Memo memo) {
        databaseAccess.open();
        databaseAccess.delete(memo);
        databaseAccess.close();

        ArrayAdapter<Memo> adapter = (ArrayAdapter<Memo>) listView.getAdapter();
        adapter.remove(memo);
        adapter.notifyDataSetChanged();
    }

    public void onEditClicked(Memo memo) {
        Intent intent = new Intent(this, EditActivity.class);
        intent.putExtra("MEMO", memo);
        startActivity(intent);
    }

    private class MemoAdapter extends ArrayAdapter<Memo> {


        public MemoAdapter(Context context, List<Memo> objects) {
            super(context, 0, objects);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if (convertView == null) {
                convertView = getLayoutInflater().inflate(R.layout.layout_list_item, parent, false);
            }

            ImageView btnEdit = (ImageView) convertView.findViewById(R.id.btnEdit);
            ImageView btnDelete = (ImageView) convertView.findViewById(R.id.btnDelete);
            TextView txtDate = (TextView) convertView.findViewById(R.id.txtDate);
            TextView txtMemo = (TextView) convertView.findViewById(R.id.txtMemo);

            final Memo memo = memos.get(position);
            memo.setFullDisplayed(false);
            txtDate.setText(memo.getDate());
            txtMemo.setText(memo.getShortText());
            btnEdit.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    onEditClicked(memo);
                }
            });
            btnDelete.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    onDeleteClicked(memo);
                }
            });
            return convertView;
        }
    }
}

Step 13:
Save all the changes and run the project.


Note:
Purpose of this tutorial and the project is not developing a perfect commercial application, but providing a basic idea to develop a simple application in Android inorder to apply your knowledge in database and ListView. The application has not been tested completely, so if there are any bugs, please comment below and I will try my best to fix them as soon as possible.

Find the project at Git Hub.
Previous
Next Post »

10 comments

Write comments
yan
AUTHOR
August 31, 2016 at 7:35 PM delete

great tutorial. may i ask if what theme of android studio are you using.

Reply
avatar
Gobinath
AUTHOR
September 1, 2016 at 6:27 AM delete

Thanks.
I think you are asking about the Color Scheme. I cannot remember exactly but I think it is the default color scheme customized by removing bold fonts.

Reply
avatar
James Cha
AUTHOR
September 15, 2016 at 8:53 AM delete

Hello, I got some errors below :
Error:(48, 69) error: cannot find symbol variable txtMemo
Error:(104, 74) error: cannot find symbol variable btnEdit
Error:(105, 76) error: cannot find symbol variable btnDelete
Error:(106, 72) error: cannot find symbol variable txtDate
Error:(107, 72) error: cannot find symbol variable txtMemo
Note: Some input files use or override a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Note: Some input files use unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
:app:compileDebugJavaWithJavac FAILED
Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
> Compilation failed; see the compiler error output for details.

how to solve them???
I did copy & paste as you showed above steps.

Reply
avatar
Ron Zheng
AUTHOR
November 10, 2016 at 12:44 PM delete

Hi, whenever I click save, only the delete button shows up, nothing else on the main activity.

Reply
avatar
Khristian
AUTHOR
November 11, 2016 at 7:00 PM delete

Nice tutorial helped me alot. But sir when i use the edit button it goes to the edit activity but doesn't update the memo it only creates new one
Please help as soon as possible

Reply
avatar
Gobinath
AUTHOR
November 16, 2016 at 5:30 PM delete

Hi,
I couldn't reproduce this in my system. If there are any error messages, could you please share the logcat error message.

Reply
avatar
Gobinath
AUTHOR
November 16, 2016 at 5:32 PM delete

Hi,
I couldn't reproduce this in my system. Please make sure that you call the update method when editing the memo. Check the onSaveClicked method:

public void onSaveClicked() {
DatabaseAccess databaseAccess = DatabaseAccess.getInstance(this);
databaseAccess.open();
if(memo == null) {
// Add new memo
Memo temp = new Memo();
temp.setText(etText.getText().toString());
databaseAccess.save(temp);
} else {
// Update the memo
memo.setText(etText.getText().toString());
databaseAccess.update(memo);
}
databaseAccess.close();
this.finish();
}

Reply
avatar
► Abdullah Hafizh
AUTHOR
May 16, 2017 at 4:55 PM delete

How to works with cloud database?

Reply
avatar
► Abdullah Hafizh
AUTHOR
May 24, 2017 at 8:09 PM delete

I have same too

Error:(34, 53) error: cannot find symbol variable listView
Note: Some input files use or override a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Note: Some input files use unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
:app:compileDebugJavaWithJavac FAILED
Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
> Compilation failed; see the compiler error output for details.

Reply
avatar
Raoul
AUTHOR
July 7, 2017 at 11:15 PM delete

Is there version of app with MySQL db system?

Reply
avatar

Contact Form

Name

Email *

Message *