博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
(干货)Android入门完整项目:一个有定时提醒功能的备忘录
阅读量:6343 次
发布时间:2019-06-22

本文共 38020 字,大约阅读时间需要 126 分钟。

本文原创地址: (食用效果最佳),转载请注明出处!

项目源码地址:,欢迎fork,star

干货推荐:

介绍

分享一个以前学习android时做的小项目,一个带有定时提醒功能的备忘录,主要用到RecycleView, sqlite, butterknife,效果如下:

详细功能实现

建立db,编写db helper类

  1. 新建一个常量类,包含所有操作db的语句,ColumnContacts:
public class ColumnContacts {    public static final String EVENT_TABLE_NAME = "event";    public static final String EVENT_TITLE_COLUMN = "title";    public static final String EVENT_CONTENT_COLUMN = "content";    public static final String EVENT_CREATED_TIME_COLUMN = "created_time";    public static final String EVENT_UPDATED_TIME_COLUMN = "updated_time";    public static final String EVENT_REMIND_TIME_COLUMN = "remind_time";    public static final String EVENT_IS_IMPORTANT_COLUMN = "is_important";    public static final String EVENT_IS_CLOCKED = "is_clocked";}复制代码
  1. 新建一个DBTemplate,此处用到设计模式模板方法,所以还包含一个回调接口DBCallbackk
public class DBTemplate
{ private DBOpenHelper dbHelper; public DBTemplate() { dbHelper = new DBOpenHelper(); } public T queryOne(String sql, DBCallback
callback, String...args) { T t = null; SQLiteDatabase db = dbHelper.getReadableDatabase(); Cursor cursor = db.rawQuery(sql, args); if (cursor != null && cursor.moveToNext()) { t = callback.cursorToInstance(cursor); cursor.close(); } return t; } public List
query(String sql, DBCallback
callback, String... args) { List
list = new ArrayList<>(); SQLiteDatabase db = dbHelper.getReadableDatabase(); Cursor cursor = db.rawQuery(sql, args); if (cursor != null) { while (cursor.moveToNext()) { T t = callback.cursorToInstance(cursor); list.add(t); } cursor.close(); } return list; } public long create(String table, ContentValues values) { SQLiteDatabase db = dbHelper.getWritableDatabase(); return db.insert(table, null, values); } public int remove(String table, String whereConditions, String... args) { SQLiteDatabase db = dbHelper.getWritableDatabase(); return db.delete(table, whereConditions, args); } public int getLatestId(String table) { SQLiteDatabase db = dbHelper.getReadableDatabase(); String sql = "SELECT MAX(" + BaseColumns._ID + ") FROM " + table; Cursor cursor = db.rawQuery(sql, new String[]{}); int result = -1; if (cursor != null && cursor.moveToNext()) { result = cursor.getInt(0); cursor.close(); } return result; } public int update(String table, ContentValues contentValues, String whereConditions, String... args) { SQLiteDatabase db = dbHelper.getWritableDatabase(); return db.update(table, contentValues, whereConditions, args); }}复制代码
public interface DBCallback 
{ /** * Gets a instance of T by cursor */ T cursorToInstance(Cursor cursor);}复制代码
  1. 新建一个类继承SQLiteOpenHelperDBOpenHelper,用于启动app时创建数据库,并且初始化数据,加入一条记录:
