Android记事本项目开发

写了一个Android记事本小程序,现在记录一下。

考虑到是记事本小程序,记录的内容只有文字,而且内容不会太长,所以选择使用SQLite数据库,数据存放在用户的手机上。
牵涉到数据库,那自然是一个实体。先设计实体数据表:DBHelper.java

package com.ikok.notepad.DBUtil; 

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

/**
 * Created by Anonymous on 2016/3/24.
 */
public class DBHelper extends SQLiteOpenHelper { 

  /**
   * 创建笔记表
   */
  private static final String CREATE_NOTE = "create table Note(" +
      "id integer primary key autoincrement," +
      "content text," +
      "time text)"; 

  private Context mContext; 

  public DBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
    super(context, name, factory, version);
    mContext = context;
  } 

  @Override
  public void onCreate(SQLiteDatabase sqLiteDatabase) {
    sqLiteDatabase.execSQL(CREATE_NOTE);
//    Toast.makeText(mContext,"Created",Toast.LENGTH_SHORT).show();
  } 

  @Override
  public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) { 

  }
}

创建完数据表后,自然需要操作数据库,CRUD数据,我把所有跟数据库有关的操作封装在一起:NoteDB.java

package com.ikok.notepad.DBUtil; 

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

import com.ikok.notepad.Entity.Note; 

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

/**
 * Created by Anonymous on 2016/3/24.
 */
public class NoteDB { 

  public static final String DB_NAME = "notepad";
  public static final int VERSION = 1;
  private static NoteDB mNoteDB;
  private SQLiteDatabase db; 

  public NoteDB(Context context) {
    DBHelper dbHelper = new DBHelper(context,DB_NAME,null,VERSION);
    db = dbHelper.getWritableDatabase();
  }
  /**
   * 获取 NoteDB 的实例
   * @param context
   * @return
   */
  public synchronized static NoteDB getInstance(Context context){
    if (mNoteDB == null){
      mNoteDB = new NoteDB(context);
    }
    return mNoteDB;
  } 

  public void saveNote(Note note){
    if (note != null) {
      ContentValues values = new ContentValues();
      values.put("content", note.getContent());
      values.put("time", note.getTime());
      db.insert("Note", null, values);
    }
  } 

  public List<Note> loadNotes(){
    List<Note> noteList = new ArrayList<Note>();
    /**
     * 先按时间降序排列,再按id降序排列
     */
    Cursor cursor = db.query("Note",null,null,null,null,null,"time desc,id desc");
    if (cursor.moveToNext()){
      do {
        Note note = new Note();
        note.setId(cursor.getInt(cursor.getColumnIndex("id")));
        note.setContent(cursor.getString(cursor.getColumnIndex("content")));
        note.setTime(cursor.getString(cursor.getColumnIndex("time")));
        noteList.add(note);
      } while (cursor.moveToNext());
    }
    return noteList;
  } 

  public Note loadById(int id){
    Note note = null;
    Cursor cursor = db.query("Note",null,"id = " + id,null,null,null,null);
    if (cursor.moveToNext()){
      note = new Note();
      note.setContent(cursor.getString(cursor.getColumnIndex("content")));
      note.setTime(cursor.getString(cursor.getColumnIndex("time")));
    }
    return note;
  } 

  public void deleteById(Integer id){
    db.delete("Note","id = " + id,null);
  } 

  public void deleteAllNote(){
    db.delete("Note", null, null);
  } 

  public void updateById(String noteTime, String noteContent, int noteId){
    ContentValues values = new ContentValues();
    values.put("content",noteContent);
    values.put("time",noteTime);
    db.update("Note",values,"id = " + noteId,null);
  } 

}

设计完数据库后,与数据库对应的需要一个实体类:Note.java

package com.ikok.notepad.Entity; 

import java.io.Serializable; 

/**
 * Created by Anonymous on 2016/3/24.
 */
public class Note implements Serializable {
  private int id;
  private String content;
  private String time; 

  public int getId() {
    return id;
  } 

  public void setId(int id) {
    this.id = id;
  } 

  public String getContent() {
    return content;
  } 

  public void setContent(String content) {
    this.content = content;
  } 

  public String getTime() {
    return time;
  } 

  public void setTime(String time) {
    this.time = time;
  }
}

接下来进行App主页的设计:main_activity.xml

<?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="match_parent"
  android:background="@drawable/repeat_bg"
  android:orientation="vertical"> 

  <TextView
    android:id="@+id/app_title"
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:textSize="16sp"
    android:gravity="center"
    android:text="@string/app_title"
    android:textColor="#333"
    /> 

  <ListView
    android:id="@+id/listview"
    android:descendantFocusability="blocksDescendants"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1"> 

  </ListView> 

  <RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="40dp"
    > 

    <ImageButton
      android:id="@+id/about_btn"
      android:src="@drawable/about_me"
      android:layout_alignParentLeft="true"
      android:paddingLeft="20dp"
      android:background="#00ffffff"
      android:scaleType="center"
      android:layout_marginTop="4dp"
      android:layout_width="52dp"
      android:layout_height="32dp" /> 

    <TextView
      android:id="@+id/note_num"
      android:layout_width="wrap_content"
      android:layout_height="30dp"
      android:paddingTop="2dp"
      android:textSize="18sp"
      android:textColor="#333"
      android:layout_centerInParent="true"
      android:text="@string/app_title"
      /> 

    <ImageButton
      android:id="@+id/write_btn"
      android:src="@drawable/write_btn"
      android:layout_alignParentRight="true"
      android:paddingRight="20dp"
      android:background="#00ffffff"
      android:scaleType="center"
      android:layout_marginTop="4dp"
      android:layout_width="52dp"
      android:layout_height="32dp" /> 

  </RelativeLayout> 

</LinearLayout>

具体效果如下(图标懒得去改颜色了):

左边的是一个关于App的按钮,右边的新建记事本的按钮。

因为主页需要显示已经记录的内容,所以我选择用ListView去显示。用到ListView,则与之对应的是要一个数据源,一个适配器。所以我为每一条子项设计了一个样式,去让它左边显示创建或更新的时间,右边显示内容。如下:list_item.xml

<?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="match_parent"
  android:minHeight="50dp"
  android:orientation="horizontal"> 

  <TextView
    android:id="@+id/show_time"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:gravity="center"
    android:paddingLeft="10dp"
    android:textColor="#333"
    android:textSize="16sp" /> 

  <TextView
    android:id="@+id/show_content"
    android:layout_width="0dp"
    android:layout_weight="1"
    android:layout_height="match_parent"
    android:textSize="16sp"
    android:paddingLeft="20dp"
    android:textColor="#333"
    android:paddingTop="14dp"
    android:singleLine="true" /> 

</LinearLayout>

创建好了ListView,接下来为它准备适配器:MyAdapter.java

package com.ikok.notepad.Util; 

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView; 

import com.ikok.notepad.Entity.Note;
import com.ikok.notepad.R; 

import java.util.List; 

/**
 * Created by Anonymous on 2016/3/24.
 */
public class MyAdapter extends BaseAdapter { 

  private List<Note> noteList;
  private LayoutInflater mInflater;
  private Context mContext;
  private int index; 

  public MyAdapter(Context context,List<Note> noteList,ListView listView) {
    this.mInflater = LayoutInflater.from(context);
    this.noteList = noteList;
    this.mContext = context;
  } 

  @Override
  public int getCount() {
    return noteList.size();
  } 

  @Override
  public Object getItem(int i) {
    return noteList.get(i);
  } 

  @Override
  public long getItemId(int i) {
    return i;
  } 

  @Override
  public View getView(int i, View convertView, ViewGroup viewGroup) {
    ViewHolder viewHolder = null;
    if (convertView == null){
      viewHolder = new ViewHolder();
      convertView = mInflater.inflate(R.layout.list_item, null);
      viewHolder.mTime = (TextView) convertView.findViewById(R.id.show_time);
      viewHolder.mContent = (TextView) convertView.findViewById(R.id.show_content);
      convertView.setTag(viewHolder);
    } else {
      viewHolder = (ViewHolder) convertView.getTag();
    }
    viewHolder.mTime.setText(noteList.get(i).getTime());
    viewHolder.mContent.setText(noteList.get(i).getContent()); 

    index = i; 

//    convertView.setOnClickListener(new View.OnClickListener() {
//      @Override
//      public void onClick(View view) {
//        Intent intent = new Intent(mContext,UpdateOrReadActivity.class);
////        Bundle bundle = new Bundle();
////        bundle.putSerializable("note_item",noteList.get(index));
////        intent.putExtras(bundle);
//        intent.putExtra("note_id",noteList.get(index).getId());
//        Log.d("Anonymous","备忘录ID:"+noteList.get(index).getId());
//        mContext.startActivity(intent);
//        Log.d("Anonymous","执行了适配器里的点击事件");
//      }
//    }); 

    return convertView; 

  } 

  class ViewHolder{
    public TextView mTime;
    public TextView mContent;
  }
}

这里采用了使用ViewHolder,来使ListView滚动的时候不必每次重新创建对象,提升性能。

创建好了ListView,准备好了适配器,接下来要为ListView准备数据源,而这数据源是要从数据库读出来的。但是数据库操作和网络访问等都是属于耗时操作,如果用主UI线程去执行响应操作的话,很可能会出现ANR现象,所以这里我用AsyncTask去执行数据库操作。主Activity代码如下:MainActivity.java

package com.ikok.notepad.Activity; 

import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TextView; 

import com.ikok.notepad.DBUtil.NoteDB;
import com.ikok.notepad.Entity.Note;
import com.ikok.notepad.R;
import com.ikok.notepad.Util.DeleteAsyncTask;
import com.ikok.notepad.Util.MyAdapter; 

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

/**
 * Created by Anonymous on 2016/3/24.
 */
public class MainActivity extends Activity {
  /**
   * 布局控件
   */
  private TextView mTitle;
  private TextView mNoteNum;
  private ImageButton mWrite;
  private ListView mNoteListView;
  private ImageButton mAbout;
  /**
   * 数据库实例,数据源
   */
  private List<Note> mNoteList = new ArrayList<Note>() ;
  private NoteDB mNoteDB; 

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.main_activity); 

    initView();
    new NewAsyncTask().execute();
    initEvent(); 

  } 

  private void initEvent() {
    /**
     * 新写一条备忘录
     */
    mWrite.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
        Intent intent = new Intent(MainActivity.this, AddNoteActivity.class);
        startActivity(intent);
      }
    });
    /**
     * 修改或查看一条已有的备忘录
     */
    mNoteListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
      @Override
      public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
        Note note = (Note) adapterView.getItemAtPosition(i);
//        Log.d("Anonymous", "点击ListView获取的note id: " + note.getId());
        Intent intent = new Intent(MainActivity.this, UpdateOrReadActivity.class);
        intent.putExtra("note_id", note.getId());
        startActivity(intent);
      }
    });
    /**
     * listview长按删除
     */
    mNoteListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
      @Override
      public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
        final Note note = (Note) parent.getItemAtPosition(position);
//        Log.d("Anonymous", "长按ListView获取的note id: " + note.getId());
        /**
         * 长按提示是否删除
         */
        new AlertDialog.Builder(MainActivity.this)
            .setTitle("提示")
            .setMessage("真的要删除这条记录吗?")
            .setPositiveButton("确定", new DialogInterface.OnClickListener() { 

              @Override
              public void onClick(DialogInterface dialog, int which) {
                new DeleteAsyncTask(mNoteDB).execute(note.getId());
                new NewAsyncTask().execute();
              }
            })
            .setNegativeButton("取消", null)
            .show();
        return true;
      }
    });
    /**
     * 关于自己
     */
    mAbout.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        Intent intent = new Intent(MainActivity.this,AboutActivity.class);
        startActivity(intent);
      }
    }); 

  } 

  public void initView() {
    /**
     * 布局控件初始化
     */
    mTitle = (TextView) findViewById(R.id.app_title);
    // 画TextView文字下的下划线
//    mTitle.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG);
    mNoteNum = (TextView) findViewById(R.id.note_num);
    mWrite = (ImageButton) findViewById(R.id.write_btn);
    mNoteListView = (ListView) findViewById(R.id.listview);
    mAbout = (ImageButton) findViewById(R.id.about_btn);
    /**
     * 获取数据库实例
     */
    mNoteDB = NoteDB.getInstance(this);
  }
  /**
   * 异步加载备忘录
   */
  class NewAsyncTask extends AsyncTask<Void,Void,List<Note>>{ 

    @Override
    protected List<Note> doInBackground(Void... voids) {
      mNoteList = mNoteDB.loadNotes();
      return mNoteList;
    } 

    @Override
    protected void onPostExecute(List<Note> notes) {
      super.onPostExecute(notes);
      /**
       * 设置适配器,绑定适配器
       */
      MyAdapter myAdapter = new MyAdapter(MainActivity.this,notes,mNoteListView);
      mNoteListView.setAdapter(myAdapter);
      /**
       * 更新备忘录记录数
       */
      int temp = mNoteList.size();
      mNoteNum.setText("共 " + temp + " 条备忘录");
    }
  }
  /**
   * 当活动恢复时,刷新listview和备忘录记录数
   */
  @Override
  protected void onResume() {
    super.onResume();
    new NewAsyncTask().execute();
  } 

}

在上面的代码中,我新建了一个 NewAsyncTask 类去继承 AsyncTask,去执行从数据库读取数据的操作,在onPostExecute()方法中,去更新UI,比如显示ListView中的数据,一下页面底部中间有几条数据等。还有我考虑了新建记事本的话,是另外一个Activity。当从另外的Activity返回到主Activity时,主页面应该再刷新一次,刷新数据和显示,所以我在onResume()方法中调用了 NewAsyncTask().execute() 方法,当活动恢复时刷新显示。
接下来是新建记事本的Activity,布局如下:write_note.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/screen_view"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:background="@drawable/repeat_bg"
  android:orientation="vertical"> 

  <RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="40dp"> 

    <ImageButton
      android:id="@+id/back_btn"
      android:src="@drawable/back_btn"
      android:layout_alignParentLeft="true"
      android:paddingLeft="5dp"
      android:background="#00ffffff"
      android:scaleType="center"
      android:layout_marginTop="6dp"
      android:layout_width="52dp"
      android:layout_height="32dp" /> 

    <TextView
      android:id="@+id/complete_btn"
      android:layout_alignParentRight="true"
      android:paddingTop="10dp"
      android:paddingRight="10dp"
      android:textSize="18sp"
      android:textColor="#ec6d51"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="@string/complete"/> 

  </RelativeLayout> 

  <EditText
    android:id="@+id/note_content"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingLeft="10dp"
    android:paddingRight="10dp"
    android:textColor="#333"
    android:textCursorDrawable="@null"
    android:background="@null"/> 

</LinearLayout> 

具体效果如下:

新建记事本的Activity如下:AddNoteActivity.java

package com.ikok.notepad.Activity; 

import android.app.Activity;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.view.View;
import android.view.Window;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast; 

import com.ikok.notepad.DBUtil.NoteDB;
import com.ikok.notepad.Entity.Note;
import com.ikok.notepad.R; 

import java.text.SimpleDateFormat;
import java.util.Date; 

/**
 * Created by Anonymous on 2016/3/24.
 */
public class AddNoteActivity extends Activity { 

  /**
   * 布局控件
   */
  private TextView mComplete;
  private ImageButton mBackBtn;
  private EditText mContent;
  /**
   * 备忘录数据
   */
  private String noteTime;
  private String noteContent;
  /**
   * 数据库
   */
  private NoteDB mNoteDB;
  private Note note; 

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.write_note); 

    initView();
    initEvent();
  } 

  private void initView() {
    /**
     * 布局控件初始化
     */
    mComplete = (TextView) findViewById(R.id.complete_btn);
    mBackBtn = (ImageButton) findViewById(R.id.back_btn);
    mContent = (EditText) findViewById(R.id.note_content);
    /**
     * 获取数据库实例
     */
    mNoteDB = NoteDB.getInstance(this);
  } 

  /**
   * 事件处理
   */
  private void initEvent() {
    /**
     * 返回上一级菜单,如果有内容,提示是否保存
     * 是、保存,销毁活动;否,直接销毁活动
     */
    mBackBtn.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
        saveDataOrNot();
      }
    }); 

    /**
     * 完成按钮,保存备忘录到数据库
     */
    mComplete.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
        if (!mContent.getText().toString().equals("")){
          new AddAsyncTask().execute();
          finish();
        } else {
          finish();
        }
      }
    });
  }
  /**
   * 根据是否有内容,提示保存
   */
  private void saveDataOrNot() {
    if (!mContent.getText().toString().trim().equals("")) {
      new AlertDialog.Builder(AddNoteActivity.this)
          .setTitle("提示")
          .setMessage("需要保存您编辑的内容吗?")
          .setPositiveButton("确定", new DialogInterface.OnClickListener() { 

            @Override
            public void onClick(DialogInterface dialog, int which) {
              new AddAsyncTask().execute();
              finish();
            }
          })
          .setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
              finish();
            }
          })
          .show();
    } else {
      finish();
    }
  } 

  /**
   * 添加数据到数据库
   */
  class AddAsyncTask extends AsyncTask<Void,Void,Void>{ 

    @Override
    protected Void doInBackground(Void... voids) {
      mNoteDB.saveNote(note);
      return null;
    } 

    @Override
    protected void onPreExecute() {
      super.onPreExecute();
      /**
       * 记录数据
       */
      SimpleDateFormat sdf = new SimpleDateFormat("MM-dd HH:mm");
      Date date = new Date(System.currentTimeMillis());
      noteTime = sdf.format(date);
      noteContent = mContent.getText().toString();
      note = new Note();
      note.setTime(noteTime);
      note.setContent(noteContent);
    } 

    @Override
    protected void onPostExecute(Void aVoid) {
      super.onPostExecute(aVoid);
      Toast.makeText(AddNoteActivity.this, "保存成功!", Toast.LENGTH_SHORT).show();
    }
  } 

  /**
   * 按返回键,有内容时,提示保存
   */
  @Override
  public void onBackPressed() {
    saveDataOrNot();
  }
}

