學了極客學院一個開發記事本的課程,利用自己對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記下來吧.
新聞熱點
疑難解答