public class DBOpenHelper extends SQLiteOpenHelper {    private static final String TAG = DBOpenHelper.class.getSimpleName();    private static final int VERSION = 1;    private static final String DB_NAME = "memo.db";    public DBOpenHelper() {        super(MemoApplication.getContext(), DB_NAME, null, VERSION);    }    @Override    public void onCreate(SQLiteDatabase db) {        /*第一次初始化app,创建表结构 */        db.execSQL("CREATE TABLE IF NOT EXISTS " + ColumnContacts.EVENT_TABLE_NAME + "( "                    + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "                    + ColumnContacts.EVENT_TITLE_COLUMN + " text, "                    + ColumnContacts.EVENT_CONTENT_COLUMN + " text, "                    + ColumnContacts.EVENT_CREATED_TIME_COLUMN + " datetime, "                    + ColumnContacts.EVENT_UPDATED_TIME_COLUMN + " datetime, "                    + ColumnContacts.EVENT_REMIND_TIME_COLUMN + " datetime, "                    + ColumnContacts.EVENT_IS_IMPORTANT_COLUMN + " INTEGER, "                    + ColumnContacts.EVENT_IS_CLOCKED + " INTEGER"        + ")");        String sql = "INSERT INTO " + ColumnContacts.EVENT_TABLE_NAME + " VALUES(NULL, ?, ?, ?, ?, ?, ?, ?)";        db.beginTransaction();        db.execSQL(sql, new Object[]{
"jsbintask->memo", "Memo是一个小巧方便带有闹铃功能的记事本app,主要使用butterknife和recycleview,clockmanager构建\n" + "git地址:https://github.com/jsbintask22/memo.git", "2018-04-25 17:28:23", "2018-04-25 17:28", "2018-04-25 17:28", 0, 0}); db.setTransactionSuccessful(); db.endTransaction(); } /*版本更新时会执行该方法,如版本变更 => 2 */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { //Nothing to do }}复制代码

编写dao层

记事本中是包含一个实体类,Event,编写实体类和dao层代码对该表进行增删改查 Event:

public class Event implements BaseColumns, Parcelable{    //id    private Integer mId;    //事件    private String mTitle;    //事件内容    private String mContent;    //创建时间    private String mCreatedTime;    public Integer getmIsClocked() {        return mIsClocked;    }    public void setmIsClocked(Integer mIsClocked) {        this.mIsClocked = mIsClocked;    }    //更新时间    private String mUpdatedTime;    //闹钟表示位:该事件是否已经响过铃了,默认没有    private Integer mIsClocked = 0;    public Event(){}    protected Event(Parcel in) {        if (in.readByte() == 0) {            mId = null;        } else {            mId = in.readInt();        }        mTitle = in.readString();        mContent = in.readString();        mCreatedTime = in.readString();        mUpdatedTime = in.readString();        if (in.readByte() == 0) {            mIsClocked = null;        } else {            mIsClocked = in.readInt();        }        if (in.readByte() == 0) {            mIsImportant = null;        } else {            mIsImportant = in.readInt();        }        mRemindTime = in.readString();    }    public static final Creator
CREATOR = new Creator
() { @Override public Event createFromParcel(Parcel in) { return new Event(in); } @Override public Event[] newArray(int size) { return new Event[size]; } }; public Integer getmIsImportant() { return mIsImportant; } public void setmIsImportant(Integer mIsImportant) { this.mIsImportant = mIsImportant; } private Integer mIsImportant; public Integer getmId() { return mId; } public void setmId(Integer mId) { this.mId = mId; } public String getmTitle() { return mTitle; } public void setmTitle(String mTitle) { this.mTitle = mTitle; } public String getmContent() { return mContent; } public void setmContent(String mContent) { this.mContent = mContent; } public String getmCreatedTime() { return mCreatedTime; } public void setmCreatedTime(String mCreatedTime) { this.mCreatedTime = mCreatedTime; } public String getmUpdatedTime() { return mUpdatedTime; } public void setmUpdatedTime(String mUpdatedTime) { this.mUpdatedTime = mUpdatedTime; } public String getmRemindTime() { return mRemindTime; } public void setmRemindTime(String mRemindTime) { this.mRemindTime = mRemindTime; } private String mRemindTime; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { if (mId == null) { dest.writeByte((byte) 0); } else { dest.writeByte((byte) 1); dest.writeInt(mId); } dest.writeString(mTitle); dest.writeString(mContent); dest.writeString(mCreatedTime); dest.writeString(mUpdatedTime); if (mIsClocked == null) { dest.writeByte((byte) 0); } else { dest.writeByte((byte) 1); dest.writeInt(mIsClocked); } if (mIsImportant == null) { dest.writeByte((byte) 0); } else { dest.writeByte((byte) 1); dest.writeInt(mIsImportant); } dest.writeString(mRemindTime); }}复制代码

值得注意的是,为了让其在Activity之间传递数据,需要继承Parcelable接口,接下编写EventDao,因为用到了模板方法,所以加入回调类EventCallback

public class EventDao {    //使用模板模式进行DB操作    private DBTemplate
mTemplate = new DBTemplate<>(); private EventCallback mCallback = new EventCallback(); //设置为单例模式,其他类均是此方法 private static EventDao mEventDao = new EventDao(); private EventDao() { } public static EventDao getInstance() { return mEventDao; } public List
findAll() { String sql = "SELECT * FROM " + ColumnContacts.EVENT_TABLE_NAME + " ORDER BY " + ColumnContacts.EVENT_IS_IMPORTANT_COLUMN + " DESC, " + ColumnContacts.EVENT_CREATED_TIME_COLUMN + " DESC"; return mTemplate.query(sql, mCallback); } public List
findAllWithNOClocked() { String sql = "SELECT * FROM " + ColumnContacts.EVENT_TABLE_NAME + " WHERE " + ColumnContacts.EVENT_IS_CLOCKED + " = " + Constants.EventClockFlag.NONE; return mTemplate.query(sql, mCallback); } public int updateEventClocked(Integer id) { ContentValues contentValues = new ContentValues(); contentValues.put(ColumnContacts.EVENT_IS_CLOCKED, Constants.EventClockFlag.CLOCKED); return mTemplate.update(ColumnContacts.EVENT_TABLE_NAME, contentValues, BaseColumns._ID + " = ?", Integer.toString(id)); } public Event findById(Integer id) { String sql = "SELECT * FROM " + ColumnContacts.EVENT_TABLE_NAME + " WHERE " + BaseColumns._ID + " = ?"; return mTemplate.queryOne(sql, mCallback, Integer.toString(id)); } public int remove(List
ids) { StringBuilder whereConditions = new StringBuilder(BaseColumns._ID + " IN("); for (Integer id : ids) { whereConditions.append(id).append(","); } whereConditions.deleteCharAt(whereConditions.length() - 1).append(")"); return mTemplate.remove(ColumnContacts.EVENT_TABLE_NAME, whereConditions.toString()); } public int create(Event event) { return (int) mTemplate.create(ColumnContacts.EVENT_TABLE_NAME, generateContentValues(event, false)); } public int update(Event event) { return mTemplate.update(ColumnContacts.EVENT_TABLE_NAME, generateContentValues(event, true), BaseColumns._ID + " = ?", Integer.toString(event.getmId())); } public int getLatestEventId() { return mTemplate.getLatestId(ColumnContacts.EVENT_TABLE_NAME); } private ContentValues generateContentValues(Event event, boolean isUpdate) { ContentValues contentValues = new ContentValues(); contentValues.put(ColumnContacts.EVENT_TITLE_COLUMN, event.getmTitle()); contentValues.put(ColumnContacts.EVENT_CONTENT_COLUMN, event.getmContent()); if (!isUpdate) { contentValues.put(ColumnContacts.EVENT_CREATED_TIME_COLUMN, DateTimeUtil.dateToStr(new Date())); } else { contentValues.put(ColumnContacts.EVENT_CREATED_TIME_COLUMN, event.getmCreatedTime()); } contentValues.put(ColumnContacts.EVENT_IS_CLOCKED, event.getmIsClocked()); contentValues.put(ColumnContacts.EVENT_UPDATED_TIME_COLUMN, DateTimeUtil.dateToStr(new Date())); contentValues.put(ColumnContacts.EVENT_REMIND_TIME_COLUMN, event.getmRemindTime()); contentValues.put(ColumnContacts.EVENT_IS_IMPORTANT_COLUMN, event.getmIsImportant()); return contentValues; }}复制代码
public class EventCallback implements DBCallback
{ @Override public Event cursorToInstance(Cursor cursor) { Event event = new Event(); event.setmId(cursor.getInt(cursor.getColumnIndexOrThrow(BaseColumns._ID))); event.setmTitle(cursor.getString(cursor.getColumnIndexOrThrow(ColumnContacts.EVENT_TITLE_COLUMN))); event.setmContent(cursor.getString(cursor.getColumnIndexOrThrow(ColumnContacts.EVENT_CONTENT_COLUMN))); event.setmCreatedTime(cursor.getString(cursor.getColumnIndexOrThrow(ColumnContacts.EVENT_CREATED_TIME_COLUMN))); event.setmUpdatedTime(cursor.getString(cursor.getColumnIndexOrThrow(ColumnContacts.EVENT_UPDATED_TIME_COLUMN))); event.setmRemindTime(cursor.getString(cursor.getColumnIndexOrThrow(ColumnContacts.EVENT_REMIND_TIME_COLUMN))); event.setmIsImportant(cursor.getInt(cursor.getColumnIndexOrThrow(ColumnContacts.EVENT_IS_IMPORTANT_COLUMN))); event.setmIsClocked(cursor.getInt(cursor.getColumnIndexOrThrow(ColumnContacts.EVENT_IS_CLOCKED))); return event; }}复制代码

编写manager层

  1. EventManager用于管理所有的event如下:
public class EventManager {    public static final String TAG = "EventManager";    private static EventManager mEventManager = new EventManager();    private EventDao mEventDao = EventDao.getInstance();    //保存一份数据    public List
getDeletedIds() { return deletedIds; } public void setDeletedIds(List
deletedIds) { this.deletedIds = deletedIds; } private List
events = new ArrayList<>(); private List
deletedIds = new ArrayList<>(); private EventManager(){ } public static EventManager getInstance() { return mEventManager; } public List
findAll() { events = mEventDao.findAll(); return events; } public void flushData() { events = mEventDao.findAll(); } public List
getEvents() { return events; } public void removeEvents(final Handler handler, final List
ids) { new Thread(new Runnable() { @Override public void run() { try { int result = mEventDao.remove(ids); Message message = new Message(); message.what = Constants.HANDLER_SUCCESS; message.obj = result; message.setTarget(handler); message.sendToTarget(); } catch (Exception e) { Log.e(TAG, "run: ", e); handler.obtainMessage(Constants.HANDLER_FAILED, new MemoException(e)).sendToTarget(); } } }).start(); } public boolean removeEvent(Integer id) { return mEventDao.remove(Collections.singletonList(id)) != 0; } public boolean saveOrUpdate(Event event) { try { if (event.getmId() != null) { mEventDao.update(event); } else { mEventDao.create(event); } return true; } catch (Exception e) { Log.e(TAG, "saveOrUpdate: ", e); return false; } } public int getLatestEventId() { return mEventDao.getLatestEventId(); } public Event getOne(Integer id) { return mEventDao.findById(id); } public boolean checkEventField(Event event) { if (event == null) { return false; } if (StringUtil.isBlank(event.getmTitle())) { ToastUtil.showToastShort(R.string.event_can_not_empty); return false; } if (StringUtil.isBlank(event.getmContent())) { ToastUtil.showToastShort(R.string.content_can_not_empty); return false; } if (StringUtil.isBlank(event.getmRemindTime())) { ToastUtil.showToastShort(R.string.remind_time_can_not_empty); return false; } if (DateTimeUtil.str2Date(event.getmRemindTime()) == null) { ToastUtil.showToastShort(R.string.invalid_remind_time_format); return false; } if (new Date().getTime() > DateTimeUtil.str2Date(event.getmRemindTime()).getTime()) { ToastUtil.showToastShort(R.string.remind_time_deprecated); return false; } return true; }}复制代码

接着编写一个ClockManager用于管理系统闹钟服务,用于app定时提醒:

public class ClockManager {    private static ClockManager instance = new ClockManager();    private ClockManager() {    }    public static ClockManager getInstance() {        return instance;    }    /**     * 获取系统闹钟服务     * @return     */    private static AlarmManager getAlarmManager() {        return (AlarmManager) MemoApplication.getContext().getSystemService(Context.ALARM_SERVICE);    }    /**     * 取消闹钟     * @param pendingIntent     */    public void cancelAlarm(PendingIntent pendingIntent) {        getAlarmManager().cancel(pendingIntent);    }    /**     * 添加闹钟     * @param pendingIntent 执行动作     * @param performTime  执行时间     */    public void addAlarm(PendingIntent pendingIntent, Date performTime) {        cancelAlarm(pendingIntent);        getAlarmManager().set(AlarmManager.RTC_WAKEUP, performTime.getTime(), pendingIntent);    }}复制代码

编写系统Service和Receiver

为了让我们的提醒服务在后台保活,我们需要编写一个ClockService或者ClockReceiver在后台运行(任意一种都行,此处用的service:

/** * Service和Broadcast都行,此处选一个,service存活率更高 */public class ClockService extends Service {    private static final String TAG = "ClockService";    public static final String EXTRA_EVENT_ID = "extra.event.id";    public static final String EXTRA_EVENT_REMIND_TIME = "extra.event.remind.time";    public static final String EXTRA_EVENT = "extra.event";    private EventDao mEventDao = EventDao.getInstance();    public ClockService() {        Log.d(TAG, "ClockService: Constructor");    }    @Override    public IBinder onBind(Intent intent) {        throw new UnsupportedOperationException("Not yet implemented");    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        Log.d(TAG, "onStartCommand: onStartCommand");        WakeLockUtil.wakeUpAndUnlock();        postToClockActivity(getApplicationContext(), intent);        return super.onStartCommand(intent, flags, startId);    }    private void postToClockActivity(Context context, Intent intent) {        Intent i = new Intent();        i.setClass(context, ClockActivity.class);        i.putExtra(EXTRA_EVENT_ID, intent.getIntExtra(EXTRA_EVENT_ID, -1));        Event event = mEventDao.findById(intent.getIntExtra(EXTRA_EVENT_ID, -1));        if (event == null) {            return;        }        i.putExtra(EXTRA_EVENT_REMIND_TIME, intent.getStringExtra(EXTRA_EVENT_REMIND_TIME));        i.putExtra(EXTRA_EVENT, event);        i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);        context.startActivity(i);    }    @Override    public void onDestroy() {        Log.d(TAG, "onDestroy: ");        super.onDestroy();    }}复制代码

ClockReceiver如下:

public class ClockReceiver extends BroadcastReceiver {    private static final String TAG = "ClockReceiver";    public static final String EXTRA_EVENT_ID = "extra.event.id";    public static final String EXTRA_EVENT_REMIND_TIME = "extra.event.remind.time";    public static final String EXTRA_EVENT = "extra.event";    private EventDao mEventDao = EventDao.getInstance();    @Override    public void onReceive(Context context, Intent intent) {        Log.d(TAG, "onReceive: " + intent.getAction());        WakeLockUtil.wakeUpAndUnlock();        postToClockActivity(context, intent);    }    private void postToClockActivity(Context context, Intent intent) {        Intent i = new Intent();        i.setClass(context, ClockActivity.class);        i.putExtra(EXTRA_EVENT_ID, intent.getIntExtra(EXTRA_EVENT_ID, -1));        Event event = mEventDao.findById(intent.getIntExtra(EXTRA_EVENT_ID, -1));        if (event == null) {            return;        }        i.putExtra(EXTRA_EVENT_REMIND_TIME, intent.getStringExtra(EXTRA_EVENT_REMIND_TIME));        i.putExtra(EXTRA_EVENT, event);        i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);        context.startActivity(i);    }    public ClockReceiver() {        super();        Log.d(TAG, "ClockReceiver: Constructor");    }}复制代码