新建记事本,插入数据到数据库,如从数据库读取数据一样,都是耗时操作,所以我还是用了AsyncTask,在 onPreExecute()方法中,先获取到系统当前时间,进行格式化,存储下来,把输入的文本存储下来,然后再 doInBackground()去保存数据。这里我考虑了,用户输入了内容,但是没有保存,在顶部的返回键或者系统的返回键的处理事件中都加了判断。如果文本为空,空格也算空,则不保存,直接退出当前Activity,如果有内容,则弹出对话框提示用户是否保存,是则保存,否则不保存,退出当前活动。

接下来是查看或修改一条记事本了,布局我是直接复用新建记事本的布局。因为没有区别 - -

接下来是查看或修改一条记事本的Activity了,之前,我想的是点击一条记事本,则进入这条记事本,把这条记事本直接显示在页面上,用户直接在内容最后进行编辑。所以这里需要一个子项点击事件。我在MainActivity里已经写了,先获取当前点击的这一项的对象,这里我费了好多时间,我不知道点击这一项的时候,怎么把该项的对象读取出来。最后自己查看源码,查API,看到参数中AdapterView是个泛型,我试着从它着手,把它强转成Note对象,然后试试获取id,没想到就成了。 - - 
所以,我获取了当前点击的item中的Note对象的id,把它放在Intent中,带着这个参数去开启活动。
这里,查看或修改一条记事本的Activity正式开始了,如下:UpdateOrReadActivity.java

package com.ikok.notepad.Activity; 

import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView; 

import com.ikok.notepad.DBUtil.NoteDB;
import com.ikok.notepad.Entity.Note;
import com.ikok.notepad.R;
import com.ikok.notepad.Util.DeleteAsyncTask; 

import java.text.SimpleDateFormat;
import java.util.Date; 

/**
 * Created by Anonymous on 2016/3/24.
 */
public class UpdateOrReadActivity extends Activity { 

  /**
   * 布局控件
   */
  private TextView mComplete;
  private ImageButton mBackBtn;
  private EditText mContent;
  private LinearLayout mScreen;
  /**
   * 备忘录数据
   */
  private int noteId;
  private String noteTime;
  private String noteContent;
  private String originData;
  /**
  * 数据库
  */
  private NoteDB mNoteDB;
  private static Note note; 

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.write_note);
    /**
     * 获取传递过来的note对象
     */
    Intent intent = getIntent();
    // 传递Note对象,必须要Note实体实现Serializable
