美文网首页程序员
android从入门到放弃(3)

android从入门到放弃(3)

作者: 雨中枫灵 | 来源:发表于2018-11-29 15:36 被阅读0次

实验二 通讯录APP实验

一、目的:1、熟悉Android数据存储和访问;2、掌握SQLite数据库的使用方法;3、掌握ContentResolver的基本用法;4、学会创建自己的内容提供器。

二、内容:设计与实现通讯录APP,具有以下功能:1、实现一个通讯录APP,展示联系人列表(不少于5个联系人,联系人信息包括:姓名,电话,邮箱);2、能对通讯录进行增删改查;3、创建自己的内容提供器,确定哪部分数据可以被外部程序访问;4、新建一个应用程序,使用ContentResolver读取通讯录里的联系人。

三、设计与实现

界面设计思路:
主界面:打开app时,直接显示通讯录中的联系人,主界面有一个新建联系人按钮,可以添加联系人,用listview显示联系人,点击后可以对其中的联系人进行修改,删除等操作。使用相对布局是为了Listview能在中间显示,容易控制如图:

image.png

代码如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="bottom">
    <TextView
        android:id="@+id/tvtitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="23sp"
        android:text="联系人列表"
        android:gravity="center"
        android:layout_marginTop="10dp"/>
    <ListView
        android:id="@+id/lv_people"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:divider="@android:color/darker_gray"
        android:layout_below="@+id/tvtitle"
        android:layout_above="@+id/btn_new"
        android:dividerHeight="1dp" />
    <Button
        android:id="@+id/btn_new"
        android:layout_alignParentBottom="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:text="新建联系人"/>

</RelativeLayout>

添加联系人界面:使用3个editview读取用户的输入,啷个按钮表示添加和取消。界面如图

image.png

实现代码如下

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="15dp">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textColor="#000"
        android:textSize="25sp"
        android:text="新建联系人"/>
    <EditText
        android:layout_marginTop="10dp"
        android:id="@+id/edt_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="姓名"/>
    <EditText
        android:layout_marginTop="10dp"
        android:id="@+id/edt_number"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="电话"/>
    <EditText
        android:layout_marginTop="10dp"
        android:id="@+id/edt_email"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="邮箱"/>
    <Button
        android:layout_marginTop="10dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/btn_add"
        android:text="添加"
        android:textSize="19sp"/>
    <Button
        android:layout_marginTop="10dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/btn_cancel"
        android:text="取消"
        android:textSize="19sp"/>
</LinearLayout>

删除修改的界面:
由于修改的时候不允许修改姓名,所以把姓名的控件改为TextView,其他的为EditView,为了对其,使用3*2的网格布局,用于显示,又可以修改。如图:

image.png
实现代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.myapplication.UpdateActivity"
    android:orientation="vertical"
    android:layout_margin="10dp">
    <GridLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:rowCount="3"
        android:columnCount="2">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="22sp"
            android:text="姓名:"/>
        <TextView
            android:id="@+id/tvuname"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="22sp"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="号码:"
            android:textSize="22sp"/>
        <EditText
            android:id="@+id/edtunumber"
            android:layout_width="wrap_content"
            android:textSize="22sp"
            android:layout_height="wrap_content" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="22sp"
            android:text="邮箱:"/>
        <EditText
            android:id="@+id/edtuemail"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="22sp"/>
    </GridLayout>
    <Button
        android:id="@+id/btn_del"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:text="删除联系人"
        android:layout_marginTop="10dp"/>
    <Button
        android:id="@+id/btn_saveup"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="保存更改"
        android:textSize="20sp" />
</LinearLayout>

业务逻辑思路:
主界面显示联系人,点击新建按钮跳转到新建联系人界面,点击listView进入删除和修改的界面。主界面负责从数据库中读取联系人的信息并显示。

首先通过ContactsdbHelper类来初始化数据库,创建联系人表,该类内容如下:

package com.example.myapplication;
import android.content.Context;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.widget.Toast;
/**
 * Created by 永恒之蓝 on 2018/5/19.
 */
