一.首先写好布局文件主界面布局 activity_main.xml(为了方便大家,这里就直接贴代码了)
列表项布局 list_item.xml(会提示缺少文件,那么我们需要把压缩包里面的文件注入到res/drawable目录下)
二.联系人信息实体类 Contact.java代码如下3
class Contact { //自定义的实体类
private String name;
private String phone;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "Contact{" + "name='" + name + ''' + ", phone='" + phone + ''' + '}';
}
}
三.对应于列表项的视图类 ListItemView.java代码如下(直接在MainActivity所在的文件目录粘贴即可)
public class ListItemView {
ImageView iv_PersonPicture; //图像
TextView tv_NameAndPhone; //姓名和手机号
CheckBox checkBox; //复选框
}
四.建立继承抽象类baseAdapter的子类 ChooseAdapter.java,除了重写四个抽象方法外,还要自定义一个用于响应勾选而动态刷新界面视图的方法refresh()。
public class ChooseAdapter extends baseAdapter {
List listData; //联系人列表数据,实体类Contact仅包含name和phone两个字段
LayoutInflater layoutInflater; //布局充气筒
HashMap map = new HashMap();
// 可以改写成显示联系人照片;,在MainActivity中要访问本类成员,因此,staitc修饰必须。
static final int[] icons = {R.drawable.male, R.drawable.male}; //全局常量
static Map checkResult; //记录勾选结果;全局变量
public ChooseAdapter(Context context, List listData) { //构造方法
layoutInflater = LayoutInflater.from(context);
this.listData = listData;
checkResult = new HashMap();
for (int i = 0; i < listData.size(); i++) {
checkResult.put(i, false); //默认全部未选择,作用相当于一个数组
}
}
@Override
public int getCount() {
return listData.size();
}
@Override
public Object getItem(int position) {
return listData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ListItemView listItemView = null;
if (convertView == null) {
//获取list_item布局文件的视图
convertView = layoutInflater.inflate(R.layout.list_item, null);
//创建与布局R.layout.list_item对应的视图对象
listItemView = new ListItemView();
listItemView.iv_PersonPicture = convertView.findViewById(R.id.iv_PersonPicture);
listItemView.tv_NameAndPhone = convertView.findViewById(R.id.tv_NameAndPhone);
listItemView.checkBox = convertView.findViewById(R.id.checkBox);
map.put(position, convertView);// 设置控件集到convertView
//贴个标签
convertView.setTag(listItemView);
} else {
//取出原来使用方法setTag()贴的标签
listItemView = (ListItemView) convertView.getTag();
}
Contact contactInfo = listData.get(position); //联系人信息
listItemView.iv_PersonPicture.setImageResource(icons[0]);
listItemView.tv_NameAndPhone.setText(contactInfo.getName() + " " + contactInfo.getPhone());
listItemView.checkBox.setChecked(checkResult.get(position)); //Map集合
return convertView;
}
//响应MainActivity中的勾选操作(供调用),实时刷新视图
public void refresh(List listData) {
this.listData = listData;
//适配器的内容改变了,通过下面的方法强制调用getView()来刷新每个Item的内容
notifyDataSetChanged();
}
}
五.权限:(全局目录下加入)
六.界面程序MainActivity.java
程序架构:
public class MainActivity extends AppCompatActivity implements View.onClickListener {
final Uri uri=ContactsContract.Contacts.CONTENT_URI; //Android联系人uri
ListView listView; //列表控件
ChooseAdapter myAdapter; //列表适配器
List contacts; //存放联系人列表(姓名+手机号),
List receiverName = new ArrayList(); //短信接收人的姓名
List receiverPhone = new ArrayList(); //短信接收人的手机号
String receiverPhones; //短信接收人的手机号字符串,中间以分号分隔
ImageView backBtn; //作为返回按钮
ImageView imageButton; //作为选择确认按钮
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);//取消对应用程序标题栏的显示
setContentView(R.layout.activity_main);
//权限处理
if (ContextCompat.checkSelfPermission(this,Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.READ_CONTACTS},1);
}else {
new GetContact().execute(); // 调用内部类,执行异步任务,获得联系人
//getContacts();initView(); //阻塞式、耗时,联系人个数较多时出现白屏
}
//控件对象监听
backBtn = findViewById(R.id.onBack);backBtn.setonClickListener(this);
imageButton = findViewById(R.id.imageButton);imageButton.setonClickListener(this);
contacts = new ArrayList();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode){
case 1:
if(grantResults.length>0){
for(int result : grantResults){
if(result != PackageManager.PERMISSION_GRANTED){
Toast.makeText(this, "权限不足!", Toast.LENGTH_SHORT).show();
finish();
return;
}
}
}
new GetContact().execute(); //执行异步线程
break;
}
}
@Override //监听实现按钮功能的两个图像
public void onClick(View arg0) {
switch (arg0.getId()) {
case R.id.onBack:
finish();
break;
case R.id.imageButton:
setMessageToSome(); //向选择的联系人群发短信
break;
}
}
//考虑到目前手机联系人数量日前增多,使用异步任务类以免阻塞UI主线程
class GetContact extends AsyncTask {
@Override
protected void onPreExecute() {
super.onPreExecute();
Toast.makeText(MainActivity.this, "联系人信息加载中,稍候...", Toast.LENGTH_SHORT).show();
}
@Override
protected String doInBackground(String... arg0) { //接收单个值或数组,还可以接收离散变量
getContacts();//获取所有联系人并存放至contacts
return null;
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
initView(); //呈现视图
}
}
private void getContacts() { //获得所有联系人
Contact tmpContact; //声明自定义实体类对象
contacts.clear();
Cursor cursor =getContentResolver().query(uri,null,null,null,
ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
if (cursor.moveToFirst()) { //如果选择了记录
int idColumn = cursor.getColumnIndex(ContactsContract.Contacts._ID);
int displayNameColumn = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
do{ //循环遍历
tmpContact = new Contact();
String contactId = cursor.getString(idColumn); //获得联系人ID
String disPlayName = cursor.getString(displayNameColumn); //获得联系人姓名
//联系人的电话数量,没有这返回值为0
int phoneCount = cursor.getInt(cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER));
tmpContact.setName(disPlayName);
if (phoneCount > 0) {
// 获得联系人的电话号码
Cursor phones = getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID+" = " + contactId, null, null);
if (phones.moveToFirst()) {
String tmpPhone = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
//有些手机(如小米)登记手机号,多了2位空格,如155 2764 3858
//手机号以“1”打头
if(tmpPhone.length() >= 11&&tmpPhone.substring(0, 1).equals("1"))
tmpContact.setPhone(tmpPhone);
}
}
if(tmpContact.getPhone()!= null) {
contacts.add(tmpContact);
Log.i("myTag",tmpContact.toString());
}else{
Log.i("myTag","none");
}
} while (cursor.moveTonext());
}
}
void initView() { //呈现供勾选联系人的界面
listView = findViewById(R.id.listView);
myAdapter = new ChooseAdapter(this, contacts);
listView.setAdapter(myAdapter);
listView.setItemsCanFocus(false);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
//列表项选择监听,同时进行了勾选或取消勾选操作
listView.setonItemClickListener(new AdapterView.onItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view, int position, long id) {
Toast.makeText(MainActivity.this,
"点击了id为" + position + "的联系人!", Toast.LENGTH_SHORT).show();
ListItemView listItemView = (ListItemView) view.getTag();
boolean check = listItemView.checkBox.isChecked();
if (check) {
listItemView.checkBox.setChecked(false);
check = false;
} else {
listItemView.checkBox.setChecked(true);
check = true;
}
ChooseAdapter.checkResult.put(position, check);
}
});
if (contacts.size()>0) {
listView.setClickable(true);
myAdapter.refresh(contacts); //调用适配器类定义的方法
}else{
Toast.makeText(MainActivity.this, "未找到任何联系人,请检查uri,", Toast.LENGTH_SHORT).show();
finish();
}
}
//先构建对话框内容和群发的手机号,调用系统的短信程序,向选择的联系人发送短信
public void setMessageToSome() {
//选择了联系人进入短信编辑界面时,可能还会按返回键重新选择。所以,调用本方法前,重新统计
receiverName.clear();receiverPhone.clear();
for (int i = 0; i < ChooseAdapter.checkResult.size(); i++) {
if (ChooseAdapter.checkResult.get(i)) {
receiverName.add(contacts.get(i).getName());
receiverPhone.add(contacts.get(i).getPhone());
}
}
if (receiverName.size() == 0) { //未勾选联系人
new alertDialog.Builder(this).setTitle("没有选中任何记录").setPositiveButton("确定", null).show();
} else {
StringBuilder sb = new StringBuilder();
sb.append("接收人:" + receiverName.get(0));
receiverPhones = receiverPhone.get(0);
for (int i = 1; i < receiverName.size(); i++) {
sb.append("," + receiverName.get(i)); //构建对话框的内容,姓名之间用逗号分隔
receiverPhones += ";" + receiverPhone.get(i); //群发的手机号码之间要求用分号分隔
}
new alertDialog.Builder(this)
.setTitle("是否确定?")
.setMessage(sb)
.setPositiveButton("确定", new DialogInterface.onClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
//使用系统的短信程序
Intent intent=new Intent(Intent.ACTION_VIEW);
//短信界面中显示的接收人字符串由接收人电话字符串决定
intent.setData(Uri.parse("sms:"+receiverPhones+"?body=这儿写群发短信内容"));
startActivity(intent); //调用系统的短信程序
}
})
.setNegativeButton("取消", null)
.show();
}
}
}
最后总结一下 这个在Android studio上面是获取不到用户的uri的,这点需要注意,我们可以把这个项目导出到手机,然后再在手机上打开即可,我这里就不配图了,因为这个在权限那块涉及到危险隐私权限所以我这个地方就开始文字描述了。
总体来说群发短信还是非常方便的,只是需要测试的话需要用到手机来测试,电脑端的模拟器是无法进行模拟并测试的,这点很重要,要考的。翻遍半天都不一定找得到我这么详细的。
至于资源下载我这边会给免费开启的。



