4

首先,我发现这个答案特别有用。然而,这让我想知道如何找到这样的信息。

我似乎无法弄清楚如何迭代收件箱中的所有消息。我当前的解决方案使用Uri.parse("content://mms-sms/conversations")了“_id”和“ct_t”。但是,尽管有 30 条消息(其中 20 条在保存会话线程中,其他在另外两个会话中分配),但我似乎只在手机中找到了三个会话。这样的声明是有道理的content://mms-sms/conversations。但是,其他提供商似乎只处理 SMS 或 MMS。有没有办法以这种方式迭代整个消息列表,我"content://mms-sms/conversations"用其他东西替换?

public boolean refresh() {
    final String[] proj = new String[]{"_id","ct_t"};
    cursor = cr.query(Uri.parse("content://mms-sms/conversations"),proj,null,null,null);
    if(!(cursor.moveToFirst())) {
        empty = true;
        cursor.close();
        return false;
    }
    return true;
}

我用下一个函数迭代消息

    public boolean next() {

        if(empty) {
            cursor.close();
            return false;
        }
        msgCnt = msgCnt + 1;

        Msg msg;
        String msgData = cursor.getString(cursor.getColumnIndex("ct_t"));
        if("application/cnd.wap.multipart.related".equals(msgData)) {
            msg = ParseMMS(cursor.getString(cursor.getColumnIndex("_id")));
        } else {
            msg = ParseSMS(cursor.getString(cursor.getColumnIndex("_id")));
        }


        if(!(cursor.moveToNext())) {
            empty = true;
            cursor.close();
            return false;
        }

        return true;
    }
4

2 回答 2

11

好吧,我要问的似乎不太可能。
对于那些刚刚开始执行此类任务的人,建议了解内容提供商的一般工作方式。添加到查询的每个 Uri 值都会返回对特定表的访问权限。

花一些时间查看可以访问的不同Telephony.Mmssms表,从我的测试看来,您可以访问的唯一表是使用"content://mms-sms/conversationsas using"content://mms-sms"导致空游标。

这就是生活,以这种方式迭代消息并没有真正意义,因为提取数据的内容和方法根据消息是 SMS 还是 MMS 消息而有很大差异。分别迭代和解析 SMS 和 MMS 消息并将感兴趣的数据存储到相同的类对象类型中以便以后操作他们想要的方式是有意义的。

Telephony.Sms 文档对此类主题很有用。可以在其中找到列索引字段的描述。您可以找到Telephony.Mms以及子表Telephony.Mms.Part的相同信息,其中包含指向每个基本列的链接以描述信息。

话虽如此,这是问题How can I iterate all the SMS/MMS messages in the phone?的解决方案,这是对我有用的解决方案。

public class Main extends AppCompatActivity {
    //Not shown, Overrides,  button to call IterateAll();
    //implementations to follow
    IterateAll();
    public void ScanMMS();
    public void ScanSMS();
    public void ParseMMS(Msg msg);
    public Bitmap getMmsImg(String id);
    public String getMmsAddr(String id);
}

IterateAll() 只是调用两个不同的函数

IterateAll() {
    ScanMMS();
    ScanSMS();
}

ScanMMS() 将遍历content://mms从每个 MMS 中提取数据的表。

public void ScanMMS() {
        System.out.println("==============================ScanMMS()==============================");
        //Initialize Box
        Uri uri = Uri.parse("content://mms");
        String[] proj = {"*"};
        ContentResolver cr = getContentResolver();

        Cursor c = cr.query(uri, proj, null, null, null);

        if(c.moveToFirst()) {
            do {
                /*String[] col = c.getColumnNames();
                String str = "";
                for(int i = 0; i < col.length; i++) {
                    str = str + col[i] + ": " + c.getString(i) + ", ";
                }
                System.out.println(str);*/
                //System.out.println("--------------------MMS------------------");
                Msg msg = new Msg(c.getString(c.getColumnIndex("_id")));
                msg.setThread(c.getString(c.getColumnIndex("thread_id")));
                msg.setDate(c.getString(c.getColumnIndex("date")));
                msg.setAddr(getMmsAddr(msg.getID()));


                ParseMMS(msg);
                //System.out.println(msg);
            } while (c.moveToNext());
        }

        c.close();

    }

}

可以看到,很多重要的彩信数据都在这张表中,比如消息的日期、消息的id和线程id。您需要使用该消息 ID 从 MMS 中提取更多信息。

