《移动应用开发》课程
第七次实验
1、在Android Studio中,完成以下功能。
图-1 联系人列表 图-2 添加联系人 图-3 联系人详情
请开发手机电话号码簿。在默认页面中,按照图-1方式展示页面内容,要求所有的信息均是从SQLite中进行获取,详细包括:
(1)联系人数量;
(2)联系人的姓名。
联系人姓名可以使用全英文方式(本项目支持中文),要求按照首字母进行分组。联系人数量在20人以上,联系人分组要求在4组以上。
联系人图标采用预先设置的图片库进行加载,并答应用户进行选取更换其他图标(参见课件中干系Demo)。
点击联系人列表上方的搜索栏后,表现搜索页面(请自行设计页面布局效果),在输入检索关键字后,查询联系人信息,并以列表方式表现。
点击联系人列表条目(包括经过检索返回的联系人列表),对应跳转到联系人详情页面(参见图-3),当用户对应点击号码条目对应的“拨打电话”、“视频电话”、“发送信息”按钮,采用Toast方式表现对应的功能,即Dial number,Video call,Send message(本项目跳转到相应的活动页面)。
点击图-1中的“+”(添加)按钮,跳转到添加联系人信息页面(参见图-2),为用户提供添加联系人信息(包括姓名、电话号码、电子信箱、备注、单位信息)和头像信息。保存后,将信息存储到数据库中,并相应更新联系人列表的表现内容。
运行效果:
搜索功能
文件目次 :