public class ContactsdbHelper extends SQLiteOpenHelper {
    public static String CONTACTSDB="create table Contacts("
            +"name text,"
            +"number text,"
            +"email text)";
    private Context mContext;
    public ContactsdbHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        mContext=context;
    }

    public ContactsdbHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version, DatabaseErrorHandler errorHandler) {
        super(context, name, factory, version, errorHandler);
        mContext=context;
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CONTACTSDB);
        Toast.makeText(mContext, "Create Succeeded", Toast.LENGTH_SHORT).show();
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

主界面逻辑实现代码如下:想实现的效果是当新建联系人成功后会回到当前主界面,主界面会显示刚刚创建的联系人。此时需要重写onResume()方法,在该方法中实现该界面显示的更新。代码如下:

package com.example.myapplication;

import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity implements View.OnClickListener, AdapterView.OnItemClickListener {
    private ContactsdbHelper contactsdbHelper;
    Button btnNew;
    ListView mlvPeople;
    ArrayAdapter<String> adapter;
    List<String> contactlists=new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getSupportActionBar().hide();
        contactsdbHelper=new ContactsdbHelper(this,"Contacts.db",null,2);
        initViews();
    }
    private void readContacts() {
        SQLiteDatabase db=contactsdbHelper.getWritableDatabase();
        Cursor cursor=null;
        try{
            cursor =db.query("Contacts",null,null,null,null,null,null);
            if(cursor.moveToFirst()){
               do{
                    String sName=cursor.getString(cursor.getColumnIndex("name"));
                    String sNumber=cursor.getString(cursor.getColumnIndex("number"));
                    String sEmail=cursor.getString(cursor.getColumnIndex("email"));
                    contactlists.add("姓名:"+sName+"\t\t电话:"+sNumber+"\n邮箱:"+sEmail);
                } while(cursor.moveToNext());
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(cursor!=null){
                cursor.close();
            }
        }
        adapter=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,contactlists);
        mlvPeople.setAdapter(adapter);
    }

    //初始化控件
    public void initViews()
    {
       btnNew=findViewById(R.id.btn_new);
       btnNew.setOnClickListener(this);
       mlvPeople=findViewById(R.id.lv_people);
       mlvPeople.setOnItemClickListener(this);

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_new:
                Intent intent=new Intent(this,AddContacts.class);
                startActivity(intent);
                break;
        }
    }
    @Override
    public void onResume() {
        super.onResume();
        //清空list列表
        contactlists.clear();
        //读取更新后的数据库
        readContacts();
    }
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        Intent intent=new Intent(this,UpdateActivity.class);
        Bundle bundle = new Bundle();
        bundle.putSerializable("pos", position);
        intent.putExtras(bundle);
        startActivity(intent);
    }
}

新建联系人界面:
可以输入联系人信息,其中姓名和电话是必填的,邮箱可以不填,点击添加按钮保存输入的信息,并结束当前activity,点击取消也结束该活动,返回主activity。实现代码如下:

package com.example.myapplication;
import android.content.ContentValues;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
/**
 * Created by 永恒之蓝 on 2018/5/19.
 */
public class AddContacts extends AppCompatActivity implements View.OnClickListener {
    Button btnAdd,btnCancel;
    EditText edtName,edtNumber,edtEmail;
    ContactsdbHelper dbHelper;
    SQLiteDatabase db;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_addcontacts);
        getSupportActionBar().hide();
        initViews();
    }
    public void initViews(){
        btnAdd=findViewById(R.id.btn_add);
        btnAdd.setOnClickListener(this);
        btnCancel=findViewById(R.id.btn_cancel);
        btnCancel.setOnClickListener(this);
        edtName=findViewById(R.id.edt_name);
        edtNumber=findViewById(R.id.edt_number);
        edtEmail=findViewById(R.id.edt_email);
        dbHelper=new ContactsdbHelper(this,"Contacts.db",null,2);
        db=dbHelper.getWritableDatabase();
    }
    @Override
    public void onClick(View v) {
        switch (v.getId())
        {
            case R.id.btn_add:
                if(!isEmpty()){
                    ContentValues values=new ContentValues();
                    values.put("name",edtName.getText().toString());
                    values.put("number",edtNumber.getText().toString());
                    values.put("email",edtEmail.getText().toString());
                    db.insert("Contacts",null,values);
                    values.clear();
                    finish();
                }
                else {
                    Toast.makeText(this,"必须填写姓名和邮箱!",Toast.LENGTH_SHORT).show();
                }
                break;
            case R.id.btn_cancel:
                finish();
                break;
        }
    }
    //判断输入是否为空。
    public boolean isEmpty(){
        if(edtName.getText().toString().equals("")||edtNumber.getText().toString().equals("")){
            return true;
        }
        else
        {
            return false;
        }
    }
}