MMS 消息被分成更小的数据部分。每个部分都包含不同的内容,例如图像或文本部分。您必须像我在下面那样迭代每个部分。

public void ParseMMS(Msg msg) {
        Uri uri = Uri.parse("content://mms/part");
        String mmsId = "mid = " + msg.getID();
        Cursor c = getContentResolver().query(uri, null, mmsId, null, null);
        while(c.moveToNext()) {
/*          String[] col = c.getColumnNames();
            String str = "";
            for(int i = 0; i < col.length; i++) {
                str = str + col[i] + ": " + c.getString(i) + ", ";
            }
            System.out.println(str);*/

            String pid = c.getString(c.getColumnIndex("_id"));
            String type = c.getString(c.getColumnIndex("ct"));
            if ("text/plain".equals(type)) {
                msg.setBody(msg.getBody() + c.getString(c.getColumnIndex("text")));
            } else if (type.contains("image")) {
                msg.setImg(getMmsImg(pid));
            }


        }
        c.close();
        return;
    }

每个部分作为中间字段,对应于之前找到的消息的 id。我们仅在 MMS 部件库中搜索该 mms id,然后迭代找到的不同部件。 ct或者content_type如文档中描述的部分是什么,即文本、图像等。我扫描类型以查看如何处理该部分。如果是纯文本,我将该文本添加到当前消息正文中(显然可以有多个文本部分,但我没有看到它,但我相信它)如果是图像,则将图像加载到位图中。我想位图很容易用 java 发送到我的计算机,但谁知道呢,也许只想将它作为字节数组加载。

无论如何,这是从 MMS 部分获取图像数据的方法。

public Bitmap getMmsImg(String id) {
    Uri uri = Uri.parse("content://mms/part/" + id);
    InputStream in = null;
    Bitmap bitmap = null;

    try {
        in = getContentResolver().openInputStream(uri);
        bitmap = BitmapFactory.decodeStream(in);
        if(in != null)
            in.close();
    } catch (IOException e) {
        e.printStackTrace();
    }

    return bitmap;
}

你知道,我不完全确定在内容解析器上打开输入流是如何工作的,以及它是如何只给我图像而不是像所有其他数据一样,没有线索,但它似乎工作。我在寻找解决方案时从一些不同的来源偷了这个。

彩信地址不像短信那样直接提取,但您可以通过以下方式获取所有地址。我唯一没能做的就是弄清楚发件人是谁。如果有人知道,我会很高兴的。

public String getMmsAddr(String id) {
        String sel = new String("msg_id=" + id);
        String uriString = MessageFormat.format("content://mms/{0}/addr", id);
        Uri uri = Uri.parse(uriString);
        Cursor c = getContentResolver().query(uri, null, sel, null, null);
        String name = "";
        while (c.moveToNext()) {
/*          String[] col = c.getColumnNames();
            String str = "";
            for(int i = 0; i < col.length; i++) {
                str = str + col[i] + ": " + c.getString(i) + ", ";
            }
            System.out.println(str);*/
            String t = c.getString(c.getColumnIndex("address"));
            if(!(t.contains("insert")))
                name = name + t + " ";
        }
        c.close();
        return name;
}

这一切都只是为了彩信。好消息是 SMS 要简单得多。

public void ScanSMS() {
        System.out.println("==============================ScanSMS()==============================");
        //Initialize Box
        Uri uri = Uri.parse("content://sms");
        String[] proj = {"*"};
        ContentResolver cr = getContentResolver();

        Cursor c = cr.query(uri,proj,null,null,null);

        if(c.moveToFirst()) {
            do {
                String[] col = c.getColumnNames();
                String str = "";
                for(int i = 0; i < col.length; i++) {
                    str = str + col[i] + ": " + c.getString(i) + ", ";
                }
                //System.out.println(str);

                System.out.println("--------------------SMS------------------");

                Msg msg = new Msg(c.getString(c.getColumnIndex("_id")));
                msg.setDate(c.getString(c.getColumnIndex("date")));
                msg.setAddr(c.getString(c.getColumnIndex("Address")));
                msg.setBody(c.getString(c.getColumnIndex("body")));
                msg.setDirection(c.getString(c.getColumnIndex("type")));
                msg.setContact(c.getString(c.getColumnIndex("person")));
                System.out.println(msg);


            } while (c.moveToNext());
        }
        c.close();
}

