SMS-MMS的草稿箱

Android4.2

1.草稿箱---存储。(ComposeMessageActivity)(type=3)

onKeyDown方法的case KeyEvent.KEYCODE_BACK:调用了exitComposeMessageActivity方法,主要判断离开时是否应该存储界面内的信息,或者提示信息会被舍弃,如果需要存储则把mToastForDraftSave设为true,这个参数决定了在saveDraft方法存储时给toast提示。

在onStop方法中调用了saveDraft(true)方法存储草稿。在saveDraft方法内,判断 如果不应该存储并且联系人编辑框不可见或者里面没联系人,则mWorkingMessage.discard()舍弃信息,discard()舍弃的过程为:把mDiscarded设置为true,接着删除可能存在的与此thread_Id关联的draft。

    if (mHasMmsDraft) {
            asyncDeleteDraftMmsMessage(mConversation);
        }
        if (mHasSmsDraft) {
            asyncDeleteDraftSmsMessage(mConversation);
        }

清除数据库中对应thread_id草稿,彩信的条件为

        // If the thread id is < 1, then the thread_id in the pdu will be "" or NULL. We have
        // to clear those messages as well as ones with a valid thread id.
        final String where = Mms.THREAD_ID +  (threadId > 0 ? " = " + threadId : " IS NULL");
        asyncDelete(Mms.Draft.CONTENT_URI, where, null);
短信则清除type=3的数据
        if (threadId > 0) {
            asyncDelete(ContentUris.withAppendedId(Sms.Conversations.CONTENT_URI, threadId),
                SMS_DRAFT_WHERE, null);
        }
清除mWorkingMessage内Conversation对象的thread_Id参数。


如果没舍弃信息,则调用mWorkingMessage.saveDraft(isStopping)存储。

 public void saveDraft(final boolean isStopping) {
        // If we have discarded the message, just bail out.
        if (mDiscarded) {
            LogTag.warn("saveDraft mDiscarded: true mConversation: " + mConversation +
                " skipping saving draft and bailing");
            return;
        }

        // Make sure setConversation was called.
        if (mConversation == null) {
            throw new IllegalStateException("saveDraft() called with no conversation");
        }

        if (LogTag.VERBOSE || Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
            LogTag.debug("saveDraft for mConversation " + mConversation);
        }

        // Get ready to write to disk. But don't notify message status when saving draft
        prepareForSave(false /* notify */);

        if (requiresMms()) {
            if (hasMmsContentToSave()) {
                asyncUpdateDraftMmsMessage(mConversation, isStopping);
                mHasMmsDraft = true;
            }
        } else {
            String content = mText.toString();

            // bug 2169583: don't bother creating a thread id only to delete the thread
            // because the content is empty. When we delete the thread in updateDraftSmsMessage,
            // we didn't nullify conv.mThreadId, causing a temperary situation where conv
            // is holding onto a thread id that isn't in the database. If a new message arrives
            // and takes that thread id (because it's the next thread id to be assigned), the
            // new message will be merged with the draft message thread, causing confusion!
            if (!TextUtils.isEmpty(content)) {
                asyncUpdateDraftSmsMessage(mConversation, content, isStopping);
                mHasSmsDraft = true;
            } else {
                // When there's no associated text message, we have to handle the case where there
                // might have been a previous mms draft for this message. This can happen when a
                // user turns an mms back into a sms, such as creating an mms draft with a picture,
                // then removing the picture.
                asyncDeleteDraftMmsMessage(mConversation);
                mMessageUri = null;
            }
        }
    }
存短信草稿后把对应thread_id的彩信删掉(如果存在),存彩信时也一样。

存短信的具体代码如下(按理说不应该存在thread_id=0的数据):(测试mMessageUri == null,新建下方法不被调用,另一种情况应该是打开草稿的情况)

    private void updateDraftSmsMessage(final Conversation conv, String contents) {
        final long threadId = conv.getThreadId();
        if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
            LogTag.debug("updateDraftSmsMessage tid=%d, contents=\"%s\"", threadId, contents);
        }

        // If we don't have a valid thread, there's nothing to do.
        if (threadId <= 0) {
            return;
        }

        ContentValues values = new ContentValues(3);
        values.put(Sms.THREAD_ID, threadId);
        values.put(Sms.BODY, contents);
        values.put(Sms.TYPE, Sms.MESSAGE_TYPE_DRAFT);
        SqliteWrapper.insert(mActivity, mContentResolver, Sms.CONTENT_URI, values);
        asyncDeleteDraftMmsMessage(conv);
        mMessageUri = null;
    }
