Android記事本項(xiàng)目開發(fā)
寫了一個(gè)Android記事本小程序,現(xiàn)在記錄一下。
考慮到是記事本小程序,記錄的內(nèi)容只有文字,而且內(nèi)容不會(huì)太長(zhǎng),所以選擇使用SQLite數(shù)據(jù)庫(kù),數(shù)據(jù)存放在用戶的手機(jī)上。
牽涉到數(shù)據(jù)庫(kù),那自然是一個(gè)實(shí)體。先設(shè)計(jì)實(shí)體數(shù)據(jù)表: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 { /** * 創(chuàng)建筆記表 */ 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) { } }
創(chuàng)建完數(shù)據(jù)表后,自然需要操作數(shù)據(jù)庫(kù),CRUD數(shù)據(jù),我把所有跟數(shù)據(jù)庫(kù)有關(guān)的操作封裝在一起: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 的實(shí)例 * @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>(); /** * 先按時(shí)間降序排列,再按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); } }
設(shè)計(jì)完數(shù)據(jù)庫(kù)后,與數(shù)據(jù)庫(kù)對(duì)應(yīng)的需要一個(gè)實(shí)體類: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; } }
接下來(lái)進(jìn)行App主頁(yè)的設(shè)計(jì):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>
具體效果如下(圖標(biāo)懶得去改顏色了):
左邊的是一個(gè)關(guān)于App的按鈕,右邊的新建記事本的按鈕。
因?yàn)橹黜?yè)需要顯示已經(jīng)記錄的內(nèi)容,所以我選擇用ListView去顯示。用到ListView,則與之對(duì)應(yīng)的是要一個(gè)數(shù)據(jù)源,一個(gè)適配器。所以我為每一條子項(xiàng)設(shè)計(jì)了一個(gè)樣式,去讓它左邊顯示創(chuàng)建或更新的時(shí)間,右邊顯示內(nèi)容。如下: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>
創(chuàng)建好了ListView,接下來(lái)為它準(zhǔn)備適配器: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","執(zhí)行了適配器里的點(diǎn)擊事件"); // } // }); return convertView; } class ViewHolder{ public TextView mTime; public TextView mContent; } }
這里采用了使用ViewHolder,來(lái)使ListView滾動(dòng)的時(shí)候不必每次重新創(chuàng)建對(duì)象,提升性能。
創(chuàng)建好了ListView,準(zhǔn)備好了適配器,接下來(lái)要為L(zhǎng)istView準(zhǔn)備數(shù)據(jù)源,而這數(shù)據(jù)源是要從數(shù)據(jù)庫(kù)讀出來(lái)的。但是數(shù)據(jù)庫(kù)操作和網(wǎng)絡(luò)訪問(wèn)等都是屬于耗時(shí)操作,如果用主UI線程去執(zhí)行響應(yīng)操作的話,很可能會(huì)出現(xiàn)ANR現(xiàn)象,所以這里我用AsyncTask去執(zhí)行數(shù)據(jù)庫(kù)操作。主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; /** * 數(shù)據(jù)庫(kù)實(shí)例,數(shù)據(jù)源 */ 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", "點(diǎn)擊ListView獲取的note id: " + note.getId()); Intent intent = new Intent(MainActivity.this, UpdateOrReadActivity.class); intent.putExtra("note_id", note.getId()); startActivity(intent); } }); /** * listview長(zhǎng)按刪除 */ 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", "長(zhǎng)按ListView獲取的note id: " + note.getId()); /** * 長(zhǎng)按提示是否刪除 */ new AlertDialog.Builder(MainActivity.this) .setTitle("提示") .setMessage("真的要?jiǎng)h除這條記錄嗎?") .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; } }); /** * 關(guān)于自己 */ 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); /** * 獲取數(shù)據(jù)庫(kù)實(shí)例 */ 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); /** * 設(shè)置適配器,綁定適配器 */ MyAdapter myAdapter = new MyAdapter(MainActivity.this,notes,mNoteListView); mNoteListView.setAdapter(myAdapter); /** * 更新備忘錄記錄數(shù) */ int temp = mNoteList.size(); mNoteNum.setText("共 " + temp + " 條備忘錄"); } } /** * 當(dāng)活動(dòng)恢復(fù)時(shí),刷新listview和備忘錄記錄數(shù) */ @Override protected void onResume() { super.onResume(); new NewAsyncTask().execute(); } }
在上面的代碼中,我新建了一個(gè) NewAsyncTask 類去繼承 AsyncTask,去執(zhí)行從數(shù)據(jù)庫(kù)讀取數(shù)據(jù)的操作,在onPostExecute()方法中,去更新UI,比如顯示ListView中的數(shù)據(jù),一下頁(yè)面底部中間有幾條數(shù)據(jù)等。還有我考慮了新建記事本的話,是另外一個(gè)Activity。當(dāng)從另外的Activity返回到主Activity時(shí),主頁(yè)面應(yīng)該再刷新一次,刷新數(shù)據(jù)和顯示,所以我在onResume()方法中調(diào)用了 NewAsyncTask().execute() 方法,當(dāng)活動(dòng)恢復(fù)時(shí)刷新顯示。
接下來(lái)是新建記事本的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; /** * 備忘錄數(shù)據(jù) */ private String noteTime; private String noteContent; /** * 數(shù)據(jù)庫(kù) */ 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); /** * 獲取數(shù)據(jù)庫(kù)實(shí)例 */ mNoteDB = NoteDB.getInstance(this); } /** * 事件處理 */ private void initEvent() { /** * 返回上一級(jí)菜單,如果有內(nèi)容,提示是否保存 * 是、保存,銷毀活動(dòng);否,直接銷毀活動(dòng) */ mBackBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { saveDataOrNot(); } }); /** * 完成按鈕,保存?zhèn)渫浀綌?shù)據(jù)庫(kù) */ mComplete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (!mContent.getText().toString().equals("")){ new AddAsyncTask().execute(); finish(); } else { finish(); } } }); } /** * 根據(jù)是否有內(nèi)容,提示保存 */ private void saveDataOrNot() { if (!mContent.getText().toString().trim().equals("")) { new AlertDialog.Builder(AddNoteActivity.this) .setTitle("提示") .setMessage("需要保存您編輯的內(nèi)容嗎?") .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(); } } /** * 添加數(shù)據(jù)到數(shù)據(jù)庫(kù) */ class AddAsyncTask extends AsyncTask<Void,Void,Void>{ @Override protected Void doInBackground(Void... voids) { mNoteDB.saveNote(note); return null; } @Override protected void onPreExecute() { super.onPreExecute(); /** * 記錄數(shù)據(jù) */ 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(); } } /** * 按返回鍵,有內(nèi)容時(shí),提示保存 */ @Override public void onBackPressed() { saveDataOrNot(); } }
新建記事本,插入數(shù)據(jù)到數(shù)據(jù)庫(kù),如從數(shù)據(jù)庫(kù)讀取數(shù)據(jù)一樣,都是耗時(shí)操作,所以我還是用了AsyncTask,在 onPreExecute()方法中,先獲取到系統(tǒng)當(dāng)前時(shí)間,進(jìn)行格式化,存儲(chǔ)下來(lái),把輸入的文本存儲(chǔ)下來(lái),然后再 doInBackground()去保存數(shù)據(jù)。這里我考慮了,用戶輸入了內(nèi)容,但是沒(méi)有保存,在頂部的返回鍵或者系統(tǒng)的返回鍵的處理事件中都加了判斷。如果文本為空,空格也算空,則不保存,直接退出當(dāng)前Activity,如果有內(nèi)容,則彈出對(duì)話框提示用戶是否保存,是則保存,否則不保存,退出當(dāng)前活動(dòng)。
接下來(lái)是查看或修改一條記事本了,布局我是直接復(fù)用新建記事本的布局。因?yàn)闆](méi)有區(qū)別 - -
接下來(lái)是查看或修改一條記事本的Activity了,之前,我想的是點(diǎn)擊一條記事本,則進(jìn)入這條記事本,把這條記事本直接顯示在頁(yè)面上,用戶直接在內(nèi)容最后進(jìn)行編輯。所以這里需要一個(gè)子項(xiàng)點(diǎn)擊事件。我在MainActivity里已經(jīng)寫了,先獲取當(dāng)前點(diǎn)擊的這一項(xiàng)的對(duì)象,這里我費(fèi)了好多時(shí)間,我不知道點(diǎn)擊這一項(xiàng)的時(shí)候,怎么把該項(xiàng)的對(duì)象讀取出來(lái)。最后自己查看源碼,查API,看到參數(shù)中AdapterView是個(gè)泛型,我試著從它著手,把它強(qiáng)轉(zhuǎn)成Note對(duì)象,然后試試獲取id,沒(méi)想到就成了。 - -
所以,我獲取了當(dāng)前點(diǎn)擊的item中的Note對(duì)象的id,把它放在Intent中,帶著這個(gè)參數(shù)去開啟活動(dòng)。
這里,查看或修改一條記事本的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; /** * 備忘錄數(shù)據(jù) */ private int noteId; private String noteTime; private String noteContent; private String originData; /** * 數(shù)據(jù)庫(kù) */ 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); /** * 獲取傳遞過(guò)來(lái)的note對(duì)象 */ Intent intent = getIntent(); // 傳遞Note對(duì)象,必須要Note實(shí)體實(shí)現(xiàn)Serializable // note = (Note) intent.getSerializableExtra("note_item"); noteId = intent.getIntExtra("note_id",0); Log.d("Anonymous", "傳遞后的備忘錄ID:" + noteId); initView(); /** * 加載顯示數(shù)據(jù) */ 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); /** * 獲取數(shù)據(jù)庫(kù)實(shí)例 */ mNoteDB = NoteDB.getInstance(this); } private void initEvent() { /** * 返回上一級(jí)菜單,直接銷毀當(dāng)前活動(dòng) */ mBackBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { updateDataOrNot(); } }); /** * 完成按鈕,修改備忘錄到數(shù)據(jù)庫(kù) */ mComplete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (mContent.getText().toString().trim().equals("")){ // Log.d("Anonymous","進(jìn)入判斷為空函數(shù)"); new DeleteAsyncTask(mNoteDB).execute(noteId); finish(); } else if (mContent.getText().toString().equals(originData)) { finish(); } else { // Log.d("Anonymous","進(jìn)入判斷不為空函數(shù)"); new UpdateAsyncTask().execute(); // Toast.makeText(UpdateOrReadActivity.this, "修改成功!", Toast.LENGTH_SHORT).show(); finish(); } } }); /** * 點(diǎn)擊屏幕空白區(qū)域,EditText選中 */ } /** * 根據(jù)id從數(shù)據(jù)庫(kù)讀數(shù)據(jù)的異步任務(wù) */ 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); /** * 根據(jù)傳遞進(jìn)來(lái)的Note顯示備忘錄內(nèi)容,并把光標(biāo)移動(dòng)到最后 * 記錄最初的文本內(nèi)容 */ originData = note.getContent(); mContent.setText(note.getContent()); mContent.setSelection(mContent.getText().toString().length()); } } /** * 更新數(shù)據(jù)庫(kù)的異步任務(wù) */ class UpdateAsyncTask extends AsyncTask<Void,Void,Void>{ @Override protected void onPreExecute() { super.onPreExecute(); /** * 記錄數(shù)據(jù) */ 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; } } /** * 根據(jù)是否有內(nèi)容,提示保存 */ private void updateDataOrNot() { if (!mContent.getText().toString().equals(originData)) { new AlertDialog.Builder(UpdateOrReadActivity.this) .setTitle("提示") .setMessage("需要保存您編輯的內(nèi)容嗎?") .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(); } } /** * 返回鍵事件 * 根據(jù)內(nèi)容是否有變化,提示是否保存 */ @Override public void onBackPressed() { updateDataOrNot(); } }
操作數(shù)據(jù)庫(kù)還是用了AsyncTask。這里,我考慮了,是否有改動(dòng),用一個(gè)變量,去存放原始的數(shù)據(jù),在用戶點(diǎn)擊頂部返回或者系統(tǒng)返回鍵的時(shí)候去判斷是否有改動(dòng),如果有,則提示用戶是否需要保存更改。如果修改內(nèi)容,沒(méi)有字了,則自動(dòng)刪除該條記事本。因?yàn)閯h除記事本的操作,在主頁(yè)還需要用到,所以我把它提出來(lái),單獨(dú)作為一個(gè)類,不再是內(nèi)部類了。如下:
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; } }
接下來(lái)是CRUD的最后一項(xiàng),刪除數(shù)據(jù)了,在主頁(yè)的時(shí)候,我設(shè)計(jì)的是單擊進(jìn)入該條記事本,去查看或修改這一條記事本,然后我考慮的是長(zhǎng)按刪除。長(zhǎng)按,彈出對(duì)話框,提示是否刪除,是則刪除,否則不做任何事。所以在MainActivity中可以看到長(zhǎng)按事件的監(jiān)聽器。但是因?yàn)锳ndroid的事件分發(fā)機(jī)制,長(zhǎng)按事件必定會(huì)觸發(fā)點(diǎn)擊事件。所以需要在ListView中設(shè)置這樣一個(gè)屬性,才能點(diǎn)擊事件和長(zhǎng)按事件同時(shí)監(jiān)聽。
android:descendantFocusability="blocksDescendants"
主要功能都差不多完成了。接下來(lái)就是優(yōu)化App了。我設(shè)計(jì)了過(guò)渡動(dòng)畫,引導(dǎo)頁(yè),以及是否第一次啟動(dòng)App。是則過(guò)渡動(dòng)畫過(guò)渡完到引導(dǎo)頁(yè),引導(dǎo)頁(yè)完才到主頁(yè)。否則過(guò)渡動(dòng)畫過(guò)渡完則直接進(jìn)入主頁(yè)。還設(shè)計(jì)了引導(dǎo)頁(yè)的切換動(dòng)畫,使用了nineoldandroid,保證動(dòng)畫在低版本手機(jī)上可顯示。
優(yōu)化App部分可見我另外一篇博客,傳送門:Android實(shí)現(xiàn)過(guò)渡動(dòng)畫、引導(dǎo)頁(yè) Android判斷是否第一次啟動(dòng)App
項(xiàng)目地址在:https://github.com/someonexiaole/Android
Notepad 即是。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android實(shí)現(xiàn)簡(jiǎn)易記事本
- Android實(shí)現(xiàn)記事本小功能
- Android實(shí)現(xiàn)記事本功能
- Android實(shí)現(xiàn)簡(jiǎn)易記事本
- android實(shí)現(xiàn)記事本app
- Android+SQLite數(shù)據(jù)庫(kù)實(shí)現(xiàn)的生詞記事本功能實(shí)例
- Android中實(shí)現(xiàn)記事本動(dòng)態(tài)添加行效果
- Android實(shí)現(xiàn)記事本功能(26)
- Android利用Intent實(shí)現(xiàn)記事本功能(NotePad)
- Android手機(jī)開發(fā)設(shè)計(jì)之記事本功能
相關(guān)文章
Android Presentation實(shí)現(xiàn)雙屏異顯
這篇文章主要為大家詳細(xì)介紹了Android Presentation實(shí)現(xiàn)雙屏異顯,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-01-01Android Activity啟動(dòng)模式之singleTask實(shí)例詳解
這篇文章主要介紹了Android Activity啟動(dòng)模式之singleTask,結(jié)合實(shí)例形式較為詳細(xì)的分析了singleTask模式的功能、使用方法與相關(guān)注意事項(xiàng),需要的朋友可以參考下2016-01-01Android實(shí)現(xiàn)取消GridView中Item選中時(shí)默認(rèn)的背景色
這篇文章主要介紹了Android實(shí)現(xiàn)取消GridView中Item選中時(shí)默認(rèn)的背景色,涉及Android GridView中Item屬性設(shè)置的相關(guān)技巧,需要的朋友可以參考下2016-02-02Android動(dòng)態(tài)繪制餅狀圖的示例代碼
這篇文章主要介紹了Android動(dòng)態(tài)繪制餅狀圖的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-03-03Android ScrollView嵌套ExpandableListView顯示不正常的問(wèn)題的解決辦法
這篇文章主要介紹了Android ScrollView嵌套ExpandableListView顯示不正常的問(wèn)題的解決辦法的相關(guān)資料,需要的朋友可以參考下2017-02-02RecyclerView中監(jiān)聽EditText變化的BUG的解決方法
本篇文章主要介紹了RecyclerView中監(jiān)聽EditText變化的BUG的解決方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11Android?LinearLayout快速設(shè)置每個(gè)item間隔
這篇文章主要介紹了Android?LinearLayout快速設(shè)置每個(gè)item間隔的相關(guān)資料,需要的朋友可以參考下2023-07-07