//    note = (Note) intent.getSerializableExtra("note_item");
    noteId = intent.getIntExtra("note_id",0);
    Log.d("Anonymous", "传递后的备忘录ID:" + noteId); 

    initView();
    /**
     * 加载显示数据
     */
    new LoadAsyncTask().execute();
    initEvent();
  } 

  private void initView() {
    /**
     * 布局控件初始化
     */
    mComplete = (TextView) findViewById(R.id.complete_btn);
    mBackBtn = (ImageButton) findViewById(R.id.back_btn);
    mContent = (EditText) findViewById(R.id.note_content);
    mScreen = (LinearLayout) findViewById(R.id.screen_view);
    /**
     * 获取数据库实例
     */
    mNoteDB = NoteDB.getInstance(this);
  } 

  private void initEvent() {
    /**
     * 返回上一级菜单,直接销毁当前活动
     */
    mBackBtn.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
        updateDataOrNot();
      }
    });
    /**
     * 完成按钮,修改备忘录到数据库
     */
    mComplete.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
        if (mContent.getText().toString().trim().equals("")){
//          Log.d("Anonymous","进入判断为空函数");
          new DeleteAsyncTask(mNoteDB).execute(noteId);
          finish();
        } else if (mContent.getText().toString().equals(originData)) {
          finish();
        } else {
//          Log.d("Anonymous","进入判断不为空函数");
          new UpdateAsyncTask().execute();
//          Toast.makeText(UpdateOrReadActivity.this, "修改成功!", Toast.LENGTH_SHORT).show();
          finish();
        }
      }
    });
    /**
     * 点击屏幕空白区域,EditText选中
     */ 

  } 

  /**
   * 根据id从数据库读数据的异步任务
   */
  class LoadAsyncTask extends AsyncTask<Void,Void,Note>{ 

    @Override
    protected Note doInBackground(Void... voids) {
      note = mNoteDB.loadById(noteId);
      return note;
    } 

    @Override
    protected void onPostExecute(Note note) {
      super.onPostExecute(note);
      /**
       * 根据传递进来的Note显示备忘录内容,并把光标移动到最后
       * 记录最初的文本内容
       */
      originData = note.getContent();
      mContent.setText(note.getContent());
      mContent.setSelection(mContent.getText().toString().length());
    }
  }
  /**
   * 更新数据库的异步任务
   */
  class UpdateAsyncTask extends AsyncTask<Void,Void,Void>{ 

    @Override
    protected void onPreExecute() {
      super.onPreExecute();
      /**
       * 记录数据
       */
      SimpleDateFormat sdf = new SimpleDateFormat("MM-dd HH:mm");
      Date date = new Date(System.currentTimeMillis());
      noteTime = sdf.format(date);
      noteContent = mContent.getText().toString();
      note.setTime(noteTime);
      note.setContent(noteContent);
    } 

    @Override
    protected Void doInBackground(Void... voids) {
      mNoteDB.updateById(noteTime, noteContent, noteId);
      return null;
    }
  }
  /**
   * 根据是否有内容,提示保存
   */
  private void updateDataOrNot() {
    if (!mContent.getText().toString().equals(originData)) {
      new AlertDialog.Builder(UpdateOrReadActivity.this)
          .setTitle("提示")
          .setMessage("需要保存您编辑的内容吗?")
          .setPositiveButton("确定", new DialogInterface.OnClickListener() { 

            @Override
            public void onClick(DialogInterface dialog, int which) {
              new UpdateAsyncTask().execute();
              finish();
            }
          })
          .setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
              finish();
            }
          })
          .show();
    } else {
      finish();
    }
  }
  /**
   * 返回键事件
   * 根据内容是否有变化,提示是否保存
   */
  @Override
  public void onBackPressed() {
    updateDataOrNot();
  }
}

操作数据库还是用了AsyncTask。这里,我考虑了,是否有改动,用一个变量,去存放原始的数据,在用户点击顶部返回或者系统返回键的时候去判断是否有改动,如果有,则提示用户是否需要保存更改。如果修改内容,没有字了,则自动删除该条记事本。因为删除记事本的操作,在主页还需要用到,所以我把它提出来,单独作为一个类,不再是内部类了。如下:

package com.ikok.notepad.Util; 

import android.os.AsyncTask; 

import com.ikok.notepad.DBUtil.NoteDB; 

/**
 * Created by Anonymous on 2016/3/25.
 */
public class DeleteAsyncTask extends AsyncTask<Integer,Void,Void> { 

  private NoteDB noteDB; 

  public DeleteAsyncTask(NoteDB noteDB) {
    this.noteDB = noteDB;
  } 

  @Override
  protected Void doInBackground(Integer... params) {
    noteDB.deleteById(params[0]);
    return null;
  } 

}

接下来是CRUD的最后一项,删除数据了,在主页的时候,我设计的是单击进入该条记事本,去查看或修改这一条记事本,然后我考虑的是长按删除。长按,弹出对话框,提示是否删除,是则删除,否则不做任何事。所以在MainActivity中可以看到长按事件的监听器。但是因为Android的事件分发机制,长按事件必定会触发点击事件。所以需要在ListView中设置这样一个属性,才能点击事件和长按事件同时监听。
android:descendantFocusability="blocksDescendants"