AddContactActivity.java
- package com.example.theseventhexperiment;
- // 导入必要的包
- import android.os.Bundle;
- import android.text.TextUtils;
- import android.view.View;
- import android.widget.*;
- import androidx.appcompat.app.AppCompatActivity;
- import java.util.*;
- public class AddContactActivity extends AppCompatActivity implements View.OnClickListener {
- // 声明UI组件
- private ImageButton ib_back;
- private Button btn_tianjia;
- private EditText et_xingming, et_dianhuahaoma, et_dianziyoujian, et_beizhu, et_danweixinxi;
- private Spinner spinner;
- // 声明数据变量
- private String name, e_mail, remark, unit_information, number, avatar, from;
- private int id;
- private Integer selectedImageResource;
- private UserDBHelper mHelper;
- private List<Map<String, Integer>> data; // 使用Integer类型,因为资源ID是整数
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_add_contact);
- // 初始化视图组件
- initView();
- // 设置监听器
- setListener();
- // 获取传递过来的数据
- getValue();
- // 设置视图内容
- setView();
- // 初始化并设置Spinner适配器
- setupSpinner();
- }
- // 初始化视图组件
- private void initView() {
- ib_back = findViewById(R.id.ib_back);
- btn_tianjia = findViewById(R.id.btn_tianjia);
- et_xingming = findViewById(R.id.et_xingming);
- et_dianhuahaoma = findViewById(R.id.et_dianhuahaoma);
- et_dianziyoujian = findViewById(R.id.et_dianziyoujian);
- et_beizhu = findViewById(R.id.et_beizhu);
- et_danweixinxi = findViewById(R.id.et_danweixinxi);
- spinner = findViewById(R.id.spinner_contact_icon);
- }
- // 设置监听器
- private void setListener() {
- ib_back.setOnClickListener(this);
- btn_tianjia.setOnClickListener(this);
- }
- // 获取传递过来的数据
- private void getValue() {
- from = getIntent().getStringExtra("from");
- if ("edit".equals(from)) {
- id = getIntent().getIntExtra("id", 0);
- name = getIntent().getStringExtra("name");
- number = getIntent().getStringExtra("number");
- avatar = getIntent().getStringExtra("avatar");
- e_mail = getIntent().getStringExtra("e-mail");
- remark = getIntent().getStringExtra("remark");
- unit_information = getIntent().getStringExtra("unit_information");
- // 对可能为null的字符串进行默认值处理
- if (e_mail == null) e_mail = "无";
- if (remark == null) remark = "无";
- if (unit_information == null) unit_information = "无";
- }
- }
- // 设置视图内容
- private void setView() {
- if ("edit".equals(from)) {
- et_xingming.setText(name);
- et_dianhuahaoma.setText(number);
- et_dianziyoujian.setText(e_mail);
- et_beizhu.setText(remark);
- et_danweixinxi.setText(unit_information);
- }
- }
- // 初始化并设置Spinner适配器
- private void setupSpinner() {
- // 准备数据
- data = getListData();
- // 创建SimpleAdapter并设置给Spinner
- SimpleAdapter simpleAdapter = new SimpleAdapter(
- this,
- data,
- R.layout.spinner_item, // 自定义布局
- new String[]{"touxiang"}, // 数据源中的键
- new int[]{R.id.imageView} // 布局中的ID
- );
- spinner.setAdapter(simpleAdapter);
- // 设置Spinner选择监听器
- spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- // 获取选中的项并设置给selectedImageResource
- Map<String, Integer> selectedItem = (Map<String, Integer>) parent.getItemAtPosition(position);
- selectedImageResource = selectedItem.get("touxiang");
- }
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- // 不执行任何操作
- }
- });
- }
- // 获取Spinner列表数据
- private List<Map<String, Integer>> getListData() {
- List<Map<String, Integer>> list = new ArrayList<>();
- int[] touxiangResources = {
- R.drawable.touxiang1, R.drawable.touxiang2, R.drawable.touxiang3,
- R.drawable.touxiang4, R.drawable.touxiang5, R.drawable.touxiang6
- };
- for (int resource : touxiangResources) {
- Map<String, Integer> item = new HashMap<>();
- item.put("touxiang", resource);
- // 如果是编辑模式且当前资源是选中的头像,则将其添加到列表的开头
- if ("edit".equals(from) && resource == Integer.parseInt(avatar)) {
- list.add(0, item);
- } else {
- list.add(item);
- }
- }
- return list;
- }
- // 数据库帮助器的初始化与关闭
- @Override
- protected void onStart() {
- super.onStart();
- mHelper = UserDBHelper.getInstance(this);
- mHelper.getReadableDatabase(); // 通常不需要显式调用,除非需要立即访问
- mHelper.getWritableDatabase(); // 同上
- }
- @Override
- protected void onStop() {
- super.onStop();
- if (mHelper != null) {
- mHelper.close();
- }
- }
- // 点击事件处理
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.ib_back:
- finish();
- break;
- case R.id.btn_tianjia:
- // 获取输入框内容并进行校验
- String et_name = et_xingming.getText().toString().trim();
- String et_phone = et_dianhuahaoma.getText().toString().trim();
- String et_email = et_dianziyoujian.getText().toString().trim();
- String et_remark = et_beizhu.getText().toString().trim();
- String et_unitInfo = et_danweixinxi.getText().toString().trim();
- // 对空值或无效输入进行处理
- if (TextUtils.isEmpty(et_name)) {
- Toast.makeText(this, "请输入姓名", Toast.LENGTH_SHORT).show();
- } else if (TextUtils.isEmpty(et_phone) || !et_phone.matches("\\d+")) {
- Toast.makeText(this, "请输入有效的电话号码", Toast.LENGTH_SHORT).show();
- } else {
- // 创建联系人对象并保存
- Contacter contacter = new Contacter(
- et_name, et_phone, et_email, et_remark, et_unitInfo,
- selectedImageResource != null ? selectedImageResource.toString() : null
- );
- if ("edit".equals(from)) {
- // 更新联系人
- if (mHelper.updateContact(id, contacter) > 0) {
- Toast.makeText(this, "修改成功", Toast.LENGTH_SHORT).show();
- finish();
- } else {
- Toast.makeText(this, "修改失败", Toast.LENGTH_SHORT).show();
- }
- } else if ("add".equals(from)) {
- // 添加联系人
- if (mHelper.insert(contacter) > 0) {
- Toast.makeText(this, "添加成功", Toast.LENGTH_SHORT).show();
- finish();
- } else {
- Toast.makeText(this, "添加失败", Toast.LENGTH_SHORT).show();
- }
- }
- }
- break;
- default:
- break;
- }
- }
- }
复制代码 Contacter.java
- package com.example.theseventhexperiment;
- public class Contacter {
- public int id;
- public String name;
- public String phonenumber;//存储电话号码
- public String e_mail;
- public String remark;
- public String unit_information;
- public String avatar;//存储头像资源id
- public String beginZ;//第一个字母
- public Contacter(int id, String name, String phonenumber, String e_mail, String remark, String unit_information, String avatar, String beginZ) {
- this.id = id;
- this.name = name;
- this.phonenumber = phonenumber;
- this.e_mail = e_mail;
- this.remark = remark;
- this.unit_information = unit_information;
- this.avatar = avatar;
- this.beginZ = beginZ;
- }
- public Contacter(String name, String phonenumber, String e_mail, String remark, String unit_information, String avatar) {
- this.name = name;
- this.phonenumber = phonenumber;
- this.e_mail = e_mail;
- this.remark = remark;
- this.unit_information = unit_information;
- this.beginZ = beginZ;
- this.avatar = avatar;
- }
- public String getAvatar() {
- return avatar;
- }
- public void setAvatar(String avatar) {
- this.avatar = avatar;
- }
- public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getPhonenumber() {
- return phonenumber;
- }
- public void setPhonenumber(String phonenumber) {
- this.phonenumber = phonenumber;
- }
- public String getE_mail() {
- return e_mail;
- }
- public void setE_mail(String e_mail) {
- this.e_mail = e_mail;
- }
- public String getRemark() {
- return remark;
- }
- public void setRemark(String remark) {
- this.remark = remark;
- }
- public String getUnit_information() {
- return unit_information;
- }
- public void setUnit_information(String unit_information) {
- this.unit_information = unit_information;
- }
- public String getBeginZ() {
- return beginZ;
- }
- public void setBeginZ(String beginZ) {
- this.beginZ = beginZ;
- }
- @Override
- public String toString() {
- return "Contacter{" +
- "id=" + id +
- ", name='" + name + '\'' +
- ", phonenumber=" + phonenumber +
- ", e_mail='" + e_mail + '\'' +
- ", remark='" + remark + '\'' +
- ", unit_information='" + unit_information + '\'' +
- ", beginZ='" + beginZ + '\'' +
- '}';
- }
- }
复制代码 ContacterAdpter.java
- package com.example.theseventhexperiment;
- import android.content.Context;
- import android.os.Build;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.ArrayAdapter;
- import android.widget.ImageView;
- import android.widget.TextView;
- import androidx.annotation.NonNull;
- import androidx.annotation.Nullable;
- import androidx.annotation.RequiresApi;
- import java.util.List;
- // 自定义的适配器类,用于显示联系人列表
- public class ContacterAdpter extends ArrayAdapter<Contacter> {
- List<Contacter> items;
- public ContacterAdpter(Context context, List<Contacter> items) {
- super(context, R.layout.lian_xi_ren_bu_ju, items);
- this.items = items;
- }
- // 重写getView方法,用于根据位置获取视图
- @RequiresApi(api = Build.VERSION_CODES.N)
- @NonNull
- @Override
- public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
- // ViewHolder模式,用于优化性能,减少findViewById的调用
- ViewHolder holder;
- // 如果convertView为空,说明需要创建新的视图
- if (convertView == null) {
- LayoutInflater layoutInflater = LayoutInflater.from(getContext());
- convertView = layoutInflater.inflate(R.layout.lian_xi_ren_bu_ju, parent, false);
- holder = new ViewHolder();
- holder.iv_touxiang = convertView.findViewById(R.id.iv_touxiang); // 头像ImageView
- holder.tv_xingming = convertView.findViewById(R.id.tv_xingming); // 姓名TextView
- holder.tv_zimu = convertView.findViewById(R.id.tv_zimu); // 首字母TextView
- // 将ViewHolder对象保存在convertView的tag中,以便复用
- convertView.setTag(holder);
- } else {
- // 如果convertView不为空,则直接获取ViewHolder对象
- holder = (ViewHolder) convertView.getTag();
- }
- // 获取当前位置的联系人对象
- Contacter contacter = items.get(position);
- // 设置姓名
- holder.tv_xingming.setText(contacter.getName());
- // 设置头像,这里假设头像资源是以字符串形式存储的整数ID
- holder.iv_touxiang.setImageResource(Integer.parseInt(contacter.getAvatar()));
- // 判断是否需要显示首字母
- // 如果当前位置是第一个或者当前联系人的首字母与前一个不同,则显示首字母
- if (position == 0 || !items.get(position - 1).getBeginZ().equals(contacter.getBeginZ())) {
- holder.tv_zimu.setText(contacter.getBeginZ());
- holder.tv_zimu.setVisibility(View.VISIBLE);
- } else {
- // 否则隐藏首字母
- holder.tv_zimu.setVisibility(View.GONE);
- }
- // 返回当前位置的视图
- return convertView;
- }
- // ViewHolder类,用于缓存视图引用,提高性能
- private static class ViewHolder {
- ImageView iv_touxiang; // 头像ImageView
- TextView tv_xingming; // 姓名TextView
- TextView tv_zimu; // 首字母TextView
- }
- }
复制代码 ContactInformationActivity.java
- package com.example.theseventhexperiment;
- import android.app.AlertDialog;
- import android.content.DialogInterface;
- import android.content.Intent;
- import android.net.Uri;
- import android.os.Bundle;
- import android.view.View;
- import android.widget.Button;
- import android.widget.ImageButton;
- import android.widget.ImageView;
- import android.widget.TextView;
- import android.widget.Toast;
- import androidx.appcompat.app.AppCompatActivity;
- // ContactInformationActivity 类用于显示联系人详细信息并提供相关操作
- public class ContactInformationActivity extends AppCompatActivity implements View.OnClickListener {
- // 视图元素
- private ImageButton btn_back;
- private TextView tv_xingming, tv_number, tv_dianziyoujian, tv_beizhu, tv_danweixinxi;
- private ImageView iv_touxiang;
- private Button btn_shanchu, btn_dadianhua, btn_faxinxi, btn_bianji;
- // 数据库帮助类实例
- private UserDBHelper dbHelper;
- // 联系人信息变量
- private String name, e_mail, remark, unit_information, number, avatar;
- private int id;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_contact_information);
- // 初始化视图元素
- initView();
- // 设置点击事件监听器
- setListener();
- // 从 Intent 中获取联系人信息
- getValueFromIntent();
- // 设置视图显示内容
- setView();
- }
- // 从 Intent 中获取联系人信息的方法
- private void getValueFromIntent() {
- id = getIntent().getIntExtra("id", 0);
- name = getIntent().getStringExtra("name");
- number = getIntent().getStringExtra("number");
- avatar = getIntent().getStringExtra("avatar");
- e_mail = getIntent().getStringExtra("e-mail");
- if (e_mail == null) {
- e_mail = "无";
- }
- remark = getIntent().getStringExtra("remark");
- if (remark == null) {
- remark = "无";
- }
- unit_information = getIntent().getStringExtra("unit_information");
- if (unit_information == null) {
- unit_information = "无";
- }
- }
- // 设置点击事件监听器的方法
- private void setListener() {
- btn_back.setOnClickListener(this);
- btn_shanchu.setOnClickListener(this);
- btn_dadianhua.setOnClickListener(this);
- btn_faxinxi.setOnClickListener(this);
- btn_bianji.setOnClickListener(this);
- }
- // 设置视图显示内容的方法
- private void setView() {
- tv_xingming.setText("姓名:" + name);
- tv_number.setText("电话号码:" + number);
- // 注意:这里假设 avatar 是一个资源 ID,如果 avatar 是 URL 或文件路径,需要相应处理
- iv_touxiang.setImageResource(Integer.parseInt(avatar));
- tv_beizhu.setText("备注:" + remark);
- tv_danweixinxi.setText("单位信息:" + unit_information);
- tv_dianziyoujian.setText("电子邮件:" + e_mail);
- }
- // 初始化视图元素的方法
- private void initView() {
- tv_xingming = findViewById(R.id.tv_datail_xingming);
- tv_number = findViewById(R.id.tv_detail_dianhuahaoma);
- tv_dianziyoujian = findViewById(R.id.tv_detail_dianziyoujian);
- tv_beizhu = findViewById(R.id.tv_detail_beizhu);
- tv_danweixinxi = findViewById(R.id.tv_detail_danweixinxi);
- btn_back = findViewById(R.id.ib_detail_back);
- btn_dadianhua = findViewById(R.id.btn_dadianhua);
- btn_faxinxi = findViewById(R.id.btn_faxiaoxi);
- btn_bianji = findViewById(R.id.btn_bianji);
- iv_touxiang = findViewById(R.id.iv_detail_touxiang);
- btn_shanchu = findViewById(R.id.btn_shanchu);
- // 初始化数据库帮助类实例
- dbHelper = UserDBHelper.getInstance(this);
- }
- // 点击事件处理方法
- @Override
- public void onClick(View v) {
- Intent intent = new Intent();
- switch (v.getId()) {
- case R.id.ib_detail_back:
- // 返回上一个界面
- intent.putExtra("from","detail");
- finish();
- break;
- case R.id.btn_shanchu:
- // 显示删除确认对话框
- showDeleteConfirmDialog();
- break;
- case R.id.btn_dadianhua:
- // 拨打电话
- intent.setAction(Intent.ACTION_DIAL);
- intent.setData(Uri.parse("tel:" + number));
- startActivity(intent);
- break;
- case R.id.btn_faxiaoxi:
- // 发送短信
- intent.setAction(Intent.ACTION_SENDTO);
- intent.setData(Uri.parse("smsto:" + number));
- startActivity(intent);
- break;
- case R.id.btn_bianji:
- // 编辑联系人信息
- intent = new Intent(ContactInformationActivity.this, AddContactActivity.class);
- intent.putExtra("id", id);
- intent.putExtra("name", name);
- intent.putExtra("e-mail", e_mail);
- intent.putExtra("remark", remark);
- intent.putExtra("unit_information", unit_information);
- intent.putExtra("number", number);
- intent.putExtra("avatar", avatar);
- intent.putExtra("from", "edit");
- startActivity(intent);
- finish();
- break;
- default:
- break;
- }
- }
- // 显示删除确认对话框的方法
- private void showDeleteConfirmDialog() {
- if (id != 0) { // 假设 0 是一个无效或未设置的 ID 值
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle("确认删除")
- .setMessage("您确定要删除该联系人吗?")
- .setCancelable(false)
- .setPositiveButton("确定", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- int numberOfContactsBefore = dbHelper.numberOfContacts();
- dbHelper.deleteContactById(id);
- int numberOfContactsAfter = dbHelper.numberOfContacts();
- if (numberOfContactsBefore - 1 == numberOfContactsAfter) {
- Toast.makeText(ContactInformationActivity.this, "删除成功", Toast.LENGTH_SHORT).show();
- finish();
- } else {
- Toast.makeText(ContactInformationActivity.this, "删除失败,可能是 ID 错误或数据库问题", Toast.LENGTH_SHORT).show();
- }
- }
- })
- .setNegativeButton("取消", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dialog.cancel();
- }
- });
- AlertDialog alert = builder.create();
- alert.show();
- } else {
- Toast.makeText(this, "无效的 ID", Toast.LENGTH_SHORT).show();
- }
- }
- }
复制代码 GteDataFromDatabase.java
- package com.example.theseventhexperiment;
- import android.content.Context;
- import android.database.Cursor;
- import android.database.sqlite.SQLiteDatabase;
- import com.hankcs.hanlp.HanLP;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
- public class GteDataFromDatabase {
- // 声明数据库实例和数据库帮助类实例
- private static SQLiteDatabase db;
- private static UserDBHelper userDBHelper;
- /**
- * 从数据库中获取所有联系人信息的方法
- *
- * @param context 上下文对象,用于访问数据库
- * @return 包含所有联系人信息的列表
- */
- public static List<Contacter> getAllContacts(Context context) {
- List<Contacter> list = new ArrayList<>(); // 创建联系人列表
- // 初始化数据库帮助类并获取可读数据库
- userDBHelper = new UserDBHelper(context);
- db = userDBHelper.getReadableDatabase();
- // 定义正则表达式用于匹配中文字符
- String regex = "[\\u4e00-\\u9fa5]+";
- // 执行SQL查询,获取所有联系人信息
- Cursor res = db.rawQuery("SELECT * FROM contacter_info", null);
- try {
- while (res.moveToNext()) { // 遍历查询结果
- // 从Cursor中提取联系人信息
- String id = res.getString(res.getColumnIndexOrThrow("_id")); // 联系人ID
- String name = res.getString(res.getColumnIndexOrThrow("name")); // 联系人姓名
- String phonenumber = res.getString(res.getColumnIndexOrThrow("phonenumber")); // 联系人电话
- String e_mail = res.getString(res.getColumnIndexOrThrow("e_mail")); // 联系人邮箱
- String remark = res.getString(res.getColumnIndexOrThrow("remark")); // 联系人备注
- String unit_information = res.getString(res.getColumnIndexOrThrow("unit_information")); // 联系人单位信息
- // 注意:原代码中avater可能是拼写错误,这里保留原样,但建议检查数据库表结构
- String avatar = res.getString(res.getColumnIndexOrThrow("avater")); // 联系人头像
- // 创建Contacter对象并设置属性
- Contacter contacter = new Contacter(
- Integer.parseInt(id),
- name,
- phonenumber,
- e_mail,
- remark,
- unit_information,
- avatar,
- ""
- );
- // 设置联系人姓名的首字母或拼音首字母
- String firstNameChar = name.substring(0, 1); // 获取姓名的第一个字符
- boolean isAlphabetic = firstNameChar.matches("^[a-zA-Z]*"); // 判断是否为英文字母
- if (isAlphabetic) {
- // 如果是英文字母,则直接设置为大写
- contacter.setBeginZ(firstNameChar.toUpperCase());
- } else {
- // 如果不是英文字母,则检查是否为中文字符
- Pattern pattern = Pattern.compile(regex);
- Matcher matcher = pattern.matcher(firstNameChar);
- if (matcher.find()) {
- // 如果是中文字符,则转换为拼音并设置首字母大写
- String pinyin = HanLP.convertToPinyinString(firstNameChar, "", false);
- contacter.setBeginZ(pinyin.substring(0, 1).toUpperCase());
- } else {
- // 如果既不是英文字母也不是中文字符,则设置为"#"
- contacter.setBeginZ("#");
- }
- }
- // 将Contacter对象添加到列表中
- list.add(contacter);
- }
- } finally {
- // 关闭Cursor以释放资源
- if (res != null) {
- res.close();
- }
- }
- // 返回联系人列表
- return list;
- }
- }
复制代码 MainActivity.java
- package com.example.theseventhexperiment;
- import android.content.Intent;
- import android.database.sqlite.SQLiteDatabase;
- import android.os.Build;
- import android.os.Bundle;
- import android.text.Editable;
- import android.text.TextWatcher;
- import android.view.MotionEvent;
- import android.view.View;
- import android.widget.AdapterView;
- import android.widget.EditText;
- import android.widget.ImageButton;
- import android.widget.ListView;
- import androidx.annotation.RequiresApi;
- import androidx.appcompat.app.AppCompatActivity;
- import java.util.ArrayList;
- import java.util.Comparator;
- import java.util.List;
- public class MainActivity extends AppCompatActivity implements View.OnClickListener {
- // 数据库相关变量
- SQLiteDatabase db;
- UserDBHelper userDBHelper;
- // 适配器和视图组件
- ContacterAdpter contacterAdpter;
- EditText ed_sousuo; // 搜索框
- ListView listView; // 联系人列表
- ImageButton ib_tianjialianxiren; // 添加联系人按钮
- @RequiresApi(api = Build.VERSION_CODES.N)
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- // 初始化视图组件
- initView();
- // 设置事件监听器
- setListener();
- // 加载联系人列表
- loadViewlist();
- }
- @RequiresApi(api = Build.VERSION_CODES.N)
- @Override
- protected void onResume() {
- super.onResume();
- // 当活动恢复时重新加载联系人列表
- ed_sousuo.setText("");//把搜索栏内容清空
- loadViewlist();
- }
- /**
- * 从数据库加载联系人列表并更新UI
- */
- @RequiresApi(api = Build.VERSION_CODES.N)
- private void loadViewlist() {
- int number = userDBHelper.numberOfContacts();
- String hind = "在" + number + "位联系人中搜索";
- ed_sousuo.setHint(hind);
- List<Contacter> result = GteDataFromDatabase.getAllContacts(this);
- // 如果联系人列表为空,则创建一个空适配器
- if (result.isEmpty()) {
- contacterAdpter = new ContacterAdpter(this, new ArrayList<>());
- } else {
- // 否则,对联系人列表进行排序并设置适配器
- sort(result);
- contacterAdpter = new ContacterAdpter(this, result);
- }
- // 为listView设置适配器
- listView.setAdapter(contacterAdpter);
- }
- /**
- * 设置事件监听器
- */
- private void setListener() {
- // 添加联系人按钮点击事件
- ib_tianjialianxiren.setOnClickListener(this);
- // 联系人列表点击事件
- listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- Contacter clickedContacter = contacterAdpter.getItem(position);
- Intent intent = new Intent(MainActivity.this, ContactInformationActivity.class);
- intent.putExtra("id", clickedContacter.getId());
- intent.putExtra("name", clickedContacter.getName());
- intent.putExtra("e-mail", clickedContacter.getE_mail());
- intent.putExtra("remark", clickedContacter.getRemark());
- intent.putExtra("unit_information", clickedContacter.getUnit_information());
- intent.putExtra("number", clickedContacter.getPhonenumber());
- intent.putExtra("avatar", clickedContacter.getAvatar());
- startActivity(intent);
- }
- });
- // 搜索框触摸事件(用于搜索功能)
- ed_sousuo.setOnTouchListener(new View.OnTouchListener() {
- @RequiresApi(api = Build.VERSION_CODES.N)
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- // 这里逻辑已经被下面的TextWatcher替代,可以移除
- return false;
- }
- });
- // 搜索框文本变化监听器(用于实时搜索)
- ed_sousuo.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {}
- @RequiresApi(api = Build.VERSION_CODES.N)
- @Override
- public void afterTextChanged(Editable s) {
- String searchText = s.toString();
- List<Contacter> searchResult = UserDBHelper.Search(MainActivity.this, searchText);
- // 更新适配器并设置到listView
- if (searchResult == null || searchResult.isEmpty()) {
- contacterAdpter = new ContacterAdpter(MainActivity.this, new ArrayList<>());
- } else {
- sort(searchResult);
- contacterAdpter = new ContacterAdpter(MainActivity.this, searchResult);
- }
- listView.setAdapter(contacterAdpter);
- }
- });
- }
- /**
- * 初始化视图组件
- */
- private void initView() {
- ib_tianjialianxiren = findViewById(R.id.ib_tianjialianxiren);
- userDBHelper = new UserDBHelper(this);
- db = userDBHelper.getReadableDatabase();
- ed_sousuo = findViewById(R.id.et_sousuo);
- listView = findViewById(R.id.lv_lianxiren);
- }
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(this, AddContactActivity.class);
- intent.putExtra("from", "add");
- startActivity(intent);
- }
- /**
- * 对联系人列表按拼音首字母排序
- */
- @RequiresApi(api = Build.VERSION_CODES.N)
- public void sort(List<Contacter> contacterList) {
- contacterList.sort(new Comparator<Contacter>() {
- @Override
- public int compare(Contacter c1, Contacter c2) {
- String beginZ1 = c1.getBeginZ();
- String beginZ2 = c2.getBeginZ();
- // 特殊处理"#"开头的联系人,通常表示未设置拼音首字母
- if ("#".equals(beginZ1) && "#".equals(beginZ2)) {
- return 0;
- }
- if ("#".equals(beginZ1)) {
- return 1;
- }
- if ("#".equals(beginZ2)) {
- return -1;
- }
- return beginZ1.compareTo(beginZ2);
- }
- });
- }
- }
复制代码 UserDBHelper.java
- package com.example.theseventhexperiment;
- import android.content.ContentValues;
- import android.content.Context;
- import android.database.Cursor;
- import android.database.sqlite.SQLiteDatabase;
- import android.database.sqlite.SQLiteOpenHelper;
- import com.hankcs.hanlp.HanLP;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
- public class UserDBHelper extends SQLiteOpenHelper {
- private static final String DB_NAME = "contact_db.db";
- private static final String TABLE_NAME = "contacter_info";
- private static final int VERSION = 1;
- public static SQLiteDatabase db = null;
- private static UserDBHelper mHelper = null;
- public UserDBHelper(Context context) {
- super(context, DB_NAME, null, VERSION);
- }
- public static UserDBHelper getInstance(Context context) {
- if (mHelper == null) {
- mHelper = new UserDBHelper(context);
- }
- return mHelper;
- }
- public static List<Contacter> Search(Context context, String what) {
- List<Contacter> list = new ArrayList<>();
- mHelper = new UserDBHelper(context);
- String sql = "SELECT * FROM " + TABLE_NAME + " WHERE name LIKE '%" + what + "%' OR phonenumber LIKE '%" + what + "%'";
- db = mHelper.getReadableDatabase();
- String regex = "[\\u4e00-\\u9fa5]+";
- Cursor res = null;
- res = db.rawQuery(sql, null);
- while (res.moveToNext()) {
- String id = res.getString(res.getColumnIndexOrThrow("_id")); // 使用列名更安全
- String name = res.getString(res.getColumnIndexOrThrow("name"));
- String phonenumber = res.getString(res.getColumnIndexOrThrow("phonenumber")); // 注意这里应该是字符串
- String e_mail = res.getString(res.getColumnIndexOrThrow("e_mail"));
- String remark = res.getString(res.getColumnIndexOrThrow("remark"));
- String unit_information = res.getString(res.getColumnIndexOrThrow("unit_information"));
- String avatar = res.getString(res.getColumnIndexOrThrow("avater"));
- Contacter contacter = new Contacter(
- Integer.parseInt(id),
- name,
- phonenumber,
- e_mail,
- remark,
- unit_information,
- avatar,
- ""
- );
- String first = name.substring(0, 1);
- boolean re = first.matches("^[a-zA-Z]*");
- if (re) {
- contacter.setBeginZ(first.toUpperCase());
- } else {
- Pattern pattern = Pattern.compile(regex);
- Matcher matcher = pattern.matcher(first);
- if (matcher.find()) {
- String pinyin = HanLP.convertToPinyinString(first, "", false);
- contacter.setBeginZ(pinyin.substring(0, 1).toUpperCase());
- } else {
- contacter.setBeginZ("#");
- }
- }
- list.add(contacter);
- }
- return list;
- }
- @Override
- public void onCreate(SQLiteDatabase db) {
- String sql = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + "(" +
- "_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," +
- "name VARCHAR NOT NULL," +
- "phonenumber VARCHAR NOT NULL," +
- "e_mail VARCHAR," +
- "remark VARCHAR," +
- "unit_information VARCHAR," +
- "avater VARCHAR NOT NULL);";
- db.execSQL(sql);
- }
- public void deleteContactById(long id) {
- SQLiteDatabase db = getWritableDatabase(); // 获取可写的数据库连接
- String selection = "_id = ?"; // 删除条件
- String[] selectionArgs = {String.valueOf(id)}; // 删除条件参数
- db.delete(TABLE_NAME, selection, selectionArgs); // 执行删除操作
- }
- public void closeLink() {
- if (db != null && db.isOpen()) {
- db.close();
- db = null;
- }
- }
- public long insert(Contacter contacter) {
- ContentValues values = new ContentValues();
- SQLiteDatabase db = this.getWritableDatabase();
- values.put("name", contacter.name);
- values.put("phonenumber", contacter.phonenumber);
- values.put("e_mail", contacter.e_mail);
- values.put("remark", contacter.remark);
- values.put("unit_information", contacter.unit_information);
- values.put("avater", contacter.avatar);
- return db.insert(TABLE_NAME, null, values);
- }
- public int numberOfContacts() {
- SQLiteDatabase db = this.getReadableDatabase();
- String countQuery = "SELECT COUNT(*) FROM " + TABLE_NAME;
- Cursor cursor = db.rawQuery(countQuery, null);
- int count = 0;
- if (cursor.moveToFirst()) {
- count = cursor.getInt(0);
- }
- cursor.close();
- return count;
- }
- public int updateContact(int id, Contacter contacter) {
- SQLiteDatabase db = getWritableDatabase();
- String selection = "_id = ?";
- String[] selectionArgs = {String.valueOf(id)};
- ContentValues values = new ContentValues();
- values.put("name", contacter.name);
- values.put("phonenumber", contacter.phonenumber); // 这里可能需要类型转换,但因为我们假设它是 int,所以不需要
- values.put("e_mail", contacter.e_mail);
- values.put("remark", contacter.remark);
- values.put("unit_information", contacter.unit_information);
- values.put("avater", contacter.avatar);
- int rowsAffected = db.update(TABLE_NAME, values, selection, selectionArgs);
- return rowsAffected;
- }
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- onCreate(db);
- }
- }
复制代码 add.xml
- <?xml version="1.0" encoding="utf-8"?>
- <vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="80dp"
- android:height="80dp"
- android:alpha="0.8"
- android:tint="#337AE5"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <group
- android:scaleX="1.1111112"
- android:scaleY="1.1111112"
- android:translateX="-1.3333334"
- android:translateY="-1.3333334">
- <path
- android:fillColor="#000000"
- android:pathData="M13,7h-2v4L7,11v2h4v4h2v-4h4v-2h-4L13,7zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z" />
- </group>
- </vector>
复制代码 back.xml
- <?xml version="1.0" encoding="utf-8"?>
- <vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="50dp"
- android:height="50dp"
- android:viewportWidth="24"
- android:viewportHeight="24"
- android:tint="#3374E5"
- android:alpha="0.8">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
- </vector>
复制代码 sou_suo_kuang.xml
- <?xml version="1.0" encoding="utf-8"?>
- <selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item>
- <shape>
- <solid android:color="#EFEDED"></solid>
- <corners android:radius="10dp"></corners>
- </shape>
- </item>
- </selector>
复制代码 stype.xml
- <?xml version="1.0" encoding="utf-8"?>
- <layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
- <item>
- <shape>
- <stroke
- android:width="0dp"
- android:color="#00FF0000" />
- <padding
- android:bottom="0dp"
- android:left="0dp"
- android:right="0dp"
- android:top="0dp" />
- </shape>
- </item>
- </layer-list>
复制代码 activity_add_contact.xml
activity_contact_information.xml
activity_main.xml
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout 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"
- android:orientation="vertical"
- tools:context=".MainActivity">
- <EditText
- android:id="@+id/et_sousuo"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="5dp"
- android:layout_marginTop="10dp"
- android:layout_marginRight="5dp"
- android:background="@drawable/sou_suo_kuang"
- android:drawableLeft="@drawable/sousuo"
- android:textColor="#4D4F60"
- android:textSize="30sp" />
- <ListView
- android:id="@+id/lv_lianxiren"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/et_sousuo"
- android:layout_weight="1" />
- <ImageButton
- android:id="@+id/ib_tianjialianxiren"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_alignParentBottom="true"
- android:layout_marginRight="20dp"
- android:layout_marginBottom="80dp"
- android:background="#00FF0000"
- android:src="@drawable/add" />
- </RelativeLayout>
复制代码 lian_xi_ren_bu_ju.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
- <TextView
- android:id="@+id/tv_zimu"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingLeft="20dp"
- android:text="A"
- android:textSize="30sp" />
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:padding="10dp">
- <ImageView
- android:id="@+id/iv_touxiang"
- android:layout_width="80dp"
- android:layout_height="80dp"
- android:src="@color/black" />
- <TextView
- android:id="@+id/tv_xingming"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingLeft="10dp"
- android:paddingTop="4dp"
- android:textSize="50sp" />
- </LinearLayout>
- </LinearLayout>
复制代码 spinner_item.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:orientation="horizontal">
- <ImageView
- android:id="@+id/imageView"
- android:layout_width="120dp"
- android:layout_height="120dp"
- android:layout_margin="8dp" />
- </LinearLayout>
复制代码 AndroidManifest.xml
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.theseventhexperiment">
- <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:roundIcon="@mipmap/ic_launcher_round"
- android:supportsRtl="true"
- android:theme="@style/Theme.TheSeventhExperiment">
- <activity android:name=".ContactInformationActivity"></activity>
- <activity android:name=".AddContactActivity" />
- <activity android:name=".MainActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
- </manifest>
复制代码 干系操纵:
switch语句报错:https://blog.csdn.net/mjh1667002013/article/details/134763804
办理Android虚拟机启动时System UI isn‘t responding错误_system ui isn't responding-CSDN博客
汉语言处理处罚包HanLP下载地址:Maven Repository: com.hankcs » hanlp » portable-1.8.4 (mvnrepository.com)
导入jar包教程(假如没有libs文件夹就创建一个):
https://blog.csdn.net/weixin_46409629/article/details/129414986?app_version=6.2.8&code=app_1562916241&csdn_share_tail=%7B%22
项目存在的问题:
1.spinner下拉图标(白色的,所以看不见)遮挡图片问题,如下图,为了美观没有使用填满颜色图片,spinner的设置在stype.xml文件内,必要再设计.
2.数据库有时报错:
Database Inspector:
Error reading Sqlite database: Database 'LiveSqliteDatabaseId(path=/data/data/com.example.theseventhexperiment/databases/contact_db.db, name=contact_db.db, connectionId=1) not found
但是项目仍可正常运行,推测是版本问题或者数据库没有及时断开毗连
3.运行卡顿问题,代码待优化
工程文件:
通过网盘分享的文件:TheSeventhExperiment.zip
链接: https://pan.baidu.com/s/1gLrwrdai95-mHhRDfBieXw?pwd=h42a提取码: h42a
gitee:android studio: 移动应用开发实验代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |