学了极客学院一个开发记事本的课程,利用自己对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记下来吧.
随机推荐
-
UESTC 30 最短路,floyd,水
最短路 Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) Submit Statu ...
-
Jsp技术总结
这节我们总结一下Jsp的相关技术. 1. 什么是JSP JSP即Java Server Pages,它和servlet技术一样,都是sun公司定义的一种用于开发动态web资源的技术.该技术的最大特点在 ...
-
iOS-定时器
一.定时器的作用 在软件开发过程中,我们常常需要在某个时间后执行某个方法,或者是按照某个周期一直执行某个方法.在这个时候,我们就需要用到定时器. 二.定时器的种类 大概有三种方法:NSTimer.CA ...
-
机械硬盘与SSD固态硬盘性能的深度
从7200转硬盘升级到10000转的迅猛龙,那叫量变.从10000转的迅猛龙升级到SSD,这个叫质变.2者的差距是有些地方相当大,而有些却很接近,主要是难比较. 经常听到有人说:我买2个黑盘组RAID ...
-
Tomcat启动时卡在“INFO: Deploying web application directory ”
今天在linux上的tomcat部署一个网站时,在刚启动tomcat的时候提示启动成功,然后也能访问成功. 可是第二次启动时虽然没有报错,但无法访问tomcat,查看了catalina.out日志,发 ...
-
FFmpeg安装(windows环境)
♣FFmpeg是什么? ♣FFmpeg组成 ♣下载工具 ♣安装FFmpeg ♣应用到j2ee项目 前言:学习视频编码,一定要知道雷霄骅(leixiaohua1020)的专栏 ,伟大的程序员,26岁去世 ...
-
线程-join();
一.join()方法,官方描述 waits for this thread to die 等待当前线程死亡: 源码: //无参,默认调用join(0) public final void join ...
-
[引]ionic framework 相关网站
http://www.w3uu.com/intro/mobile/ionic2-tutorial.html ionic2中文教程 https://beta.ionicframework.com/do ...
-
centos重启报错Umounting file systems:umount:/opt:device is busy
系统重启报错: Umounting file systems:umount:/opt:device is busy 只能硬关机,回想一下最近刚安装了nod32 for linux x64的杀毒软件,开 ...
-
CSS快速入门-实用技巧
1.整体布局 大部分的布局都是由三部分组成,header.body.footer. 代码布局:写三个div <!DOCTYPE html> <html lang="en&q ...