修改和删除联系人:通过点击主界面的listview进入,可以修改电话号码,邮箱信息,可以删除一个联系人,当删除或保存时会结束当前活动,返回上一个活动。

package com.example.myapplication;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class UpdateActivity extends AppCompatActivity implements View.OnClickListener {
    private TextView tvuname;
    private EditText edtunumber;
    private EditText edtuemail;
    private Button btnDel;
    private Button btnSaveup;
    int pos;
    private ContactsdbHelper contactsdbHelper;
    private void initViews() {
        tvuname = findViewById(R.id.tvuname);
        edtunumber =  findViewById(R.id.edtunumber);
        edtuemail = findViewById(R.id.edtuemail);
        btnDel = findViewById(R.id.btn_del);
        btnDel.setOnClickListener(this);
        btnSaveup = findViewById(R.id.btn_saveup);
        btnSaveup.setOnClickListener(this);
        pos= (int)getIntent().getSerializableExtra("pos");
        contactsdbHelper=new ContactsdbHelper(this,"Contacts.db",null,2);

    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.updatecontacts);
        initViews();
        initContacts();
    }

    private void initContacts() {
        SQLiteDatabase db=contactsdbHelper.getWritableDatabase();
        Cursor cursor=null;
        try{
            cursor =db.query("Contacts",null,null,null,null,null,null);
            if(cursor.moveToPosition(pos)){

                String sName=cursor.getString(cursor.getColumnIndex("name"));
                String sNumber=cursor.getString(cursor.getColumnIndex("number"));
                String sEmail=cursor.getString(cursor.getColumnIndex("email"));
                tvuname.setText(sName);
                edtunumber.setText(sNumber);
                edtuemail.setText(sEmail);

            }

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(cursor!=null){
                cursor.close();
            }
        }
    }
    @Override
    public void onClick(View v) {
        SQLiteDatabase db=contactsdbHelper.getWritableDatabase();
        switch (v.getId()){
            case R.id.btn_del:
                db.delete("Contacts","name=?",new String[]{tvuname.getText().toString()});
                finish();
                break;
            case R.id.btn_saveup:
                ContentValues values=new ContentValues();
                values.put("number",edtunumber.getText().toString());
                values.put("email",edtuemail.getText().toString());
                db.update("Contacts",values,"name=?",new String[]{tvuname.getText().toString()});
                finish();
                break;
        }
    }
}

至此,已经实现了第一和第二个实验要求。
实现自己的内容提供器:将内容都设为可让外部读取,方便进行测试。

package com.example.myapplication;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
/**
 * Created by 永恒之蓝 on 2018/5/22.
 */
public class MyProvider extends ContentProvider {
    public static final int CONTACTS_DIR=0;
    public static final int CONTACTS_ITEM=1;
    private ContactsdbHelper dbHelper;
    public static final String AUTHORITY="com.example.myapplication";

    private static UriMatcher uriMatcher;
    static {
        uriMatcher=new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI( AUTHORITY,"Contacts",CONTACTS_DIR);
        uriMatcher.addURI( AUTHORITY,"Contacts/#",CONTACTS_ITEM);
    }
    @Override
    public boolean onCreate() {
        dbHelper=new ContactsdbHelper(getContext(),"Contacts.db",null,2);
        return true;
    }

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        SQLiteDatabase db=dbHelper.getReadableDatabase();
        Cursor cursor=null;
        switch (uriMatcher.match(uri))
        {
            case CONTACTS_DIR:
                cursor=db.query("Contacts",projection,selection,selectionArgs,null,null,sortOrder);
                break;
            case CONTACTS_ITEM:
                String nameId=uri.getPathSegments().get(1);
                cursor=db.query("Contacts",projection,"name=?",new String[]{nameId},null,null,sortOrder);
                break;
            default:
                break;

        }
        return cursor;
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        switch (uriMatcher.match(uri))
        {
            case  CONTACTS_DIR:
                return "vnd.android.cursor.dir/vnd.com.example.myapplication.Contacts";
            case  CONTACTS_ITEM:
                return "vnd.android.cursor.item/vnd.com.example.myapplication.Contacts";
            default:
                break;
        }

