一款適合安卓開發(fā)初學(xué)者學(xué)習(xí)的 短信 APP

Ridder_SMS

A SMS app that can replace the System SMS

一個可以替代系統(tǒng)短信應(yīng)用的sms app

ic_launcher_round.png

前言

本文的內(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ā)的效果 :

4.png

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。

如果有什么想法或者建議跳昼,非常歡迎大家來討論般甲。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末肋乍,一起剝皮案震驚了整個濱河市鹅颊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌墓造,老刑警劉巖堪伍,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異觅闽,居然都是意外死亡帝雇,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門蛉拙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來尸闸,“玉大人,你說我怎么就攤上這事孕锄∷绷” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵畸肆,是天一觀的道長宦芦。 經(jīng)常有香客問我,道長轴脐,這世上最難降的妖魔是什么调卑? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮大咱,結(jié)果婚禮上恬涧,老公的妹妹穿的比我還像新娘。我一直安慰自己碴巾,他們只是感情好气破,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著餐抢,像睡著了一般现使。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上旷痕,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天碳锈,我揣著相機(jī)與錄音,去河邊找鬼欺抗。 笑死售碳,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播贸人,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼间景,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了艺智?” 一聲冷哼從身側(cè)響起倘要,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎十拣,沒想到半個月后封拧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡夭问,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年泽西,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缰趋。...
    茶點(diǎn)故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡捧杉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出秘血,到底是詐尸還是另有隱情味抖,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布直撤,位于F島的核電站非竿,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏谋竖。R本人自食惡果不足惜红柱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蓖乘。 院中可真熱鬧锤悄,春花似錦、人聲如沸嘉抒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽些侍。三九已至隶症,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間岗宣,已是汗流浹背蚂会。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留耗式,地道東北人胁住。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓趁猴,卻偏偏與公主長得像,于是被迫代替她去往敵國和親彪见。 傳聞我的和親對象是個殘疾皇子儡司,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容