Activity

接着编写Activity,首先,写一个主界面,用于展示事件清单,因为有多个Activity,所以我们加入BaseActivity:

public abstract class BaseActivity extends AppCompatActivity {    /*Butterknife绑定器,该activity销毁时要取消绑定,避免内存泄漏  */    private Unbinder mUnbinder;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(getContentView());        mUnbinder = ButterKnife.bind(this);        /*Base activity中的公共的方法,因为每个类都需要初始化,所以在基类中定义 */        initView();        initData();        setListener();    }    protected abstract void setListener();    protected abstract void initView();    protected abstract void initData();    public abstract int getContentView();    @Override    protected void onDestroy() {        super.onDestroy();        mUnbinder.unbind();    }}复制代码

MainActivity如下:

public class MainActivity extends BaseActivity implements BaseHandler.HandlerResultCallBack {    @BindView(R.id.recycler_view)    RecyclerView mRecyclerView;    @BindView(R.id.search_view)    SearchView mSearchView;    private EventRecyclerViewAdapter mAdapter;    private EventManager mEventManger = EventManager.getInstance();    private ClockManager mClockManager = ClockManager.getInstance();    private BaseHandler mBaseHandler = new BaseHandler(this);    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);    }    @Override    protected void initView() {        mAdapter = new EventRecyclerViewAdapter(this);        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mSearchView.getLayoutParams();        //将文字内容略微下移,SearchView  bug        params.bottomMargin = -3;        mSearchView.setLayoutParams(params);        mSearchView.onActionViewExpanded();        initSearchView();    }    private void initSearchView() {        //一处searchView进入屏幕时候的焦点        mSearchView.clearFocus();        Class
aClass = mSearchView.getClass(); try { //去掉SearchView自带的下划线 Field mSearchPlate = aClass.getDeclaredField("mSearchPlate"); mSearchPlate.setAccessible(true); View o = (View) mSearchPlate.get(mSearchView); o.setBackgroundColor(getColor(R.color.transparent)); } catch (Exception e) { e.printStackTrace(); } //隐藏键盘 AppUtil.hideSoftInput(this, mSearchView); } @Override protected void onStart() { super.onStart(); } @Override protected void onPause() { super.onPause(); } @Override protected void initData() { //设置数据源,适配器等等 mAdapter.setDatabases(mEventManger.findAll()); mRecyclerView.setAdapter(mAdapter); mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL)); } @Override protected void setListener() { mAdapter.setOnItemClickListener(mOnItemClickListener); mSearchView.setOnQueryTextListener(mQueryListener); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main_activity, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { //判断是点击了那个按钮,删除,添加 if (item.getItemId() == R.id.menu_add) { Intent intent = new Intent(); intent.setClass(this, EventDetailActivity.class); intent.putExtra(EventDetailActivity.EXTRA_IS_ADD_EVENT, true); startActivity(intent); } else if (item.getItemId() == R.id.menu_delete) { if (mAdapter.getIsDeleteMode()) { //删除数据 if (mAdapter.getSelectedEventIds().size() == 0) { ToastUtil.showToastShort(R.string.no_event_selected_msg); } else { int msg = mAdapter.getSelectedEventIds().size() == 1 ? R.string.delete_event_msg : R.string.delete_events_msg; AlertDialogUtil.showDialog(this, msg, mConfirmListener); } } else { mAdapter.setDeleteMode(true); } } return super.onOptionsItemSelected(item); } @Override public int getContentView() { return R.layout.activity_main; } private EventRecyclerViewAdapter.OnItemClickListener mOnItemClickListener = new EventRecyclerViewAdapter.OnItemClickListener() { @Override public void onItemClick(View view, int position) { if (!mAdapter.getIsDeleteMode()) { //跳屏,此时为查看详情,不是编辑状态 Intent intent = new Intent(); intent.setClass(MainActivity.this, EventDetailActivity.class); intent.putExtra(EventDetailActivity.EXTRA_IS_EDIT_EVENT, false); intent.putExtra(EventDetailActivity.EXTRA_EVENT_DATA, mAdapter.getDatabases().get(position)); startActivity(intent); } } @Override public void onItemLongClick(View view, int position) { ToastUtil.showToastShort("Long clicked"); mAdapter.setDeleteMode(true); } }; private DialogInterface.OnClickListener mConfirmListener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { mEventManger.setDeletedIds(mAdapter.getSelectedEventIds()); mEventManger.removeEvents(mBaseHandler, mEventManger.getDeletedIds()); } }; /** * 从编辑屏幕回来时调用该方法,做数据更新 */ @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); mAdapter.setDatabases(mEventManger.getEvents()); } private SearchView.OnQueryTextListener mQueryListener = new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { return false; } @Override public boolean onQueryTextChange(String newText) { //做本地查询 if (!StringUtil.isBlank(newText)) { List
events = new ArrayList<>(); for (Event event : mAdapter.getDatabases()) { if (event.getmTitle().contains(newText)) { events.add(event); } } mAdapter.setDatabases(events); } else { mAdapter.setDatabases(mEventManger.getEvents()); } return true; } }; /** * handler处理成功的回调函数 * @link com.jsbintask@gmail.com.memo.base.BaseHandler */ @Override public void handlerSuccess(Message msg) { ToastUtil.showToastShort(R.string.delete_successful); for (PendingIntent pendingIntent : buildIntent(mEventManger.getDeletedIds())) { mClockManager.cancelAlarm(pendingIntent); } mAdapter.setDatabases(mEventManger.findAll()); } /** * 处理失败的回调函数 */ @Override public void handlerFailed(MemoException e) { ToastUtil.showToastShort(R.string.delete_failed); mAdapter.setDeleteMode(false); } private List
buildIntent(List
ids) { List
pendingIntents = new ArrayList<>(); for (Integer id : ids) { Intent intent = new Intent(); intent.putExtra(ClockService.EXTRA_EVENT_ID, id); intent.setClass(this, ClockService.class); pendingIntents.add(PendingIntent.getService(this, 0x001, intent, PendingIntent.FLAG_UPDATE_CURRENT)); } return pendingIntents; }}复制代码