存彩信使用framework里面类存储的,先获取uri,再存储。
    private static void updateDraftMmsMessage(Uri uri, PduPersister persister,
            SlideshowModel slideshow, SendReq sendReq, HashMap preOpenedFiles) {
        if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
            LogTag.debug("updateDraftMmsMessage uri=%s", uri);
        }
        if (uri == null) {
            Log.e(TAG, "updateDraftMmsMessage null uri");
            return;
        }
        persister.updateHeaders(uri, sendReq);

        final PduBody pb = slideshow.toPduBody();

        try {
            persister.updateParts(uri, pb, preOpenedFiles);
        } catch (MmsException e) {
            Log.e(TAG, "updateDraftMmsMessage: cannot update message " + uri);
        }

        slideshow.sync(pb);
    }

2、加载(WorkingMessage、DraftCache、Conversation)

在Activity的onStart方法及ListView的size变化时都会调用loadMessagesAndDraft()方法,这个方法会调用loadMessageContent()方法加载数据库里的短彩信。接着调用loadDraft()方法加载草稿箱。通过WorkingMessage.loadDraft方法查询草稿箱。在WorkingMessage的loadDraft方法里用异步线程查询,调用readDraftSmsMessage(Conversation conv)方法,此方法里做了限制,如果要查询的thread_id<=0或者!conv.hasDraft()则不查询返回

       long thread_id = conv.getThreadId();
        if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
            Log.d(TAG, "readDraftSmsMessage conv: " + conv);
        }
        // If it's an invalid thread or we know there's no draft, don't bother.
        if (thread_id <= 0 || !conv.hasDraft()) {  
            return "";
        }

        Uri thread_uri = ContentUris.withAppendedId(Sms.Conversations.CONTENT_URI, thread_id);
        String body = "";

        Cursor c = SqliteWrapper.query(mActivity, mContentResolver,
                        thread_uri, SMS_BODY_PROJECTION, SMS_DRAFT_WHERE, null, null);
如果查询到了短信,则删掉数据库的这条草稿记录再返回结果,彩信不删除
      Cursor c = SqliteWrapper.query(mActivity, mContentResolver,
                        thread_uri, SMS_BODY_PROJECTION, SMS_DRAFT_WHERE, null, null);
        boolean haveDraft = false;
        if (c != null) {
            try {
                if (c.moveToFirst()) {
                    body = c.getString(SMS_BODY_INDEX);
                    haveDraft = true;
                }
            } finally {
                c.close();
            }
        }

        // We found a draft, and if there are no messages in the conversation,
        // that means we deleted the thread, too. Must reset the thread id
        // so we'll eventually create a new thread.
        if (haveDraft && conv.getMessageCount() == 0) {
            asyncDeleteDraftSmsMessage(conv);

            // Clean out drafts for this thread -- if the recipient set changes,
            // we will lose track of the original draft and be unable to delete
            // it later.  The message will be re-saved if necessary upon exit of
            // the activity.
            clearConversation(conv, true);
        }
        if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
            LogTag.debug("readDraftSmsMessage haveDraft: ", !TextUtils.isEmpty(body));
        }

        return body;

总结:很明显,如果conv.hasDraft()为false是得不到草稿信息的,Conversation的hasDraft方法实际调用DraftCache.getInstance().hasDraft(mThreadId),而DraftCache的hasDraft则是判断这个thread_id有没有在里面的HashSet中记录。

疑问:DraftCache什么时候得到草稿箱的thread_id?

在程序初始化时,在MmsApp的onCreate中调用了DraftCache.init()方法,此方法中构造了单例DraftCache对象,构造时调用refresh()方法,再里面调用rebuildCache()方法获取数据库内所有有草稿的thread_id给静态Hashset对象mDraftSet。在保存、

注意:当离开短信界面时onStop方法里调用的saveDraft(boolean isStopping)方法里

        if (mWorkingMessage.isDiscarded()) {
            return;
        }

        if (!mWaitingForSubActivity &&
                !mWorkingMessage.isWorthSaving() &&
                (!isRecipientsEditorVisible() || recipientCount() == 0)) {
            if (LogTag.VERBOSE || Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
                log("not worth saving, discard WorkingMessage and bail");
            }
            mWorkingMessage.discard();
            return;
        }

        mWorkingMessage.saveDraft(isStopping);
也就是说不存储则舍弃,而在discard()方法里调用 clearConversation(mConversation, true), clearConversation方法里调用conv.setDraftState(false);一直调用到DraftCache中
        synchronized (mDraftSetLock) {
            if (hasDraft) {
                changed = mDraftSet.add(threadId);
            } else {
                changed = mDraftSet.remove(threadId);
            }
        }




你可能感兴趣的:(SMS-MMS的草稿箱)