学了极客学院一个开发记事本的课程,利用自己对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.xml
3.逻辑实现 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 创建了一个数据库 用来存放记事内容 记事时间 图片路径
1 package com.bluesky.mynote; 2 3 import android.content.Context; 4 import android.database.sqlite.SQLiteDatabase; 5 import android.database.sqlite.SQLiteOpenHelper; 6 7 /** 8 * Created by 清晨 on 2015/5/6. 9 */10 public class NoteDB extends SQLiteOpenHelper {11 12 public static final String TABLE_NAME="notes";//表名13 public static final String CONTENT="content";//内容14 public static final String ID="id"; //标识每一条数据15 public static final String TIME="time"; //存放添加数据时的时间16 public static final String PATH="path"; //路径,用来存放照片路径17 18 //构造函数参数保留一个Content即可19 public NoteDB(Context context) {20 super(context, "notes", null, 1);21 }22 23 //注意属性内的空格 " TEXT NOT NULL,"第一个引号后的空格不能省略 否则名称会变为contentTEXT24 @Override25 public void onCreate(SQLiteDatabase db) {26 db.execSQL("CREATE TABLE " + TABLE_NAME + " ("27 + ID+ " INTEGER PRIMARY KEY AUTOINCREMENT,"28 + CONTENT+" TEXT NOT NULL,"29 + PATH +" TEXT NOT NULL,"30 + TIME +" TEXT NOT NULL)");31 }32 33 //不需要更新34 @Override35 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {36 37 }38 }
MyAdapter.java 用来设定主界面listview的内容格式
1 package com.bluesky.mynote; 2 3 import android.content.Context; 4 import android.database.Cursor; 5 import android.graphics.Bitmap; 6 import android.graphics.BitmapFactory; 7 import android.media.ThumbnailUtils; 8 import android.view.LayoutInflater; 9 import android.view.View;10 import android.view.ViewGroup;11 import android.widget.BaseAdapter;12 import android.widget.ImageView;13 import android.widget.LinearLayout;14 import android.widget.TextView;15 16 /**17 * Created by 清晨 on 2015/5/7.18 */19 public class MyAdapter extends BaseAdapter {20 private Context mContext;21 private Cursor mCursor;22 private LinearLayout layout;23 24 public MyAdapter(Context context,Cursor cursor){25 mContext=context;26 mCursor=cursor;27 }28 @Override29 public int getCount() {30 return mCursor.getCount();31 }32 33 @Override34 public Object getItem(int position) {35 return mCursor.getPosition();36 }37 38 @Override39 public long getItemId(int position) {40 return position;41 }42 43 @Override44 public View getView(int position, View convertView, ViewGroup parent) {45 LayoutInflater inflater=LayoutInflater.from(mContext);//加载视图权限46 layout= (LinearLayout) inflater.inflate(R.layout.cell,null);//加载视图47 //初始化控件48 TextView content_tv= (TextView) layout.findViewById(R.id.list_content);49 TextView time_tv= (TextView) layout.findViewById(R.id.list_time);50 ImageView img_iv= (ImageView) layout.findViewById(R.id.list_img);51 //查询mCursor 用String获取查询内容52 mCursor.moveToPosition(position);53 String content=mCursor.getString(mCursor.getColumnIndex("content"));54 String time=mCursor.getString(mCursor.getColumnIndex("time"));55 String url=mCursor.getString(mCursor.getColumnIndex("path"));56 content_tv.setText(content);57 time_tv.setText(time);58 img_iv.setImageBitmap(getImageThumbnail(url,200,200));59 return layout;60 }61 62 //获取缩略图63 public Bitmap getImageThumbnail(String uri,int width,int height){64 Bitmap bitmap=null;65 BitmapFactory.Options options=new BitmapFactory.Options();66 options.inJustDecodeBounds=true;67 bitmap=BitmapFactory.decodeFile(uri,options);68 options.inJustDecodeBounds=false;69 int beWidth=options.outWidth/width;70 int beHeight=options.outHeight/height;71 int be=1;72 //防止图片超出过大或过小不予缩小73 if(beWidth<beHeight){74 be=beWidth;75 }else {76 be=beHeight;77 }78 if(be<=0){79 be=1;80 }81 options.inSampleSize=be;82 bitmap=BitmapFactory.decodeFile(uri,options);83 bitmap=ThumbnailUtils.extractThumbnail(bitmap,width,height,ThumbnailUtils.OPTIONS_RECYCLE_INPUT);84 return bitmap;85 }86 }
视图层(View):
分别是主界面 activity_main.xml 添加内容addcontent.xml 内容详情页incontent.xml
内容详情页与添加内容界面 基本相似 所以可实现代码的简单修改 将编辑框改为文本框 再修改相应ID即可
接下来是核心部分
控制器(Controler):
主activity:
1 package com.bluesky.mynote; 2 import android.content.Intent; 3 import android.database.Cursor; 4 import android.database.sqlite.SQLiteDatabase; 5 import android.support.v7.app.ActionBarActivity; 6 import android.os.Bundle; 7 import android.view.View; 8 import android.widget.AdapterView; 9 import android.widget.Button;10 import android.widget.ListView;11 12 13 public class MainActivity extends ActionBarActivity implements View.OnClickListener {14 private Button text_btn, img_btn;15 private ListView lv;16 private Intent i;17 private MyAdapter adapter;18 private NoteDB noteDB;19 private SQLiteDatabase dbReader;20 private Cursor cursor;21 22 @Override23 protected void onCreate(Bundle savedInstanceState) {24 super.onCreate(savedInstanceState);25 setContentView(R.layout.activity_main);26 initView();27 //给按钮加入监听事件28 text_btn.setOnClickListener(this);29 img_btn.setOnClickListener(this);30 noteDB = new NoteDB(this);31 //获取读取权限 用于加载listview的内容32 dbReader = noteDB.getReadableDatabase();33 lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {34 @Override35 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {36 cursor.moveToPosition(position);//游标挪到了position的位置上37 Intent i=new Intent(MainActivity.this,InContent.class);38 i.putExtra(NoteDB.ID,cursor.getInt(cursor.getColumnIndex(NoteDB.ID)));//以便根据ID删除数据39 i.putExtra(NoteDB.CONTENT,cursor.getString(cursor.getColumnIndex(NoteDB.CONTENT)));40 i.putExtra(NoteDB.TIME,cursor.getString(cursor.getColumnIndex(NoteDB.TIME)));41 i.putExtra(NoteDB.PATH,cursor.getString(cursor.getColumnIndex(NoteDB.PATH)));42 startActivity(i);43 }44 });45 46 }47 48 //初始化控件49 public void initView() {50 lv = (ListView) findViewById(R.id.list);51 text_btn = (Button) findViewById(R.id.text);52 img_btn = (Button) findViewById(R.id.image);53 }54 55 //查询数据56 public void selectDB() {57 cursor = dbReader.query(NoteDB.TABLE_NAME,null,null,null,null,null,null,null);58 adapter = new MyAdapter(this,cursor);59 lv.setAdapter(adapter);60 }61 62 @Override63 public void onClick(View v) {64 i = new Intent(this, AddContent.class);65 switch (v.getId()) {66 case R.id.text:67 i.putExtra("flag", "1");68 startActivity(i);69 break;70 case R.id.image:71 i.putExtra("flag", "2");72 startActivity(i);73 break;74 }75 }76 77 @Override78 protected void onResume() {79 super.onResume();80 selectDB();81 }82 }
添加内容 activity
1 package com.bluesky.mynote; 2 3 import android.app.Activity; 4 import android.content.ContentValues; 5 import android.content.DialogInterface; 6 import android.content.Intent; 7 import android.database.sqlite.SQLiteDatabase; 8 import android.graphics.Bitmap; 9 import android.graphics.BitmapFactory; 10 import android.net.Uri; 11 import android.os.Bundle; 12 import android.os.Environment; 13 import android.os.PersistableBundle; 14 import android.provider.MediaStore; 15 import android.util.Log; 16 import android.view.Menu; 17 import android.view.View; 18 import android.widget.Button; 19 import android.widget.EditText; 20 import android.widget.ImageView; 21 import android.widget.VideoView; 22 23 import java.io.File; 24 import java.text.SimpleDateFormat; 25 import java.util.Date; 26 27 /** 28 * Created by 清晨 on 2015/5/6. 29 */ 30 public class AddContent extends Activity implements View.OnClickListener { 31 private NoteDB noteDB; 32 private SQLiteDatabase dbWriter; 33 private String flag; //接受从mainactivity传来的标识 用于判定加载不同的添加内容界面(图文或者纯文字) 34 private EditText editText; 35 private Button save_btn,cancel_btn; 36 private ImageView c_img; 37 private File imgfile; 38 @Override 39 public void onCreate(Bundle savedInstanceState) { 40 super.onCreate(savedInstanceState); 41 setContentView(R.layout.addcontent); 42 flag=getIntent().getStringExtra("flag"); 43 initView(); 44 save_btn.setOnClickListener(this); 45 cancel_btn.setOnClickListener(this); 46 noteDB=new NoteDB(this); 47 dbWriter=noteDB.getWritableDatabase();//获取写入数据库权限 48 } 49 50 //初始化控件 51 public void initView(){ 52 editText= (EditText) findViewById(R.id.ettext); 53 save_btn= (Button) findViewById(R.id.save); 54 cancel_btn= (Button) findViewById(R.id.cancel); 55 c_img= (ImageView) findViewById(R.id.c_img); 56 if(flag.equals("1")){ 57 c_img.setVisibility(View.GONE);//隐藏imageview 58 } 59 if(flag.equals("2")){ 60 c_img.setVisibility(View.VISIBLE);//显示imageview 61 //启动系统相机拍照 62 Intent getImg=new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 63 //图片是放在存储卡中 路径存在数据库中 以时间命名图片 避免重名 64 imgfile=new File(Environment.getExternalStorageDirectory() 65 .getAbsolutePath()+"/"+getTime()+".jpg"); 66 getImg.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(imgfile)); 67 startActivityForResult(getImg,1);//便于立即查看效果 68 69 70 } 71 } 72 73 //获取内容并写入数据库 74 public void addDB(){ 75 ContentValues cv=new ContentValues(); 76 cv.put(NoteDB.CONTENT,editText.getText().toString()); 77 cv.put(NoteDB.TIME,getTime()); 78 cv.put(NoteDB.PATH,imgfile + ""); 79 dbWriter.insert(NoteDB.TABLE_NAME,null,cv); 80 } 81 82 //获取系统当前时间 83 public String getTime(){ 84 SimpleDateFormat format=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); 85 Date curDate=new Date(); 86 String str=format.format(curDate); 87 return str; 88 } 89 90 @Override 91 public void onClick(View v) { 92 switch (v.getId()){ 93 case R.id.save: 94 addDB(); 95 finish(); 96 break; 97 case R.id.cancel: 98 finish(); 99 break;100 101 }102 103 }104 105 //预览显示拍摄内容106 @Override107 protected void onActivityResult(int requestCode, int resultCode, Intent data) {108 super.onActivityResult(requestCode, resultCode, data);109 if(resultCode==1){110 Bitmap bitmap= BitmapFactory.decodeFile(imgfile.getAbsolutePath());111 c_img.setImageBitmap(bitmap);112 }113 }114 }
内容详情页Activity
1 package com.bluesky.mynote; 2 3 import android.app.Activity; 4 import android.database.sqlite.SQLiteDatabase; 5 import android.graphics.Bitmap; 6 import android.graphics.BitmapFactory; 7 import android.os.Bundle; 8 import android.view.View; 9 import android.widget.Button;10 import android.widget.ImageView;11 import android.widget.TextView;12 13 /**14 * Created by 清晨 on 2015/5/8.15 */16 public class InContent extends Activity implements View.OnClickListener {17 private Button del_btn;18 private Button back_btn;19 private ImageView in_img;20 private TextView in_tv;21 private NoteDB noteDB;22 private SQLiteDatabase dbWriter;23 @Override24 protected void onCreate(Bundle savedInstanceState) {25 super.onCreate(savedInstanceState);26 setContentView(R.layout.incontent);27 initView();28 noteDB= new NoteDB(this);29 dbWriter=noteDB.getWritableDatabase();30 del_btn.setOnClickListener(this);31 back_btn.setOnClickListener(this);32 //根据记事方式加载不同视图33 if(getIntent().getStringExtra(NoteDB.PATH).equals("null")){34 in_img.setVisibility(View.GONE);35 }else {36 in_img.setVisibility(View.VISIBLE);37 }38 //显示文字39 in_tv.setText(getIntent().getStringExtra(NoteDB.CONTENT));40 //显示图片41 Bitmap bitmap= BitmapFactory.decodeFile(getIntent().getStringExtra(NoteDB.PATH));42 in_img.setImageBitmap(bitmap);43 }44 45 public void initView(){46 del_btn= (Button) findViewById(R.id.delete);47 back_btn= (Button) findViewById(R.id.back);48 in_img= (ImageView) findViewById(R.id.in_img);49 in_tv= (TextView) findViewById(R.id.in_tv);50 }51 52 @Override53 public void onClick(View v) {54 switch (v.getId()){55 case R.id.delete:56 delDB();57 finish();58 break;59 case R.id.back:60 finish();61 break;62 }63 }64 //删除数据65 public void delDB(){66 dbWriter.delete(NoteDB.TABLE_NAME,"id="+getIntent()67 .getIntExtra(NoteDB.ID,0),null);68 }69 }
新人一枚,初学安卓,也初次尝试着写博客,暂且把这一路的code time记下来吧.
新闻热点
疑难解答