        return null;
    }
    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        SQLiteDatabase db=dbHelper.getWritableDatabase();
        Uri uriRetrun=null;
        switch (uriMatcher.match(uri))
        {
            case CONTACTS_DIR:
            case CONTACTS_ITEM:
               long newContactsId=db.insert("Contacts",null,values);
               uriRetrun=Uri.parse("content://"+AUTHORITY+"/Contacts/"+newContactsId);
               break;
            default:
                break;

        }
        return uriRetrun;
    }

    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        SQLiteDatabase db =dbHelper.getWritableDatabase();
        int deleteRows=0;
        switch (uriMatcher.match(uri)){
            case CONTACTS_DIR:
                deleteRows=db.delete("Contacts",selection,selectionArgs);
                break;
            case CONTACTS_ITEM:
                String nameId=uri.getPathSegments().get(1);
                deleteRows=db.delete("Contacts","name=?",new String[]{nameId});
                break;
            default:
                break;
        }
        return deleteRows;
    }

    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
        SQLiteDatabase db =dbHelper.getWritableDatabase();
        int updateRows=0;
        switch (uriMatcher.match(uri)){
            case CONTACTS_DIR:
                updateRows=db.update("Contacts",values,selection,selectionArgs);
                break;
            case CONTACTS_ITEM:
                String nameId=uri.getPathSegments().get(1);
                updateRows=db.update("Contacts",values,"name=?",new String[]{nameId});
                break;
            default:
                break;
        }
        return updateRows;
    }
}

新建一个项目,用来读取以上建立的数据库。界面布局和主界面差不多,通过listview显示。
读取数据库代码如下:

package com.example.providertest;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    ListView lvPeople;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getSupportActionBar().hide();
        lvPeople=findViewById(R.id.lv_people);
        ArrayAdapter<String> adapter;
        List<String> contactlists=new ArrayList<>();
        Uri uri=Uri.parse("content://com.example.myapplication/Contacts");
        Cursor cursor=getContentResolver().query(uri,null,null,null,null);
        if (cursor!=null){
            while(cursor.moveToNext()){
                String name=cursor.getString(cursor.getColumnIndex("name"));
                String number=cursor.getString(cursor.getColumnIndex("number"));
                String email=cursor.getString(cursor.getColumnIndex("email"));
                contactlists.add("姓名:"+name+"\t\t电话:"+number+"\n邮箱:"+email);

            }
            cursor.close();
        }
        adapter=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,contactlists);
        lvPeople.setAdapter(adapter);
    }
}

实验结果如下(运行结果可在上面界面代码部分的图片看见),可以发现可以读取该数据库信息:

image.png
四、遇到的问题
主界面的新建联系人按钮会挡住listView的下半部分,会挡住最后一个联系人的信息。
解决方法:
使用相对布局,使ListView位置控制在button上方。关键代码如下:
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="bottom">
    <TextView
        android:id="@+id/tvtitle"
            …>
    <ListView
        android:id="@+id/lv_people"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:divider="@android:color/darker_gray"
        android:layout_below="@+id/tvtitle"
        android:layout_above="@+id/btn_new"
        android:dividerHeight="1dp" />

    <Button
        android:id="@+id/btn_new"
        …>
android:text="新建联系人"/>

</RelativeLayout>

在修改通讯录界面,如何获取用户点击的联系人信息?解决方法是监听用户点击的是第几个ListViewItem,把位置传给修改的活动,该活动在从数据库中读取该联系人信息并显示。
关键代码如下:

@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    Intent intent=new Intent(this,UpdateActivity.class);
    Bundle bundle = new Bundle();
    bundle.putSerializable("pos", position);
    intent.putExtras(bundle);
    startActivity(intent);
}

当返回主活动时由于会重新读取更新后的数据库,会显示重复相同的联系人。解决方法是清空list的数据,在重新读取:

@Override
public void onResume() {
    super.onResume();
    //清空list列表
    contactlists.clear();
    //读取更新后的数据库
    readContacts();
}

相关文章

网友评论

    本文标题:android从入门到放弃(3)

    本文链接:https://www.haomeiwen.com/subject/selfcqtx.html