利用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.点击标题或阅读全文链接,进入博客阅 ...
随机推荐
- 如果出现isapi和CGI限制的时候
将isapi和CGI中对应的不允许改为允许即可
- [转]MFC中UpdateData()函数的使用
当你使用了ClassWizard建立了控件和变量之间的联系后:当你修改了变量的值,而希望对话框控件更新显示,就应该在修改变量后调用 UpdateData(FALSE):如果你希望知道用户在对话框中到底 ...
- 使用appium模拟用户发送短信
一段简单粗糙的代码.主要是实现的功能是模拟用户发送短信的功能. python版本3.5.2 appium版本1.4.16.1 from appium import webdriver desired_ ...
- Kafka Quick Start
1.Download > tar -xzf kafka_2.11-0.10.0.0.tgz> cd kafka_2.11-0.10.0.0 2.启动zookeeper服务 Kafka使用的 ...
- EXTJS 密码确认与验证
extjs 框架是一个非常优秀的前端框架,提供了丰富的功能与炫丽的界面展示,在用 extjs 创建表单时,特别是在注册或修改密码的时候,要对密码进行确认,这里就密码确认一致性验证和大家分享自己的心得与 ...
- html中button的type属性
接触web开发不久,今天遇到了一个问题,点击button按钮,浏览器没有反应,尝试了自己可以想到的所有办法,还是无果.只得请教他人,才发现是button的type属性搞得怪,原来: ...
- c# 将页面导出到word(含图片及控件)
/// <summary> /// 创建word /// <param name="filePath">文件路径 </param> /// &l ...
- 多XML追加操作
假设要统计当前系统中所有的试卷进行分析,试卷是以XML格式存储的,所有这就需要将所有零散的XML文件整合起来,处理成一个完整的XML文件,进行分析, 下面是简单额处理方法: 当前XML文件格式: &l ...
- ios如何获取位置权限
获取当前位置需要改plist文件 在plist文件加入 NSLocationWhenInUseUsageDescription 字段 /** 初始化一个管理器对象 */ locationMan ...
- 讲解DLL内容的比较详细的站点
1.通过 Visual Studio 2008 用C语言创建和调用DLL : http://blog.chinaunix.net/uid-631975-id-116622.html 2.DLL(Dyn ...