Lab 2 Android Data Storage Instance Address Book
1. Experimental Purpose
(1) Skilled in UI interface design process and methods;
(2) To further understand the establishment and operation of the SQLite database;
(3) Skilled in Andriod database programming.
2. Experimental Environment
(1) Hardware: PC, other related hardware;
(2) Software: Windows XP, Android Studio Integrated Development Environment, Android Development Tools Plug-in.
3. Experimental Contents and Requirements
(1) Master the interface layout;
(2) Skilled in the creation and operation programming of SQLite database;
(3) Skilled in using ListView controls;
(4) Complete the programming design and debugging of the mobile phone address book.
IV. EXPERIMENTAL STEPS
In this experiment, we will complete an address book function on Android.First we'll determine what functionality this address book will have, such as browsing contacts, adding contacts, deleting contacts, editing contacts, viewing contacts, and calling or sending text messages to a contact when one is found.Once you've identified these capabilities, consider what knowledge you need to use, such as: to store many contacts, you can use a database for easy administration and maintenance.Once you're sure, you can start a new project.
1. UI Design
When designing the interface, you need to design it according to the function you have set. In this section, we browse contacts to display to users through a List, as shown in Figure 1. Users need actions, so you need to design options for users to operate, such as add, query, etc. Figures 2 and 3 are the menu of long press contacts and the effect of clicking contacts directly.
After designing these basic functions, you need to design an interface to add and modify contacts.This layout is simple, and you can display a tag through TextView, such as a name, phone, and so on.Since editing definitely requires receiving input from the user, EditText is used here for the user to enter information, as shown in Figure 3; after modification, contact information can be viewed in the current interface, as shown in Figure 4.
2. Database Design
For the storage of contact information, you can use the database provided in Android.To design a database, you first need to determine what the data is. To facilitate management, maintenance, and sharing, you first define all the data you want to use in the database into a DBdao class. The data information defined in this example is in a file DBdao.java In; where contact information data is encapsulated in the Person class, the code list is shown below.
//Define data public class Person implements Serializable { private String DEFAULT="No record"; /*Full name*/ private String name; /*Contact number*/ private String tel; public String getAddr() { return addr; } public void setAddr(String addr) { if (addr.trim().length()==0){ this.addr=DEFAULT; } this.addr = addr; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getTel() { return tel; } public void setTel(String tel) { this.tel = tel; } public String getEmail() { return email; } public void setEmail(String email) { if (email.trim().length()==0){ this.email=DEFAULT; }else { this.email = email; } } public String getRemarks() { return remarks; } public void setRemarks(String remarks) { //If empty string, set to default if (remarks.trim().length()==0) { this.remarks=DEFAULT; }else { this.remarks = remarks; } } public void setHeadPickture(Bitmap headPickture) { this.headPickture = headPickture; } /*address*/ private String addr; /*E-mail*/ private String email; /*Remarks*/ private String remarks; /*Head portrait*/ private Bitmap headPickture; }
In Android Android.database.sqliteThe.SQLiteOpenHelper class is an auxiliary class designed for database creation and version management.Therefore, in order to better manage the database, we create an auxiliary class DBdao inherited from SQLiteOpenHelper to maintain and update the database, and to add, delete, check and change the database, as shown in the code list below.
/* Provide four ways to add, delete, and change a database*/ public class DBdao extends SQLiteOpenHelper{ private static final String DB_NAME ="TXL.db"; private static final String TABLE_NAME = "person"; private static int DB_VERSION =1; private SQLiteDatabase db; private Context context; /*Global persons container*/ public static final List<Person> persons = new ArrayList<Person>(); /*Build table structure, initialize table*/ private static final String CREATETABLE="create table if not exists person(" + "tel text primary key not null,"+ "name text,"+ "addr text, "+ "email text ,"+ "remarks text)"; public DBdao(Context context) { super(context,DB_NAME,null,DB_VERSION); this.context = context; db = getWritableDatabase();//set up a database } //Open SQLite database connection public SQLiteDatabase openConnection(){ db = getWritableDatabase(); return db; } //Close database connection, only one connection is outside public void closeConnection(){ db.close(); } //Create Table public boolean creatTable(String createTableSql){ try { openConnection(); db.execSQL(createTableSql); }catch (Exception e){ e.printStackTrace(); return false; }finally { closeConnection(); } return true; } //Add data public boolean save(Person person/*String tableName,ContentValues context*/){ String tableName=TABLE_NAME; ContentValues context=new ContentValues(); context.put("name",person.getName().trim()); context.put("tel",person.getTel().trim()); context.put("addr",person.getAddr().trim()); context.put("email",person.getEmail().trim()); context.put("remarks",person.getRemarks().trim()); try { openConnection(); db.insert(tableName,null,context); }catch (Exception e){ e.printStackTrace(); return false; }finally { closeConnection(); } return true; } //Modify data public boolean update(Person p){ /*String tableName,ContentValues contentValues,String whereClause,String []whereArgs*/ ContentValues contentValues = new ContentValues(); contentValues.put("name"/*Field name of table*/,p.getName().trim()/*The value corresponding to this field*/); contentValues.put("tel",p.getTel().trim()); contentValues.put("addr",p.getAddr().trim()); contentValues.put("email",p.getEmail().trim()); contentValues.put("remarks",p.getRemarks().trim()); /* * The order in which question marks appear corresponds to the subscripts in the String[] table, starting with 0 * For example: * The first question mark corresponds to the element with subscript 0 in String[] * The second question mark corresponds to the element subscribed to 1 in String[] * */ String whereClause = "name=?"; String []whereArgs=new String[]{p.getName().trim()}; try { openConnection(); db.update(TABLE_NAME,contentValues,whereClause,whereArgs); }catch (Exception e){ e.printStackTrace(); return false; }finally { closeConnection(); } return true; } //Delete data public boolean delete(String condition){ String[] obj=new String[]{condition}; String delSql="tel=?"; try { openConnection(); db.delete(TABLE_NAME,delSql,obj); }catch (Exception e){ e.printStackTrace(); return false; }finally { closeConnection(); } return true; } //Query operation /* *1.Read person objects from the database into the persons collection *2.Iterate persons collection and encapsulate map objects into list collection * 3.Return list collection * */ public List<Person> getData() { //Read Table Operation //Empty persons container before reading table operation if (persons.size()>0){ persons.clear(); } String sql = "select *from person"; /* Cursor: Functionality is similar to ResultSet in JDBC rawQuery:Functionality similar to PrepareStatement rawQuery(String sqlStatment,String[] agrs); eg: String sql = "select *from person where name=? and tel=?" String[] agrs={"fang","188XXXXXX"}; Cursor c = rawQuery(sql,agrs); */ openConnection(); Cursor cursor =null; try { cursor = db.rawQuery(sql, null); while (cursor.moveToNext()) { Person person = new Person(); /* * getColumnIndex("name")Return index value based on column name * getString() Returns the value of the column based on the index * */ person.setName(cursor.getString(cursor.getColumnIndex("name")).trim()); person.setTel(cursor.getString(cursor.getColumnIndex("tel")).trim()); person.setEmail(cursor.getString(cursor.getColumnIndex("email")).trim()); person.setAddr(cursor.getString(cursor.getColumnIndex("addr")).trim()); person.setRemarks(cursor.getString(cursor.getColumnIndex("remarks")).trim()); persons.add(person); } }catch (Exception e){ e.printStackTrace(); }finally { closeConnection(); } //Determine whether it is the first use if (persons.size()==0){ Person s =new Person(); s.setName("fangzirui"); s.setTel("18871245731"); persons.add(s); } return persons; } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATETABLE); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
3. Contact List Implementation
stay MainActivity.java File to view contact list and contact query and delete operations, code list as shown below.
public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private Button btnadd; private EditText etSearch; private ListView lv; private ImageButton btnImage; private String searchCondition; //Adapter private SimpleAdapter simpleAdapter=null; //Global container for data private final List<Map<String,String>> data=new ArrayList<>(); //Load data that meets search criteria private final List<Map<String,String>> newData=new ArrayList<>(); private List<Person> persons=null; private final Intent intent = new Intent(); private Thread thread=null; //Definition Assistant private final Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: searchCondition = (String) msg.obj; //Update UI newData.clear(); //Traversing a data collection /* * 1.Get a map * 2.Get map's mobile number * 3.Put in newData * */ for (int i=0;i<data.size();i++) { Map map = data.get(i); /* * Combine person's tel and name into a new string. * Then find the searchCondition substring in this new string * Achieve search results * */ String te = (String)map.get("tel"); te += (String)map.get("name"); if (te.contains(searchCondition)){ newData.add(map); } } adapterSet(newData); break; case 2: adapterSet(data); break; } } }; /* * Set up an adapter * */ private void adapterSet(List<Map<String,String>> data) { simpleAdapter = new SimpleAdapter( MainActivity.this, //Context Environment data, //Fill in updated data R.layout.lv_item, //Defined List Styles new String[]{"img","name","tel"},//Index Value //Control to fill in data new int[]{R.id.lv_item_head,R.id.lv_item_name,R.id.lv_item_tel} ); lv.setAdapter(simpleAdapter); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //No Horizontal Screen setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); setContentView(R.layout.activity_main); /* Generally speaking, when there are too many entries in the Actionbar, the menu with three small vertical dots is displayed, but it is not shown when testing on the real machine. If the machine owns the entity menu key, instead of displaying the overflow menu on the right side, press menu to generate it.This is not conducive to a unified interface style. We can change this display by changing whether the system detects the presence of the entity menu key. The menu display is judged by the public boolean hasPermanentMenuKey ().This method is to get the boolean value of sHasPermanentMenuKey. Solution: By in onCreate() */ try { ViewConfiguration mconfig = ViewConfiguration.get(this); Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey"); if(menuKeyField != null) { menuKeyField.setAccessible(true); menuKeyField.setBoolean(mconfig, false); } } catch (Exception ex) { ex.printStackTrace(); } btnadd = (Button) findViewById(R.id.main_btn_add); btnadd.setOnClickListener(this); btnImage = (ImageButton) findViewById(R.id.main_btn_del); btnImage.setOnClickListener(this); btnImage.setVisibility(View.GONE); etSearch = (EditText) findViewById(R.id.main_et_search); lv = (ListView) findViewById(R.id.main_lV); DBdao DBdao = new DBdao(MainActivity.this); //Reading Contacts Map from SQLtie persons = DBdao.getData(); //Iterate over the persons collection and convert persons into map objects into data for (Person p: persons){ Map map = new HashMap(); map.put("img", R.drawable.a); map.put("name", p.getName()); map.put("tel", p.getTel()); data.add(map); } //Data adapter adapterSet(data); //Set etSearch listener etSearch.addTextChangedListener(new TextWatcher() { //Before Change @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } //When to change @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } //After change @Override public void afterTextChanged(Editable s) { if(s.length() == 0){ btnImage.setVisibility(View.GONE);//Fork out when text box is empty Message mgs2 = new Message(); mgs2.what=2; handler.sendMessage(mgs2); } else { btnImage.setVisibility(View.VISIBLE);//A fork appears when the text box is not empty Message mgs = new Message(); mgs.what=1; mgs.obj =s.toString().trim(); handler.sendMessage(mgs); } } }); //lv's Click Event lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Person person=new Person(); person.setName(data.get(position).get("name").toString()); person.setTel(data.get(position).get("tel").toString()); //Jump intent.setClass(MainActivity.this, UpdateActivity.class); Bundle bundle = new Bundle(); bundle.putSerializable("person", person); intent.putExtras(bundle); startActivity(intent); finish(); } }); //lv long press event lv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { final int pos = position; AlertDialog.Builder builder = new AlertDialog.Builder( MainActivity.this); builder.setTitle("Delete"); builder.setIcon(R.drawable.w); builder.setMessage(" Want to delete this record?"); builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { /* Delete order must be 1-2-3 irreversible If the pos value is present after deleting the selected record in the data container, because pos is modified by final There will be no change in its value until the end of this operation, all when we reuse itData.get(pos) Method to get the object, the pos corresponding object is no longer in the data container, all will report a indexBorderOutException */ //Delete operation //1. Delete from database //1.1 Get the selected mobile number first String Tel= MainActivity.this.data.get(pos).get("tel").trim(); //1.2 Delete records from SQLite based on the resulting mobile number boolean flag = new DBdao(MainActivity.this).delete(Tel); //2. Remove from listView MainActivity.this.data.remove(pos); //3. Refresh simpleAdapter MainActivity.this.lv.setAdapter(MainActivity.this.simpleAdapter); if (!flag){ Toast.makeText(MainActivity.this, "delete failed!", Toast.LENGTH_LONG).show(); }else { Toast.makeText(MainActivity.this, "delete ok!", Toast.LENGTH_LONG).show(); } } }); builder.setNegativeButton("No", null); builder.create().show(); return true; } }); } @Override public void onClick(View v) { switch (v.getId()){ case R.id.main_btn_add:{ //Jump to Add Contact Interface /* 1.Create a new Intent object */ // /* 2.Specify the class intent will start */ intent.setClass(this, AddActivity.class); /* 3.Start a new Activity */ this.startActivity(intent); /* 4.Close the current Activity */ this.finish(); break; } case R.id.main_btn_del:{ etSearch.setText(""); break; } } } /** * Menu Settings * @param menu * @return */ @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main_main, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch(item.getItemId()){ case R.id.bakSet_item: Toast.makeText(this,"you clicked SET",Toast.LENGTH_SHORT).show(); break; case R.id.bakGet_item: Toast.makeText(this,"you clicked GET",Toast.LENGTH_SHORT).show(); break; default: } return true; } }
4. Add Contact Implementation
stay AddActivity.java File to add contacts, code list as shown below.
public class AddActivity extends AppCompatActivity implements View.OnClickListener{ private Button btn_retrun; private Button btn_cancel; private Button btn_save; private EditText et_name; private EditText et_tel; private EditText et_email; private EditText et_remarks; private EditText et_addr; private View im; private DBdao DBdao =null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.actitiy_add); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); btn_retrun = (Button) findViewById(R.id.add_btn_return); btn_cancel = (Button) findViewById(R.id.add_btn_cancel); btn_save = (Button) findViewById(R.id.add_btn_save); btn_save.setOnClickListener(this); btn_cancel.setOnClickListener(this); btn_retrun.setOnClickListener(this); et_name = (EditText) findViewById(R.id.add_ET_name); et_addr = (EditText) findViewById(R.id.add_ET_addr); et_tel = (EditText) findViewById(R.id.add_ET_tel); et_email = (EditText) findViewById(R.id.add_ET_email); et_remarks = (EditText) findViewById(R.id.add_ET_remarks); im = findViewById(R.id.add_IV_headPickture); //Settings to get pictures on ImageView im.setDrawingCacheEnabled(true); //Set the cursor position when you start entering the page et_name.setFocusable(true); et_name.setFocusableInTouchMode(true); } /* Click Event * Storage Button * Cancel button * Return button * */ @Override public void onClick(View v) { switch (v.getId()){ //Storage Button case R.id.add_btn_save:{ //Detect if the name or phone entered is empty if(et_tel.getText().toString().length()==0 || et_name.getText().toString().length()==0){ Toast.makeText(this,"Name or phone cannot be empty!",Toast.LENGTH_SHORT).show(); switchActivity(); }else { Person person = new Person(); person.setName(et_name.getText().toString()); person.setAddr(et_addr.getText().toString()); person.setEmail(et_email.getText().toString()); person.setTel(et_tel.getText().toString()); person.setRemarks(et_remarks.getText().toString()); /* * Store Person in SQLite * */ DBdao = new DBdao(AddActivity.this); DBdao.save(person); Toast.makeText(this, "add success!", Toast.LENGTH_SHORT).show(); } break; } //Cancel button case R.id.add_btn_cancel:{ this.et_name.setText(""); this.et_tel.setText(""); this.et_email.setText(""); this.et_addr.setText(""); this.et_remarks.setText(""); Toast.makeText(this,"clean success!",Toast.LENGTH_SHORT).show(); break; } //Back to Home Button case R.id.add_btn_return:{ switchActivity(); break; } } } /* * Jump function * */ private void switchActivity() { /* 1.Create a new Intent object */ Intent intent = new Intent(); /* 2.Specify the class intent will start */ intent.setClass(this, mainActivity.class); /* 3.Start a new Activity */ this.startActivity(intent); /* 4.Close the current Activity */ this.finish(); } }
5. Modify and view contact implementation
stay UpdateActivity.java File to achieve contact viewing and modification, that is, when you click from the main interface to enter, you can view all information of the contact, when you click the Modify button to enter editable mode to modify, after the modification is completed, click the Save button to complete the modification of information.The implementation code is shown below.
public class UpdateActivity extends AppCompatActivity implements View.OnClickListener { private Button btn_modify; private Button btn_call; private Button btn_ems; private Button btn_return; private TextView tv_name; private EditText et_tel; private EditText et_email; private EditText et_remarks; private EditText et_addr; private ImageView im; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); setContentView(R.layout.activity_update); btn_modify = (Button) findViewById(R.id.update_btn_modify); btn_call = (Button) findViewById(R.id.update_btn_call); btn_ems = (Button) findViewById(R.id.update_btn_ems); btn_return = (Button) findViewById(R.id.update_btn_return); btn_modify.setOnClickListener(this); btn_call.setOnClickListener(this); btn_ems.setOnClickListener(this); btn_return.setOnClickListener(this); tv_name = (TextView) findViewById(R.id.update_TV_name); et_addr = (EditText) findViewById(R.id.update_ET_addr); et_tel = (EditText) findViewById(R.id.update_ET_tel); et_email = (EditText) findViewById(R.id.update_ET_email); et_remarks = (EditText) findViewById(R.id.update_ET_remarks); im = (ImageView) findViewById(R.id.update_IV_headPickture); im.setDrawingCacheEnabled(true); //Receive Person objects from the mainActivity page Person person = getDataFromMain(); shows(person); //Enter read-only mode loseFocuse(); } /* *Fill in person information on the control corresponding to the scene *@param person * */ private void shows(Person person) { //The query here does not have to go to the database to find the corresponding one directly in the Persons container //Object is OK for (Person p: DBdao.persons){ if (person.getTel().trim().equals(p.getTel().trim())){ tv_name.setText(p.getName()); et_tel.setText(p.getTel()); et_addr.setText(p.getAddr()); et_email.setText(p.getEmail()); et_remarks.setText(p.getRemarks()); } } } /* *Receive Person objects from the mainActivity page *@param null * */ private Person getDataFromMain() { //Gets the person object that the home page puts into Intent with an index value of "person" //And according to its tel fromMainActivity.dataCorresponding data found in //Wrap it as a person object and go back Intent intent =getIntent(); Person p = (Person) intent.getSerializableExtra("person"); //Read the object from the database return p; } private int flag=0; @Override public void onClick(View v) { switch (v.getId()) { //dial button case R.id.update_btn_call: { //Call Intent in2 = new Intent(); in2.setAction(Intent.ACTION_CALL);//Specify Intentional Action in2.setData(Uri.parse("tel:"+this.et_tel.getText().toString().trim().toLowerCase()));//specify the phone number startActivity(in2); this.finish();//End the current page break; } //Edit Button case R.id.update_btn_modify: { /* * flag = 0 Representation Edit * flag = 1 Represents save * */ switch (flag) { case 0:{ btn_modify.setText("Preservation"); btn_modify.setTextColor(this.getResources().getColor(R.color.btn)); flag=1; Toast.makeText(this, "Enter Modify Mode", Toast.LENGTH_SHORT).show(); //Lose focus getFoucuse(); break; } case 1:{ Person person = new Person(); person.setName(this.tv_name.getText().toString()); person.setAddr(this.et_addr.getText().toString()); person.setEmail(this.et_email.getText().toString()); person.setTel(this.et_tel.getText().toString()); person.setRemarks(this.et_remarks.getText().toString()); //Get pictures on ImageView // person.setHeadPickture(this.im.getDrawingCache()); /* * Store Person in the person table * */ new DBdao(this).update(person); Toast.makeText(this,"Save Success",Toast.LENGTH_SHORT).show(); //Restore to read-only mode loseFocuse(); btn_modify.setText("Modification"); btn_modify.setTextColor(this.getResources().getColor(R.color.white)); flag=0; break; } } break; } //Text Message Button case R.id.update_btn_ems: { Intent intent = new Intent("android.intent.action.SENDTO", Uri.parse("smsto:"+this.et_tel.getText().toString().trim().toLowerCase())); startActivity(intent); break; } //Back to Home Button case R.id.update_btn_return: { /* 1.Create a new Intent object */ Intent intent = new Intent(); /* 2.Specify the class intent will start */ intent.setClass(this, mainActivity.class); /* 3.Start a new Activity */ this.startActivity(intent); /* 4.Close the current Activity */ this.finish(); break; } } } /* * Keep all edit boxes out of focus * */ private void loseFocuse() { et_tel.setFocusable(false); et_remarks.setFocusable(false); et_addr.setFocusable(false); et_email.setFocusable(false); tv_name.setFocusable(false); //Untouchable tv_name.setFocusableInTouchMode(false); et_tel.setFocusableInTouchMode(false); et_email.setFocusableInTouchMode(false); et_addr.setFocusableInTouchMode(false); et_remarks.setFocusableInTouchMode(false); } private void getFoucuse() { //Touchable et_tel.setFocusableInTouchMode(true); et_email.setFocusableInTouchMode(true); et_addr.setFocusableInTouchMode(true); et_remarks.setFocusableInTouchMode(true); et_tel.setFocusable(true); et_remarks.setFocusable(true); et_addr.setFocusable(true); et_email.setFocusable(true); } } }
6. Permission Settings
In this example, a new type is created, so you need toAndroidManifest.xmlDefinition, declaration.Direct call contacts and text messaging are also set up, which requiresAndroidManifest.xmlRegistered in the code list below.
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="homework.cn.txl"> <!--call Permission--> <uses-permission android:name="android.permission.CALL_PHONE"/> <uses-permission android:name="android.permission.SEND_SMS"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <!-- //Prohibit Horizontal Screen Properties android:screenOrientation="portrait" --> <activity android:name=".main.mainActivity" android:screenOrientation="portrait" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <!--Add Contact Scene--> <activity android:name=".main.AddActivity" android:label="Add a Contact" android:screenOrientation="portrait" > </activity> <!--Modify Contact Scene--> <activity android:name=".main.UpdateActivity" android:label="Modify Contacts" android:screenOrientation="portrait" > </activity> </application> </manifest>