Ridder_SMS
A SMS app that can replace the System SMS
一個可以替代系統(tǒng)短信應(yīng)用的sms app
前言
本文的內(nèi)容主要是解析短信App Ridder_SMS 的制作流程,以及代碼的具體實(shí)現(xiàn)房午,若有什么不足之處引几,還請?zhí)岢鼋ㄗh,附上這個 APP 的 Github 地址 Ridder_SMS 歡迎大家 :heart: star 和 fork.
本文的主要內(nèi)容
- 聯(lián)系人查詢 短信查詢 以及 短信收發(fā)的效果演示
- 聯(lián)系人 查詢 短信查詢的實(shí)現(xiàn)
- 短信接收的實(shí)現(xiàn)
- 短信聊天界面的實(shí)現(xiàn)
1.聯(lián)系人查詢 短信查詢 以及 短信收發(fā)的效果 :
2.聯(lián)系人 查詢 短信查詢的實(shí)現(xiàn) :
(1).聯(lián)系人 查詢 的實(shí)現(xiàn)
private List<ContactBean> getContentConfig()
{
Uri raw_uri=Uri.parse("content://com.android.contacts/raw_contacts");
Uri data_uri=Uri.parse("content://com.android.contacts/data");
Cursor raw_cursor=getContext().getContentResolver().query(raw_uri,new String[]{"_id"},null,null,null);
if(raw_cursor==null)
{
return mDataList;
}
Log.i(TAG,raw_cursor.getCount()+"");
while(raw_cursor.moveToNext())
{
String id=raw_cursor.getString(0);
Cursor data_cursor= getContext().getContentResolver().query(data_uri,new String[]{"mimetype","data1"},
"raw_contact_id = ?",new String[]{id},null);
if(data_cursor==null)
{
return mDataList;
}
Log.i(TAG,"聯(lián)系人"+id);
String name =null;
String number=null;
while(data_cursor.moveToNext())
{
String type=data_cursor.getString(0);
if(type.equals("vnd.android.cursor.item/name"))
{
Log.i(TAG,"name"+data_cursor.getString(1));
name=data_cursor.getString(1);
}else if(type.equals("vnd.android.cursor.item/phone_v2"))
{
Log.i(TAG,"number"+data_cursor.getString(1));
number=data_cursor.getString(1);
}
}
ContactBean contactBean=new ContactBean(name,number);
mDataList.add(contactBean);
data_cursor.close();
}
raw_cursor.close();
return mDataList;
}
1.首先利用contentProvider查詢 raw_contacts表筋蓖,得到id的游標(biāo)raw_cursor。
2.接著游標(biāo)raw_cursor一行行下移退敦,得到每一行的id粘咖。查詢data表中raw_contact_id列等于raw_cursor中id的行,選出其中的mimetype和data1列侈百,得到游標(biāo)data_cursor瓮下。
3.data_cursor一一行行下移,首先查詢mimetype的類型钝域,如果是name類型讽坏,則將data1列賦值給name變量。如果是phone_v2類型例证,則將data1列賦值給number變量路呜。
4.利用raw_cursor的每一行中的name變量和number變量 構(gòu)造 ContactBean類型的List,最終返回List。
public class RecyclerViewCallAdapter extends BaseQuickAdapter<ContactBean,BaseViewHolder>
{
public RecyclerViewCallAdapter(int layoutResId, @Nullable List<ContactBean> data) {
super(layoutResId, data);
}
@Override
protected void convert(BaseViewHolder helper, ContactBean item) {
helper.setText(R.id.tv_name,item.getName())
.setText(R.id.tv_number,item.getCallNum());
}
}
5.將List 加載到recycleView上胀葱。
(2)短信 查詢 的實(shí)現(xiàn)
public ArrayList<MessageBean> getSmsContent()
{
ContentResolver cr= getContext().getContentResolver();
String[] projection=new String[]{"_id","thread_id","address","person","date","read","status","type","body"};
Cursor cur = cr.query(SMS, projection, null, null, "date desc");
if(cur!=null)
{
while (cur.moveToNext())
{
int id=cur.getInt(cur.getColumnIndex("_id"));
long threadId=cur.getLong(cur.getColumnIndex("thread_id"));
String addressNumber=cur.getString(cur.getColumnIndex("address"));
String person=cur.getString(cur.getColumnIndex("person"));
long date=cur.getLong(cur.getColumnIndex("date"));
int read=cur.getInt(cur.getColumnIndex("read"));
int status=cur.getInt(cur.getColumnIndex("status"));
int type=cur.getInt(cur.getColumnIndex("type"));
String body=cur.getString(cur.getColumnIndex("body"));
if(type== 4)
{
Log.i("tag","id : " + id + ",address: " + addressNumber + " person : " + person + " date : " + date +" type : "
+ type+ " read : " + read + " threadid: " + threadId+"body"+body);
}
MessageBean messageBean=new MessageBean(id,addressNumber,person,date,read,type,threadId,body);
mDatalist.add(messageBean);
}
cur.close();
return mDatalist;
}else
{
MessageBean no_message=new MessageBean(1,"","",0,0,0,0,"No Message");
mDatalist.add(no_message);
cur.close();
return mDatalist;
}
}
短信的查詢則簡單的多漠秋,只涉及到了一張表(Uri.parse("content://sms/"))
1.首先利用contentProvider查詢sms表,選出其中的id,addressNumber,person,date,read,type,threadId,body列抵屿,按照時間降序排列庆锦,得到游標(biāo)cur。
2.cur一行行下移轧葛,用cur的每一行和 id,addressNumber,person,date,read,type,threadId,body 變量搂抒,構(gòu)造MessageBean類型的List。
private ArrayList<MessageBean> ContentRemove(ArrayList<MessageBean> smsContent)
{
ArrayList<Long> addressList =new ArrayList<>();
ArrayList<MessageBean> contentRemoveBeanList=new ArrayList<>();
for(MessageBean messageBean :smsContent)
{
long threadId=messageBean.getThreadId();
boolean contains=addressList.contains(threadId);
if(!contains)
{
addressList.add(threadId);
contentRemoveBeanList.add(messageBean);
}
}
return contentRemoveBeanList;
}
3.根據(jù)threadId去重短信尿扯。
protected void convert(BaseViewHolder helper, MessageBean item)
{
if(!TextUtils.isEmpty(item.getPerson()))
{
helper.setText(R.id.mi_tv_person,item.getPerson());
}else
{
helper.setText(R.id.mi_tv_person,item.getAddress());
}
if(item.getDate()==0)
{
helper.setText(R.id.tv_date," ");
}else
{
CharSequence format= DateFormat.format("MM-dd hh:mm",item.getDate());
helper.setText(R.id.tv_date,format.toString());
}
if(!TextUtils.isEmpty(item.getMessage()))
{
helper.setText(R.id.mi_tv_content,item.getMessage());
}else
{
helper.setText(R.id.mi_tv_content,"++");
}
helper.addOnClickListener(R.id.tv_delete)
.addOnClickListener(R.id.tv_thumb)
.addOnClickListener(R.id.mi_rl_content);
}
4.最終返回List燕耿,加list裝到recycleView中。
3.短信接收的實(shí)現(xiàn):
1.首先注冊SmsSReceiver姜胖,當(dāng)接收到短信和短信發(fā)送成功時誉帅,系統(tǒng)會發(fā)出兩條廣播,分別是SMS_RECEIVED_ACTION 和 SMS_DELIVER_ACTION右莱。
private Uri storeMessage(Context context,SmsMessage[] msgs,int error)
{
SmsMessage sms=msgs[0];
ContentValues values=extractContentValues(sms);
values.put(Telephony.Sms.ERROR_CODE, error);
int pduCount = msgs.length;
if (pduCount == 1) {
values.put(Telephony.Sms.Inbox.BODY, replaceFormFeeds(sms.getDisplayMessageBody()));
} else {
StringBuilder body = new StringBuilder();
for (int i = 0; i < pduCount; i++) {
sms = msgs[i];
body.append(sms.getDisplayMessageBody());
}
values.put(Telephony.Sms.Inbox.BODY, replaceFormFeeds(body.toString()));
}
Long threadId = values.getAsLong(Telephony.Sms.THREAD_ID);
String address = sms.getOriginatingAddress();
values.put(Telephony.Sms.ADDRESS, address);
if (((threadId == null) || (threadId == 0)) && (address != null)) {
threadId = getOrCreateThreadId(context, address);
values.put(Telephony.Sms.THREAD_ID, threadId);
}
ContentResolver resolver = context.getContentResolver();
Uri insertedUri = resolver.insert(Uri.parse("content://sms"), values);
return insertedUri;
}
2.在onReceive方法中蚜锨,借助ContentResolver和ContentValues將發(fā)出與接收到的短信和寫入到sms表中。
intentFilter=new IntentFilter();
intentFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
mfMessageReceiver=new MFMessageReceiver();
getActivity().registerReceiver(mfMessageReceiver,intentFilter);
mDatalist=new ArrayList<>();
ArrayList<MessageBean> smsContent1=getSmsContent();
ArrayList<MessageBean> messgeBeans1=ContentRemove(smsContent1);
recyclerViewMessageAdapter=new RecyclerViewMessageAdapter(R.layout.message_item,messgeBeans1);
recyclerViewMessageAdapter.setOnItemChildClickListener(MessageFragment.this);
messageRecycler.setAdapter(recyclerViewMessageAdapter);
3.在MessageFragment中慢蜓,注冊廣播亚再,當(dāng)接收到到android.provider.Telephony.SMS_RECEIVED 廣播時,刷新recycleView晨抡。
4.短信聊天界面的實(shí)現(xiàn):
public void onBindViewHolder(ViewHolder holder, int position) {
MessageBean messageBean=messageBeanList.get(position);
if(messageBean.getType()==1)
{
holder.leftLayout.setVisibility(View.VISIBLE);
holder.rightLayout.setVisibility(View.GONE);
holder.leftMsg.setText(messageBean.getMessage());
}else if(messageBean.getType()==2)
{
holder.leftLayout.setVisibility(View.GONE);
holder.rightLayout.setVisibility(View.VISIBLE);
holder.rightMsg.setText(messageBean.getMessage());
}
}
1.MsgAdapter中有左右兩個layout氛悬,根據(jù)messageBean的type類型,如果是接收耘柱,則顯示leftLayout如捅,隱藏rightLayout。如果是發(fā)出调煎,則隱藏leftLayout镜遣,顯示rightLayout。
private static ArrayList<MessageBean> getSmsContent(String threadId)
{
messageBeanList.clear();
ContentResolver cr=mContext.getContentResolver();
String[] projection=new String[]{"_id","address","person","date","read","status","type","body" };
Cursor cur=cr.query(SMS_INBOX,projection,"thread_id=?",new String[]{threadId},"date asc");
if(null!=cur)
{
while(cur.moveToNext())
{
int id = cur.getInt(cur.getColumnIndex("_id"));
String addressNumber=cur.getString(cur.getColumnIndex("address"));
String person=cur.getString(cur.getColumnIndex("person"));
long date=cur.getLong(cur.getColumnIndex("date"));
int read=cur.getInt(cur.getColumnIndex("read"));
int status=cur.getInt(cur.getColumnIndex("status"));
int type=cur.getInt(cur.getColumnIndex("type"));
String body=cur.getString(cur.getColumnIndex("body"));
Log.i("tag","id : " + id + ",address: " + addressNumber + " person : " + person + " date : " + date + " type : "
+ type + " read : " + read + " threadid: " + 0+"body"+body);
MessageBean messageBean=new MessageBean(id,addressNumber,person,date,read,type,0,body);
messageBeanList.add(messageBean);
}
cur.close();
return messageBeanList;
}else
{
MessageBean no_message=new MessageBean(1,"","",0,0,0,0,"No message");
messageBeanList.add(no_message);
cur.close();
return messageBeanList;
}
}
2.借助 ContentResolver 和從MainActivity傳遞過來的threadId士袄,進(jìn)行短信查詢悲关,構(gòu)造messageBeanList,最終加載到RecycleView上娄柳。不要忘記將RecycleVIew定位到最后一行寓辱。
msgRecyclerView.scrollToPosition(messageBeanArrayList1.size()-1);
結(jié)語
以上便是我寫這個 APP 的具體實(shí)現(xiàn)思路,以及踩過的一些坑赤拒,記錄下來秫筏,給大家看看诱鞠。
最后附上這個 APP 的 Github 地址 Ridder_SMS 歡迎大家 :heart: star 和 fork。
如果有什么想法或者建議跳昼,非常歡迎大家來討論般甲。