主要功能都差不多完成了。接下来就是优化App了。我设计了过渡动画,引导页,以及是否第一次启动App。是则过渡动画过渡完到引导页,引导页完才到主页。否则过渡动画过渡完则直接进入主页。还设计了引导页的切换动画,使用了nineoldandroid,保证动画在低版本手机上可显示。

优化App部分可见我另外一篇博客,传送门:Android实现过渡动画、引导页 Android判断是否第一次启动App

项目地址在:https://github.com/someonexiaole/Android
Notepad 即是。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android实现简易记事本

    本文实例为大家分享了Android实现简易记事本的具体代码,供大家参考,具体内容如下 此次做的Android简易记事本的存储方式使用了SQLite数据库,然后界面的实现比较简单,但是,具有增删改查的基本功能,这里可以看一下效果图,如下: 具体操作就是长按可以删除操作,点击可以进行修改,点击添加笔记按钮可以添加一个笔记. 首先我们需要三个界面样式一个是我们的进入程序时的第一个界面,然后第一个界面里面有一个ListView,这个ListView需要一个xml来描述里面的各个元素,这也是第二个.还有一

  • Android实现记事本功能(26)

    本文实例为大家分享了Android实现记事本功能的具体代码,供大家参考,具体内容如下 MainActivity.java代码: package siso.smartnotef.activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.support.

  • Android实现记事本功能

    本文实例为大家分享了Android实现记事本功能的具体代码,供大家参考,具体内容如下 实现功能 1.文本数据的存储 2.图片数据存储 3.视频数据存储 4.自定义的Adapter 5.SQlite的创建 6.数据listview列表的显示 demo地址 记事本 界面布局 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.

  • Android中实现记事本动态添加行效果

    本文主要给大家介绍了关于Android实现记事本动态添加行的相关内容,分享出来供大家参考学习,下面来一起看看详细的介绍: 先看效果图: 这是昨天在群里面有人在问这个问题,在这里顺便记录一下,这个效果我们可以自定义EditText,实现起来也不难 看详细步骤: 第一:初始化Paint,这里肯定要用到画笔的 this.paint = new Paint(); paint.setStyle(Paint.Style.STROKE); paint.setColor(getResources().getCo

  • Android利用Intent实现记事本功能(NotePad)

    本文实例为大家分享了Intent如何实现一个简单的记事本功能的演示过程,供大家参考,具体内容如下 1.运行截图 单击右上角[-]会弹出[添加]菜单项,长按某条记录会弹出快捷菜单[删除]项. 2.主要设计步骤 (1)添加引用 鼠标右击[引用]à[添加引用],在弹出的窗口中勾选"System.Data"和"System.Data.SQlite",如下图所示: 注意:不需要通过NuGet添加SQLite程序包,只需要按这种方式添加即可. (2)添加图片 到Android

  • Android+SQLite数据库实现的生词记事本功能实例

    本文实例讲述了Android+SQLite数据库实现的生词记事本功能.分享给大家供大家参考,具体如下: 主activity命名为 Dict: 代码如下: package example.com.myapplication; import android.app.Activity; import android.content.Intent; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase;

  • android实现记事本app

    自己写的一个简单的记事本app,效果如下: 一.首先是第一个界面的编写,最上面是一个TextView,中间是一个Linearlayout中嵌套一个listview布局,最下面是一个button.下面附上第一个页面的简单布局xml文件. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" androi

  • Android记事本项目开发

    写了一个Android记事本小程序,现在记录一下. 考虑到是记事本小程序,记录的内容只有文字,而且内容不会太长,所以选择使用SQLite数据库,数据存放在用户的手机上. 牵涉到数据库,那自然是一个实体.先设计实体数据表:DBHelper.java package com.ikok.notepad.DBUtil; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android

  • Android项目开发常用工具类LightTaskUtils源码介绍

    目录 LightTaskUtils概述 LightTaskUtils截图 LightTaskUtils源码 版权声明 本文原创作者:谷哥的小弟 作者博客地址:http://blog.csdn.net/lfdfhl LightTaskUtils概述 LightTaskUtils是一个轻量级的线程管理工具. LightTaskUtils截图 LightTaskUtils截图如下: LightTaskUtils源码 LightTaskUtils源码如下: import android.os.Handl

  • Android微信支付开发问题

    并不是所有的BAT的API都是非常好用的,微信支付就有不少的缺陷,总结一下微信支付实现中出现的问题   坑点一: PayReq的参数 sign的生成   PayReq对象有个参数为packageValue 而sign生成时要用到packageValue,但是对应的Key是package,这里的key容易弄错 复制代码 代码如下: List<NameValuePair> signParams = new LinkedList<NameValuePair>();         sig

  • Android Studio项目中导入开源库的方法

    前两天,谷歌发布了Android Studio 1.0的正式版,也有更多的人开始迁移到Android Studio进行开发.然而,网上很多的开源库,控件等还是以前的基于Eclipse进行开发,很多人不知道怎么导入到自己的基于Android Studio项目中来,微博上也有人私信我,让我来写写,正好今天回来的比较早,就写写吧.主要介绍一下常见的一些导包的场景. 前言 复制代码 代码如下: --project   //项目目录   |   build.gradle  //项目的gradle配置文件

  • vue-cli+webpack记事本项目创建

    vue-cli+webpack记事本项目使用的是vue-cli2.0里面的项目构建工具webpack 项目的准备工作: 1.了解vue2.0 2.了解一些ES6 3.储备一些webpack知识 参照项目地址:vue2.0构建单页应用最佳实战 我们将会选择使用一些vue周边的库 vue-cli , vue-router , vue-resource , vuex 1.使用vue-cli创建项目 2.使用vue-router实现单页路由 3.用vuex管理我们的数据流 4.使用vue-resourc

  • Android+Html5混合开发仿微信朋友圈

    开发之前 大约从去年开始吧, 也可能是前年 Html5好像火得不得了, 不得了...总能从网上听说到 XXX混合开发, 为了紧跟潮流(虽然有点儿晚了), 咱们也看看Android+Html5混合开发是怎样的! 今天带来的案例是微信的朋友圈, 因为我觉得是微信把H5给"捧红了". 不过丑话说在前头, 咱们的仿朋友圈可是"低仿", 只是把混合开发的大致流程说说, 界面可能不堪入目...见谅.. 开发环境 Android Studio 2.2.2 JDK1.7 API 2

  • Android Studio应用开发集成百度语音合成使用方法实例讲解

    首先,语音合成是指将文本信息转换成声音.意思就是将文本转化为声音,让你的应用开口说话.国内在业内比较有名的第三方语音合成平台有百度语音和科大讯飞. 本文集成的是百度语音合成,其主要特点是: 完全永久免费 业界首创完全永久免费新形式,为开发者提供最流畅最自然的语音合成服务.完全免费,永久使用,彻底摆脱限制. 离线在线融合模式 SDK可以根据当前网络状况,自动判断使用本地引擎还是云端引擎进行语音合成,再也不用担心流量消耗! 多语言多音色可选 中文普通话.中英文混读.男声.女声任你选,更支持语速.音调

  • C#之Android手机App开发

    目前Android在全世界市场上大约有75%的占有率,国人Android手机的持有比例更甚,甚至达到90%以上.因此搞计算机的一听说手机应用开发,一个个都像着了魔似的,既然有那么多人对它感兴趣,那咱也跟着玩一玩.但是,本模块不是介绍如何用Java开发,而是全部用C#去实现. 为什么用C#去实现?原因很简单,目前手机市场经过多年的你争我斗,现在就剩下Android.iOS.Windows Phone还能互相斗狠,其他的统统都被打趴下找不着北了.但是,学Android应用开发要用Java.学iOS应

  • Android 判断是开发debug模式,还是发布release模式的方法

    如下所示: public class LogUtils { public static boolean APP_DBG = false; // 是否是debug模式 public static void init(Context context){ APP_DBG = isApkDebugable(context); } /** * 但是当我们没在AndroidManifest.xml中设置其debug属性时: * 使用Eclipse运行这种方式打包时其debug属性为true,使用Eclips

  • 从零开始搭建一个react项目开发

    本文介绍了从零开始搭建一个react项目开发,分享给大家,具体如下: 1.npm init 生成 package.json 文件. 2.安装各种需要的依赖: npm install  --save react - 安装React. npm install  --save react-dom 安装React Dom,这个包是用来处理virtual DOM.这里提一下用React Native的话,这里就是安装react-native. npm install  --save-dev webpack

随机推荐