这是我的简单消息结构,因此任何人都可以根据需要快速编译上述代码。

import android.graphics.Bitmap;

/**
 * Created by rbenedict on 3/16/2016.
 */

//import java.util.Date;

public class Msg {
    private String id;
    private String t_id;
    private String date;
    private String dispDate;
    private String addr;
    private String contact;
    private String direction;
    private String body;
    private Bitmap img;
    private boolean bData;
    //Date vdat;

    public Msg(String ID) {
        id = ID;
        body = "";
    }

    public void setDate(String d) {
        date = d;
        dispDate = msToDate(date);
    }
    public void setThread(String d) { t_id = d; }

    public void setAddr(String a) {
        addr = a;
    }
    public void setContact(String c) {
        if (c==null) {
            contact = "Unknown";
        } else {
            contact = c;
        }
    }
    public void setDirection(String d) {
        if ("1".equals(d))
            direction = "FROM: ";
        else
            direction = "TO: ";

    }
    public void setBody(String b) {
        body = b;
    }
    public void setImg(Bitmap bm) {
        img = bm;
        if (bm != null)
            bData = true;
        else
            bData = false;
    }

    public String getDate() {
        return date;
    }
    public String getDispDate() {
        return dispDate;
    }
    public String getThread() { return t_id; }
    public String getID() { return id; }
    public String getBody() { return body; }
    public Bitmap getImg() { return img; }
    public boolean hasData() { return bData; }

    public String toString() {

        String s = id + ". " + dispDate + " - " + direction + " " + contact + " " + addr + ": "  + body;
        if (bData)
            s = s + "\nData: " + img;
        return s;
    }

    public String msToDate(String mss) {

        long time = Long.parseLong(mss,10);

        long sec = ( time / 1000 ) % 60;
        time = time / 60000;

        long min = time % 60;
        time = time / 60;

        long hour = time % 24 - 5;
        time = time / 24;

        long day = time % 365;
        time = time / 365;

        long yr = time + 1970;

        day = day - ( time / 4 );
        long mo = getMonth(day);
        day = getDay(day);

        mss = String.valueOf(yr) + "/" + String.valueOf(mo) + "/" + String.valueOf(day) + " " + String.valueOf(hour) + ":" + String.valueOf(min) + ":" + String.valueOf(sec);

        return mss;
    }
    public long getMonth(long day) {
        long[] calendar = {31,28,31,30,31,30,31,31,30,31,30,31};
        for(int i = 0; i < 12; i++) {
            if(day < calendar[i]) {
                return i + 1;
            } else {
                day = day - calendar[i];
            }
        }
        return 1;
    }
    public long getDay(long day) {
        long[] calendar = {31,28,31,30,31,30,31,31,30,31,30,31};
        for(int i = 0; i < 12; i++) {
            if(day < calendar[i]) {
                return day;
            } else {
                day = day - calendar[i];
            }
        }
        return day;
    }



}

关于此解决方案的一些最终评论和说明。

person 字段似乎始终为 NULL,稍后我计划实现联系人查找。我也无法确定是谁发送了彩信。

我对java不是很熟悉,我还在学习它。我很肯定有一个数据容器(ArrayList)(Vector?)可以容纳用户定义的对象。如果可以按对象(日期)中的特定字段排序,则可以迭代该列表并具有所有消息的时间顺序:MMS/SMS 和发送/接收。

于 2016-03-24T13:00:42.460 回答
4

有没有办法以这种方式迭代整个消息列表,我"content://mms-sms/conversations"用其他东西替换?

content://mms-sms/complete-conversations可以使用URL在单个查询中获取所有 MMS 和 SMS 消息。出于某种奇怪的原因,类中没有Uri此字段,但至少从 Froyo 开始就可以使用它。Telephony.MmsSms

使用这个单一查询肯定会比单独查询表更有效,并且任何需要完成的排序、分组或过滤肯定会比操作 Java 集合更快地由 SQLite 引擎执行。

projection请注意,您必须为此查询使用特定的。您不能通过null*通配符。此外,建议在您的 - 中包含MmsSms.TYPE_DISCRIMINATOR_COLUMN( "transport_type") ,projection其值为"mms"or "sms"- 以轻松区分消息类型。

、和参数照常工作,selection可以为其中任何一个或所有参数传递。selectionArgsorderBynull

于 2016-04-06T00:57:55.663 回答