利用MVC编程模式-开发一个简易记事本app
学了极客学院一个开发记事本的课程,利用自己对MVC编程模式的简单理解重写了一遍该app。
github地址:https://github.com/morningsky/MyNote
MVC即,模型(model)-视图(view)-控制器(controller),有效的实现了数据-业务逻辑-视图显示的代码分离,使得加入新功能时不需要重新编写业务逻辑,大大提高了代码的可维护性。
在这个案列中,一开始只是开发了添加文字内容的记事功能,添加图片功能时在activity文件中写入imageview的逻辑 在数据库中加入图片路径数据 在视图中加一个imageview的。后期若再添加视频功能可参照之前添加图片的操作快速实现app的升级。整个代码编写过程脉络清晰,加上Android Studio的帅气主题,开发过程感觉极好。
下面是整个app的开发流程:
/*步骤:
1.model构建
1.1创建数据库 NoteDB类
1.2创建自定义的adapter MyAdapter类
1.2.1构造函数
1.2.2复写4个子类方法 注意getView方法2.创建视图
2.1布局主界面 两个按钮 一个listview activity_main.xml
2.2 listview每一条数据的视图格式 图片imageview 内容textview 时间textview cell.xml
2.3添加内容界面 imageview editext 两个Button addcontent.xml
2.4创建详情页视图 与addcontent视图相似 将Editext转换为Textview Button的内容由返回变成删除 incontent.xml3.逻辑实现
MainActivity:
3.1初始化主界面布局 定义initView方法 给按钮设置监听
3.7在MainActivity实例化一个SQLiteDatabase 获取读取权限 用于加载listview的内容
3.8添加查询数据方法selectDB 并在该方法中加载MyAdapter
AddContent:
3.2创建添加内容界面的activity 并在AndroidManifest文件中注册该activity 两个activity添加固定竖屏参数
3.3初始化AddContent界面布局 定义initView方法 给按钮设置监听 实例化SQLiteDatabase 获取写入数据权限
3.4添加addDB方法获取内容 时间并写入数据库
3.5添加getTime方法获取系统当前时间
3.6为按钮添加事件
3.9增加根据添加文字还是图文加载不同界面的initView逻辑
4.0添加Intent调用系统相机 实例化一个File存放照片路径
4.1复写onActivityResult来查看照片效果
4.2add函数添加图片路径MyAdapter:
4.3添加查看缩略图函数getImageThumbnail listview中显示
4.5添加用来查询的String path 储存地址InContent:
4.6添加详情页Activity 并注册
4.7给listview添加监听事件 跳转到详情页 并传入部分数据
4.8根据图文还是文字加载不同视图 显示文字 图片信息
4.9实例化一个SQLiteDatabase 获取写入数据权限 用来删除数据
5.0添加删除数据方法delDB 给按钮加上方法
*/
model层:
NoteDB.java 创建了一个数据库 用来存放记事内容 记事时间 图片路径
package com.bluesky.mynote; import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper; /**
* Created by 清晨 on 2015/5/6.
*/
public class NoteDB extends SQLiteOpenHelper { public static final String TABLE_NAME="notes";//表名
public static final String CONTENT="content";//内容
public static final String ID="id"; //标识每一条数据
public static final String TIME="time"; //存放添加数据时的时间
public static final String PATH="path"; //路径,用来存放照片路径 //构造函数参数保留一个Content即可
public NoteDB(Context context) {
super(context, "notes", null, 1);
} //注意属性内的空格 " TEXT NOT NULL,"第一个引号后的空格不能省略 否则名称会变为contentTEXT
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE_NAME + " ("
+ ID+ " INTEGER PRIMARY KEY AUTOINCREMENT,"
+ CONTENT+" TEXT NOT NULL,"
+ PATH +" TEXT NOT NULL,"
+ TIME +" TEXT NOT NULL)");
} //不需要更新
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { }
}
MyAdapter.java 用来设定主界面listview的内容格式
package com.bluesky.mynote; import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.ThumbnailUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView; /**
* Created by 清晨 on 2015/5/7.
*/
public class MyAdapter extends BaseAdapter {
private Context mContext;
private Cursor mCursor;
private LinearLayout layout; public MyAdapter(Context context,Cursor cursor){
mContext=context;
mCursor=cursor;
}
@Override
public int getCount() {
return mCursor.getCount();
} @Override
public Object getItem(int position) {
return mCursor.getPosition();
} @Override
public long getItemId(int position) {
return position;
} @Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater=LayoutInflater.from(mContext);//加载视图权限
layout= (LinearLayout) inflater.inflate(R.layout.cell,null);//加载视图
//初始化控件
TextView content_tv= (TextView) layout.findViewById(R.id.list_content);
TextView time_tv= (TextView) layout.findViewById(R.id.list_time);
ImageView img_iv= (ImageView) layout.findViewById(R.id.list_img);
//查询mCursor 用String获取查询内容
mCursor.moveToPosition(position);
String content=mCursor.getString(mCursor.getColumnIndex("content"));
String time=mCursor.getString(mCursor.getColumnIndex("time"));
String url=mCursor.getString(mCursor.getColumnIndex("path"));
content_tv.setText(content);
time_tv.setText(time);
img_iv.setImageBitmap(getImageThumbnail(url,200,200));
return layout;
} //获取缩略图
public Bitmap getImageThumbnail(String uri,int width,int height){
Bitmap bitmap=null;
BitmapFactory.Options options=new BitmapFactory.Options();
options.inJustDecodeBounds=true;
bitmap=BitmapFactory.decodeFile(uri,options);
options.inJustDecodeBounds=false;
int beWidth=options.outWidth/width;
int beHeight=options.outHeight/height;
int be=1;
//防止图片超出过大或过小不予缩小
if(beWidth<beHeight){
be=beWidth;
}else {
be=beHeight;
}
if(be<=0){
be=1;
}
options.inSampleSize=be;
bitmap=BitmapFactory.decodeFile(uri,options);
bitmap=ThumbnailUtils.extractThumbnail(bitmap,width,height,ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
return bitmap;
}
}
视图层(View):
分别是主界面 activity_main.xml 添加内容addcontent.xml 内容详情页incontent.xml
内容详情页与添加内容界面 基本相似 所以可实现代码的简单修改 将编辑框改为文本框 再修改相应ID即可
接下来是核心部分
控制器(Controler):
主activity:
package com.bluesky.mynote;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView; public class MainActivity extends ActionBarActivity implements View.OnClickListener {
private Button text_btn, img_btn;
private ListView lv;
private Intent i;
private MyAdapter adapter;
private NoteDB noteDB;
private SQLiteDatabase dbReader;
private Cursor cursor; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
//给按钮加入监听事件
text_btn.setOnClickListener(this);
img_btn.setOnClickListener(this);
noteDB = new NoteDB(this);
//获取读取权限 用于加载listview的内容
dbReader = noteDB.getReadableDatabase();
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
cursor.moveToPosition(position);//游标挪到了position的位置上
Intent i=new Intent(MainActivity.this,InContent.class);
i.putExtra(NoteDB.ID,cursor.getInt(cursor.getColumnIndex(NoteDB.ID)));//以便根据ID删除数据
i.putExtra(NoteDB.CONTENT,cursor.getString(cursor.getColumnIndex(NoteDB.CONTENT)));
i.putExtra(NoteDB.TIME,cursor.getString(cursor.getColumnIndex(NoteDB.TIME)));
i.putExtra(NoteDB.PATH,cursor.getString(cursor.getColumnIndex(NoteDB.PATH)));
startActivity(i);
}
}); } //初始化控件
public void initView() {
lv = (ListView) findViewById(R.id.list);
text_btn = (Button) findViewById(R.id.text);
img_btn = (Button) findViewById(R.id.image);
} //查询数据
public void selectDB() {
cursor = dbReader.query(NoteDB.TABLE_NAME,null,null,null,null,null,null,null);
adapter = new MyAdapter(this,cursor);
lv.setAdapter(adapter);
} @Override
public void onClick(View v) {
i = new Intent(this, AddContent.class);
switch (v.getId()) {
case R.id.text:
i.putExtra("flag", "1");
startActivity(i);
break;
case R.id.image:
i.putExtra("flag", "2");
startActivity(i);
break;
}
} @Override
protected void onResume() {
super.onResume();
selectDB();
}
}
添加内容 activity
package com.bluesky.mynote; import android.app.Activity;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.PersistableBundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.VideoView; import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date; /**
* Created by 清晨 on 2015/5/6.
*/
public class AddContent extends Activity implements View.OnClickListener {
private NoteDB noteDB;
private SQLiteDatabase dbWriter;
private String flag; //接受从mainactivity传来的标识 用于判定加载不同的添加内容界面(图文或者纯文字)
private EditText editText;
private Button save_btn,cancel_btn;
private ImageView c_img;
private File imgfile;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.addcontent);
flag=getIntent().getStringExtra("flag");
initView();
save_btn.setOnClickListener(this);
cancel_btn.setOnClickListener(this);
noteDB=new NoteDB(this);
dbWriter=noteDB.getWritableDatabase();//获取写入数据库权限
} //初始化控件
public void initView(){
editText= (EditText) findViewById(R.id.ettext);
save_btn= (Button) findViewById(R.id.save);
cancel_btn= (Button) findViewById(R.id.cancel);
c_img= (ImageView) findViewById(R.id.c_img);
if(flag.equals("1")){
c_img.setVisibility(View.GONE);//隐藏imageview
}
if(flag.equals("2")){
c_img.setVisibility(View.VISIBLE);//显示imageview
//启动系统相机拍照
Intent getImg=new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//图片是放在存储卡中 路径存在数据库中 以时间命名图片 避免重名
imgfile=new File(Environment.getExternalStorageDirectory()
.getAbsolutePath()+"/"+getTime()+".jpg");
getImg.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(imgfile));
startActivityForResult(getImg,1);//便于立即查看效果 }
} //获取内容并写入数据库
public void addDB(){
ContentValues cv=new ContentValues();
cv.put(NoteDB.CONTENT,editText.getText().toString());
cv.put(NoteDB.TIME,getTime());
cv.put(NoteDB.PATH,imgfile + "");
dbWriter.insert(NoteDB.TABLE_NAME,null,cv);
} //获取系统当前时间
public String getTime(){
SimpleDateFormat format=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
Date curDate=new Date();
String str=format.format(curDate);
return str;
} @Override
public void onClick(View v) {
switch (v.getId()){
case R.id.save:
addDB();
finish();
break;
case R.id.cancel:
finish();
break; } } //预览显示拍摄内容
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode==1){
Bitmap bitmap= BitmapFactory.decodeFile(imgfile.getAbsolutePath());
c_img.setImageBitmap(bitmap);
}
}
}
内容详情页Activity
package com.bluesky.mynote; import android.app.Activity;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView; /**
* Created by 清晨 on 2015/5/8.
*/
public class InContent extends Activity implements View.OnClickListener {
private Button del_btn;
private Button back_btn;
private ImageView in_img;
private TextView in_tv;
private NoteDB noteDB;
private SQLiteDatabase dbWriter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.incontent);
initView();
noteDB= new NoteDB(this);
dbWriter=noteDB.getWritableDatabase();
del_btn.setOnClickListener(this);
back_btn.setOnClickListener(this);
//根据记事方式加载不同视图
if(getIntent().getStringExtra(NoteDB.PATH).equals("null")){
in_img.setVisibility(View.GONE);
}else {
in_img.setVisibility(View.VISIBLE);
}
//显示文字
in_tv.setText(getIntent().getStringExtra(NoteDB.CONTENT));
//显示图片
Bitmap bitmap= BitmapFactory.decodeFile(getIntent().getStringExtra(NoteDB.PATH));
in_img.setImageBitmap(bitmap);
} public void initView(){
del_btn= (Button) findViewById(R.id.delete);
back_btn= (Button) findViewById(R.id.back);
in_img= (ImageView) findViewById(R.id.in_img);
in_tv= (TextView) findViewById(R.id.in_tv);
} @Override
public void onClick(View v) {
switch (v.getId()){
case R.id.delete:
delDB();
finish();
break;
case R.id.back:
finish();
break;
}
}
//删除数据
public void delDB(){
dbWriter.delete(NoteDB.TABLE_NAME,"id="+getIntent()
.getIntExtra(NoteDB.ID,0),null);
}
}
新人一枚,初学安卓,也初次尝试着写博客,暂且把这一路的code time记下来吧.
利用MVC编程模式-开发一个简易记事本app的更多相关文章
- MVC编程模式
MVC编程模式 MVC 是一种使用 MVC(Model View Controller 模型-视图-控制器)设计创建 Web 应用程序的模式: Model(模型)表示应用程序核心(比如数据库记录列表) ...
- 利用JSP编程技术实现一个简单的购物车程序
实验二 JSP编程 一.实验目的1. 掌握JSP指令的使用方法:2. 掌握JSP动作的使用方法:3. 掌握JSP内置对象的使用方法:4. 掌握JavaBean的编程技术及使用方法:5. 掌握JSP ...
- 使用Phalcon框架开发一个简易的博客系统
使用Phalcon PHP框架开发一个简易的博客系统(类似于CMS) 最近在做Phalcon(Phalcon在英文中指的是鸟类中飞得最快的那一个物种,由于是高性能框架,借用了这个词)相关的项目,由于刚 ...
- android开发学习---开发一个简易的短信发送器
一.需求: 开发一个简易的短信发送器,输入:对方手机号码,短信内容,点击发送按钮,短信发送成功,对方手机成功收到短信. 其中要求短信内容过长时可以自动拆分,长度英文是160个英文,中文是70个,中英混 ...
- jQuery 开发一个简易插件
jQuery 开发一个简易插件 //主要内容 $.changeCss = function(options){ var defaults = { color:'blue', ele:'text', f ...
- 移动跨平台开发框架Ionic开发一个新闻阅读APP
移动跨平台开发框架Ionic开发一个新闻阅读APP 前言 这是一个系列文章,从环境搭建开始讲解,包括网络数据请求,将持续更新到项目完结.实战开发中遇到的各种问题的解决方案,也都将毫无保留的分享给大家. ...
- ASP.NET没有魔法——ASP.NET MVC使用Area开发一个管理模块
之前的My Blog提供了列表的展示和文章显示功能,但是所有数据仍然只能通过数据库录入,为了完成最初的角色“作者”的用例,本章将介绍如何使用“Area”实现My Blog的管理功能. 根据功能分离代码 ...
- 利用阿里云如何开发一款直播app?
在开发的过程中应该注意些什么?下面让小编告诉你: 随着互联网的发展,越来越多的人已经加入互联网的行列.而且很多的人也开始直播,和众多的网友分享自己身边事情.互联网还在加速发展,从PC互联网,到移动互联 ...
- 如何用django开发一个简易个人Blog
功能概要:(目前已实现功能) 公共展示部分: 1.网站首页展示已发布的博客记录,包括名称.摘要信息.发布日期.阅读量及评论数. 2.首页文章列表可按照分类筛选. 3.点击标题或阅读全文链接,进入博客阅 ...
随机推荐
- sqlite报错OutOfMemory
如 java.sql.SQLException: out of memory at org.sqlite.DB.throwex(DB.java:252) at org.sqlite.NestedDB. ...
- HttpClient + ASP.NET Web API, WCF之外的另一个选择
WCF的野心造成了它的庞大复杂,HTTP的单纯造就了它的简单优美.为了实现分布式Web应用,我们不得不将两者凑合在一起 —— WCF服务以HTTP绑定宿主于IIS. 于是有了让人晕头转向的配置.让人郁 ...
- [工具] 如何利用Notepad++去除重复行
问题: 需要去除重复数据, 例如: 解决方案: 1. 打开notepad++: 2. 如果没有找到"TextFx" 选项, 需要先安装该插件. 依次打开"插件" ...
- win8或win8.1修改注册表失败的原因
win8 and win8.1 modify the registry need compiled to be different versions according to the os bits.
- socket学习笔记——并发服务器与I/O程序分割客户端
client.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <u ...
- Microsoft Visual C++ 2010(86) Redistributable不能安装完美解决
见http://jingyan.baidu.com/article/9c69d48f41aa6313c9024ebe.html 1. 去mircosoft下载安装包(vcredist_x64.exe) ...
- c语言描述简单的线性表,获取元素,删除元素,
//定义线性表 #define MAXSIZE 20 typedef int ElemType; typedef struct { ElemType data[MAXSIZE]; //这是数组的长度, ...
- 学习总结 java Iterator迭代器练习
package com.hanqi.jh; import java.util.*; public class Text3 { public static void main(String[] args ...
- windows异常调用顺序
(一) 发生异常时系统的处理顺序(by Jeremy Gordon, Hume): 1.系统首先判断异常是否应发送给目标程序的异常处理例程,如果决定应该发送,并且目标程序正在被调试,则系统 挂 ...
- 图解CISCO 3550忘记密码解决方法
图解CISCO3550忘记密码解决方法 Cisco网络设备密码忘记怎么初始出厂默认值?这时网友常常会提出的问题,怎么解决,有人说啦,去百度去谷歌一下不就行啦,然而这对初学者任是个挑战,虽然步骤只有简单 ...