接着,编写个用于展示事件详情的EventDetailActivity:

public class EventDetailActivity extends BaseActivity {    public static final String EXTRA_IS_EDIT_EVENT = "extra.is.edit.event";    public static final String EXTRA_EVENT_DATA = "extra.event.data";    public static final String EXTRA_IS_ADD_EVENT = "extra.is.create.event";    //从主屏进来的操作是不是编辑操作    private boolean isEditEvent;    //从主屏进来的操作是不是添加操作    private boolean isAddEvent;    private EventManager mEventManager = EventManager.getInstance();    private ClockManager mClockManager = ClockManager.getInstance();    @BindView(R.id.ll_update_time)    LinearLayout llUpdateTime;    @BindView(R.id.ed_title)    EditText edTitle;    @BindView(R.id.tv_remind_time_picker)    EditText tvRemindTime;    @BindView(R.id.ed_content)    EditText edContent;    @BindView(R.id.tv_last_edit_time)    TextView tvUpdateTime;    @BindView(R.id.iv_back)    ImageView ivBack;    @BindView(R.id.tv_confirm)    TextView tvConfirm;    @BindView(R.id.iv_delete)    ImageView ivDelete;    @BindView(R.id.iv_edit)    ImageView ivEdit;    @BindView(R.id.chb_is_important)    CheckBox chbIsImportant;    @BindView(R.id.scroll_view)    ScrollView scrollView;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);    }    @Override    protected void setListener() {    }    @Override    protected void initView() {        isEditEvent = getIntent().getBooleanExtra(EXTRA_IS_EDIT_EVENT, false);        isAddEvent = getIntent().getBooleanExtra(EXTRA_IS_ADD_EVENT, false);        judgeOperate();    }    private void judgeOperate() {        //是否显示上方上次编辑时间        llUpdateTime.setVisibility(isAddEvent ? View.GONE : View.VISIBLE);        //是否能够编辑标题        setEditTextReadOnly(edTitle, !isEditEvent && !isAddEvent);        //是否能够编辑内容        setEditTextReadOnly(edContent, !isEditEvent && !isAddEvent);        //设置提醒时间不能手动输入        setEditTextReadOnly(tvRemindTime, true);        //设置提醒时间是否能够点击:弹出时间选择器        tvRemindTime.setClickable(isEditEvent || isAddEvent);        //设置右上角确定按钮是否可见        tvConfirm.setVisibility(isEditEvent || isAddEvent ? View.VISIBLE : View.GONE);        //设置右下角编辑按钮是否可见        ivEdit.setVisibility(!isEditEvent && !isAddEvent ? View.VISIBLE : View.GONE);        //设置左下角删除按钮是否可见        ivDelete.setVisibility(!isAddEvent ? View.VISIBLE : View.GONE);        //设置checkbox能不能点击        chbIsImportant.setClickable(isEditEvent || isAddEvent);    }    @Override    protected void initData() {        if (!isAddEvent) {            Event event = getIntent().getParcelableExtra(EXTRA_EVENT_DATA);            //填充值            tvUpdateTime.setText(event.getmUpdatedTime());            edTitle.setText(event.getmTitle());            edContent.setText(event.getmContent());            tvRemindTime.setText(event.getmRemindTime());            chbIsImportant.setChecked(event.getmIsImportant() == Constants.EventFlag.IMPORTANT);        }    }    @OnClick(R.id.iv_back)    public void backImageClick(View view) {        finish();    }    @OnClick(R.id.iv_delete)    public void deleteImageClick(View view) {        if (!isAddEvent) {            AlertDialogUtil.showDialog(this, R.string.delete_event_msg, new DialogInterface.OnClickListener() {                @Override                public void onClick(DialogInterface dialog, int which) {                    Event event = getIntent().getParcelableExtra(EventDetailActivity.EXTRA_EVENT_DATA);                    if (mEventManager.removeEvent(event.getmId())) {                        ToastUtil.showToastShort(R.string.delete_successful);                        mClockManager.cancelAlarm(buildIntent(event.getmId()));                        mEventManager.flushData();                        postToMainActivity();                    } else {                        ToastUtil.showToastShort(R.string.delete_failed);                    }                }            });        }    }    /**     * 回到主屏幕     */    private void postToMainActivity() {        Intent intent = new Intent();        intent.setClass(EventDetailActivity.this, MainActivity.class);        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);        startActivity(intent);        finish();    }    @Override    public int getContentView() {        return R.layout.activity_event_detail;    }    /**     * 弹出时间选择器,选择闹钟执行时间     * @param view     */    @OnClick(R.id.tv_remind_time_picker)    public void datePickClick(View view) {        if (isEditEvent || isAddEvent) {            final Calendar calendar = Calendar.getInstance();            DatePickerDialog dialog = new DatePickerDialog(this, new DatePickerDialog.OnDateSetListener() {                @Override                public void onDateSet(DatePicker view, final int year, final int month, final int dayOfMonth) {                    TimePickerDialog timePickerDialog = new TimePickerDialog(EventDetailActivity.this, new TimePickerDialog.OnTimeSetListener() {                        @Override                        public void onTimeSet(TimePicker view, int hourOfDay, int minute) {                            String time = year + "-" + StringUtil.getLocalMonth(month) + "-" + StringUtil.getMultiNumber(dayOfMonth) + " " + StringUtil.getMultiNumber(hourOfDay) + ":" + StringUtil.getMultiNumber(minute);                            tvRemindTime.setText(time);                        }                    }, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), false);                    timePickerDialog.show();                }            }, calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH));            dialog.getDatePicker().setMinDate(calendar.getTimeInMillis());            dialog.show();        }    }    @OnClick(R.id.iv_edit)    public void editImageClick(View view) {        if (!isEditEvent) {            ToastUtil.showToastShort(R.string.enter_edit_mode);            ivEdit.setVisibility(View.GONE);            isEditEvent = true;            judgeOperate();        }    }    @OnClick(R.id.tv_confirm)    public void confirmClick(View view) {        //更新        if (isEditEvent || isAddEvent) {            Event event = buildEvent();            //检查属性并且提醒            if (!mEventManager.checkEventField(event)) {                return;            }            if (mEventManager.saveOrUpdate(event)) {                if (isEditEvent) {                    ToastUtil.showToastShort(R.string.update_successful);                } else if (isAddEvent) {                    ToastUtil.showToastShort(R.string.create_successful);                    event.setmId(mEventManager.getLatestEventId());                }                //添加闹钟                mClockManager.addAlarm(buildIntent(event.getmId()), DateTimeUtil.str2Date(event.getmRemindTime()));                mEventManager.flushData();                postToMainActivity();            } else {                if (isEditEvent) {                    ToastUtil.showToastShort(R.string.update_failed);                } else if (isAddEvent) {                    ToastUtil.showToastShort(R.string.create_failed);                }            }        }    }    private PendingIntent buildIntent(int id) {        Intent intent = new Intent();        intent.putExtra(ClockReceiver.EXTRA_EVENT_ID, id);        intent.setClass(this, ClockService.class);        return PendingIntent.getService(this, 0x001, intent, PendingIntent.FLAG_UPDATE_CURRENT);    }    @OnClick(R.id.scroll_view)    public void scrollViewClick(View view) {        if (isAddEvent || isEditEvent) {            //打开软键盘            setEditTextReadOnly(edContent, false);        }    }    @NonNull    private Event buildEvent() {        Event event = new Event();        if (isEditEvent) {            event.setmId(((Event) getIntent().getParcelableExtra(EXTRA_EVENT_DATA)).getmId());            event.setmCreatedTime(((Event) getIntent().getParcelableExtra(EXTRA_EVENT_DATA)).getmCreatedTime());        }        event.setmRemindTime(tvRemindTime.getText().toString());        event.setmTitle(edTitle.getText().toString());        event.setmIsImportant(chbIsImportant.isChecked() ? Constants.EventFlag.IMPORTANT : Constants.EventFlag.NORMAL);        event.setmContent(edContent.getText().toString());        event.setmUpdatedTime(DateTimeUtil.dateToStr(new Date()));        return event;    }    private void setEditTextReadOnly(EditText editText, boolean readOnly) {        editText.setFocusable(!readOnly);        editText.setFocusableInTouchMode(!readOnly);        editText.setCursorVisible(!readOnly);        editText.setTextColor(getColor(readOnly ? R.color.gray3 : R.color.black));    }}复制代码

最后,再写一个Activity用于展示闹铃提醒,ClockActivity:

public class ClockActivity extends BaseActivity {    private static final String TAG = "ClockActivity";    public static final String EXTRA_CLOCK_EVENT = "clock.event";    //闹铃    private MediaPlayer mediaPlayer;    //震动    private Vibrator mVibrator;    private EventManager mEventManger = EventManager.getInstance();    private Event event;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);    }    @Override    protected void setListener() {    }    @Override    protected void initView() {    }    private void clock() {        mediaPlayer.start();        long[] pattern = new long[]{
1500, 1000}; mVibrator.vibrate(pattern, 0); //获取自定义布局 View inflate = LayoutInflater.from(this).inflate(R.layout.dialog_alarm_layout, null); TextView textView = inflate.findViewById(R.id.tv_event); textView.setText(String.format(getString(R.string.clock_event_msg_template), event.getmTitle())); Button btnConfirm = inflate.findViewById(R.id.btn_confirm); final AlertDialog alertDialog = AlertDialogUtil.showDialog(this, inflate); btnConfirm.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mediaPlayer.stop(); mVibrator.cancel(); alertDialog.dismiss(); finish(); } }); alertDialog.show(); } @Override protected void onStart() { super.onStart(); clock(); } @Override protected void initData() { mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.clock); mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); Intent intent = getIntent(); event = getIntent().getParcelableExtra(ClockService.EXTRA_EVENT); if (event == null) { finish(); } } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); clock(); } @Override public int getContentView() { return R.layout.activity_clock; }}复制代码

系统界面,服务注册清单

复制代码

效果展示

闹铃提醒:

批量删除:
新增和编辑:
搜索:

关注我!这里只有干货!

你可能感兴趣的文章
笔记本触摸板滑动事件导致连滑的解决方式
查看>>
Android推荐常用的31个库
查看>>
Runtime 学习:消息传递
查看>>
你了解BFC吗?
查看>>
深入V8引擎-默认Platform之mac篇(1)
查看>>
linux ssh tunnel使用
查看>>
十、详解FFplay音视频同步
查看>>
自定义元素探秘及构建可复用组件最佳实践
查看>>
小猿圈Python教程之全面解析@property的使用
查看>>
mpvue开发小程序所遇问题及h5转化方案
查看>>
View和Activity的生命周期
查看>>
解决PHP下载大文件失败,并限制下载速度
查看>>
java B2B2C Springcloud电子商城系统—Feign实例
查看>>
java B2B2C Springcloud多租户电子商城系统 (五)springboot整合 beatlsql
查看>>
Throwable是一个怎样的类?
查看>>
Python基础(一)
查看>>
三条代码 搞定 python 生成验证码
查看>>
我的友情链接
查看>>
我的友情链接
查看>>
无线和有线路由哪种性能更好
查看>>