你的位置:首页 > Java教程

[Java教程]利用MVC编程模式


  学了极客学院一个开发记事本的课程,利用自己对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.   2.2 listview每一条数据的视图格式 图片imageview 内容textview 时间textview cell.   2.3添加内容界面 imageview editext 两个Button addcontent.   2.4创建详情页视图 与addcontent视图相似 将Editext转换为Textview Button的内容由返回变成删除 incontent.

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.

内容详情页与添加内容界面 基本相似 所以可实现代码的简单修改 将编辑框改为文本框 再修改相应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记下来吧.