之前做了个简单的知乎日报的客户端,在这的基础上再加上了便签的功能,使用LitePal操作数据库。
效果
配置和创建数据库
首先需要添加依赖
compile 'org.litepal.android:core:1.4.1'
在这个功能中还添加了
compile 'com.hanks.animatecheckbox:library:0.1'
compile 'com.android.support:multidex:1.0.0'
animatecheckbox:就是一个checkbox,不过好看点。。
multidex:导入第三方项目后,导致重复,添加这个依赖可以进行分包
使用方法http://stackoverflow.com/questions/27377080/after-update-of-as-to-1-0-getting-method-id-not-in-0-0xffff-65536-error-i
需要设置AndroidManifest.xml里的application
android:name="android.support.multidex.MultiDexApplication"
但是问题来了,litePal需要将application设置为
android:name="org.litepal.LitePalApplication"
但是java不能多继承啊..
看了下LitePalFramework/LitePal ,发现可以定义自己的MyApplication
public class MyApplication extends android.support.multidex.MultiDexApplication {
@Override
public void onCreate() {
super.onCreate();
LitePal.initialize(this);
}
}
android:name=".app.MyApplication"
再创建一个assets目录,在目录下建一个litepal.xml
<litepal>
<dbname value="oneday"></dbname>
<version value="2" />
<list>
<mapping class="com.example.linsawako.zhihu.bean.Schedule"/>
</list>
</litepal>
LitePal是对象关系映射的模式,将面向对象的语言和面向关系的数据库之间建立一种映射关系。
<mapping>
用来声明要配置的映射模式类,需要完整的类名。
升级数据库的时候,只需要更改version的值。
只需要任意的一次数据库操作,这个数据库就会自动创建出来。
配置的工作就到这。
具体实现
便笺的bean类
public class Schedule extends DataSupport implements Serializable{
private int id;
private Date date;
private String content;
private Boolean finish;
public int getId() {
return id;
}
public Date getDate() {
return date;
}
public String getContent() {
return content;
}
public Boolean getFinish() {
return finish;
}
public void setContent(String content) {
this.content = content;
}
public void setDate(Date date) {
this.date = date;
}
public void setFinish(Boolean finish) {
this.finish = finish;
}
public void setId(int id) {
this.id = id;
}
}
模型类需继承DataSupport。implements Serializable是因为需要在使用intent调转时,可以传递整个对象。关于序列化可以看下我的另外一篇文章 java-Serializable 序列化
RecyclerView的Adapter
public class ScheduleAdapter extends RecyclerView.Adapter<ScheduleAdapter.ViewHolder> {
public final static int NAME = 1;//用来判断是哪个intent跳转的
private List<Schedule> list;
private Context mContext;
private int scheduleId;
public ScheduleAdapter(List<Schedule> list) {
this.list = list;
}
class ViewHolder extends RecyclerView.ViewHolder {
CardView cardView;
AnimateCheckBox animateCheckBox;
TextView scheduleText;
TextView date;
public ViewHolder(View itemView) {
super(itemView);
cardView = (CardView) itemView.findViewById(R.id.schedule_cardview);
animateCheckBox = (AnimateCheckBox) itemView.findViewById(R.id.schedule_checkbox);
scheduleText = (TextView) itemView.findViewById(R.id.schedule_text);
date = (TextView) itemView.findViewById(R.id.schedule_date);
}
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (mContext == null) {
mContext = parent.getContext();
}
View view = LayoutInflater.from(mContext).inflate(R.layout.schedule_item, parent, false);
final ViewHolder viewHolder = new ViewHolder(view);
//点击后跳转,数据可更改
viewHolder.cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int position = viewHolder.getAdapterPosition();
Schedule schedule = list.get(position);
Intent intent = new Intent(mContext, AddScheduleActivity.class);
intent.putExtra("ActivityName", NAME);
intent.putExtra("Content", schedule);
mContext.startActivity(intent);
}
});
//设置checkBox点击后的数据存储
viewHolder.animateCheckBox.setOnCheckedChangeListener(new AnimateCheckBox.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(View buttonView, boolean isChecked) {
int position = viewHolder.getAdapterPosition();
Schedule schedule = list.get(position);
schedule.setFinish(viewHolder.animateCheckBox.isChecked());
schedule.update(schedule.getId());
}
});
return viewHolder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Schedule schedule = list.get(position);
holder.date.setText(new SimpleDateFormat("yyyy/MM/dd").format(schedule.getDate()));
holder.scheduleText.setText(schedule.getContent());
holder.animateCheckBox.setChecked(schedule.getFinish());
}
@Override
public int getItemCount() {
return list.size();
}
}
这里涉及了使用LitePal更新数据,
Schedule schedule = list.get(position);
schedule.setFinish(viewHolder.animateCheckBox.isChecked());
schedule.update(schedule.getId());
更新数据的另一个方法,示例
albumToUpdate.updateAll("name = ?", "album");
括号中相当于是where的内容。
ScheduleFragment显示便签的瀑布流
public class ScheduleFragment extends Fragment {
private static final String TAG = "ScheduleFragment";
public final static int NAME = 0;
private RecyclerView recyclerView;
private List<Schedule> scheduleList;
private ScheduleAdapter mAdapter;
PopOptionUtil mPop;//用于长按时弹出删除提示框
public ScheduleFragment() {
}
@Override
public void onResume() {
super.onResume();
scheduleList.clear(); //去掉之前的数据
List<Schedule> newList = DataSupport.order("date desc").find(Schedule.class);
scheduleList.addAll(newList);//注意要将数据复制过来,而不是直接使用,不然无法更新数据
mAdapter.notifyDataSetChanged();
Log.d(TAG, "onResume: ");
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d(TAG, "onCreateView: ");
View view = inflater.inflate(R.layout.fragment_schedule, container, false);
//fab点击后跳转到添加便签的界面
FloatingActionButton fab = (FloatingActionButton) view.findViewById(R.id.schedule_fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.d(TAG, "onClick: intent");
Intent intent = new Intent(getContext(), AddScheduleActivity.class);
intent.putExtra("ActivityName", NAME);
startActivity(intent);
}
});
mPop = new PopOptionUtil(getContext());
scheduleList = DataSupport.order("date desc").find(Schedule.class);
mAdapter = new ScheduleAdapter(scheduleList);
recyclerView = (RecyclerView) view.findViewById(R.id.schedule_recyclerview);
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(mAdapter);
//设置recyclerview的长按事件
recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(getActivity(), recyclerView, new RecyclerItemClickListener.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
// ...
}
@Override
public void onItemLongClick(View view, final int position) {
Log.d(TAG, "onItemLongClick: ");
mPop.setOnPopClickEvent(new PopClickEvent() {
@Override
public void onNextClick() {
//删除item
Log.d(TAG, "onNextClick: delete");
int id = scheduleList.get(position).getId();
Log.d(TAG, "onNextClick: position:" + position + " id: " + id);
deleteData(id);
scheduleList.remove(position);
mAdapter.notifyItemRemoved(position);
mAdapter.notifyItemRangeChanged(0,scheduleList.size());//这个需要设置,因为删除后item的position会改变
mPop.dismiss();
}
});
mPop.show(view);
}
}));
return view;
}
//litepal删除数据
public void deleteData(int id){
DataSupport.deleteAll(Schedule.class, "id = ?", String.valueOf(id));
Log.d(TAG, "deleteData: " + id);
}
}
关于PopOptionUtil参考了这篇文章仿QQ长按弹出功能菜单 ,就不把具体代码贴上来了
recyclerview的长按事件,参考Android RecyclerView点击事件与长按事件
AddScheduleActivity
public class AddScheduleActivity extends AppCompatActivity {
private static final String TAG = "AddScheduleActivity";
private int activityName;
private int scheduleID;
@Bind(R.id.addSchedule_editText)
EditText contentText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_schedule);
ButterKnife.bind(this);
Toolbar toolbar = (Toolbar) findViewById(R.id.edit_toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);//让导航按钮显示出来,设置为返回键
}
Intent intent = getIntent();
activityName = intent.getIntExtra("ActivityName", 0);//判断是哪个intent跳转的
//修改便签的事件
if (activityName == ScheduleAdapter.NAME){
Schedule schedule = (Schedule) intent.getSerializableExtra("Content");
contentText.setText(schedule.getContent());//填入已有的数据
scheduleID = schedule.getId();
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home://返回
finish();
break;
case R.id.save://存储键
Log.d(TAG, "onOptionsItemSelected: savedata");
if (activityName == ScheduleAdapter.NAME) {//如果是已有的数据就更新,否则存储
updateDate();
} else if (activityName == ScheduleFragment.NAME) {
saveDate();
}
finish();
break;
}
return true;
}
//使用litepal更新数据
public void updateDate() {
Schedule schedule = new Schedule();
schedule.setContent(contentText.getText().toString());
schedule.setDate(new Date());
schedule.update(scheduleID);
}
//使用litepal存储数据
public void saveDate(){
Schedule schedule = new Schedule();
schedule.setDate(new Date());//存入的时间
schedule.setContent(contentText.getText().toString());
schedule.setFinish(false);
schedule.save();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_schedule, menu);
return true;
}
}
差不多就这样,GitHub:https://github.com/linsawako/oneDay
说下感想吧,,单单搬砖还是无聊的orz,玩了一寒假,也快开学了,如往常一样,写的计划没一个做到的(:з」∠)…明天起好好打基础