学了极客学院一个开发记事本的课程,利用自己对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 创建了一个数据库 用来存放记事内容 记事时间 图片路径
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,"第一个引号后的空格不能省略 否则名称会变为contentTEXT 24 @Override 25 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 @Override 35 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 @Override 29 public int getCount() { 30 return mCursor.getCount(); 31 } 32 33 @Override 34 public Object getItem(int position) { 35 return mCursor.getPosition(); 36 } 37 38 @Override 39 public long getItemId(int position) { 40 return position; 41 } 42 43 @Override 44 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 @Override 23 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 @Override 35 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 @Override 63 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 @Override 78 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 @Override 107 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 @Override 24 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 @Override 53 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记下来吧.