簡體   English   中英

應用程序在方向更改時保存文本框狀態嗎?

[英]Application saving textbox state on orientation change?

我試圖了解Android應用程序的總體流程,並且遇到了我認為很奇怪的情況(注意:我對android編程非常陌生)。

我僅使用多行編輯文本字段制作了一個測試應用程序。 我在現場寫了1234。 沒有其他任何事情,對默認的Eclipse ADT制造的應用程序沒有其他更改,並且沒有在后端專門覆蓋任何內容,我改變了方向。 剩余的1234。 然后,我按下主頁按鈕,然后從最近的應用程序中將其打開。 剩余的1234。

我對應用程序生命周期的理解是,按下主屏幕按鈕后,該應用程序已停止並啟動,而當更改應用程序的方向時,該應用程序將被破壞並創建。 如果這是正確的,那么是否存在某種形式的自動狀態保持? 我當時的假設是,我必須從狀態束中取出各個變量,然后自己恢復它們。 那不正確嗎?

一個經驗豐富的Android開發人員可以對此做出的任何解釋都將是很棒的。 我一直在尋找合適的答案,但無濟於事。

MainActivity.java

package com.example.teststate;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;


public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

Activity_Main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.teststate.MainActivity" >

    <EditText
        android:id="@+id/editText1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginTop="30dp"
        android:ems="10"
        android:inputType="textMultiLine" >

        <requestFocus />
    </EditText>

</RelativeLayout>

Manifest.xml中的代碼段

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name=".MainActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

謝謝!

發生這種情況的原因是,視圖通過覆蓋View#onSaveInstanceState()View#onRestoreInstanceStance(Parcelable )來顯式保存並在方向更改時恢復其狀態。 這是TextViewEditText的超類)中的實現。

@Override
public Parcelable onSaveInstanceState() {
    Parcelable superState = super.onSaveInstanceState();

    // Save state if we are forced to
    boolean save = mFreezesText;
    int start = 0;
    int end = 0;

    if (mText != null) {
        start = getSelectionStart();
        end = getSelectionEnd();
        if (start >= 0 || end >= 0) {
            // Or save state if there is a selection
            save = true;
        }
    }

    if (save) {
        SavedState ss = new SavedState(superState);
        // XXX Should also save the current scroll position!
        ss.selStart = start;
        ss.selEnd = end;

        if (mText instanceof Spanned) {
            Spannable sp = new SpannableStringBuilder(mText);

            if (mEditor != null) {
                removeMisspelledSpans(sp);
                sp.removeSpan(mEditor.mSuggestionRangeSpan);
            }

            ss.text = sp;
        } else {
            ss.text = mText.toString();
        }

        if (isFocused() && start >= 0 && end >= 0) {
            ss.frozenWithFocus = true;
        }

        ss.error = getError();

        return ss;
    }

    return superState;
}

[...]

@Override
public void onRestoreInstanceState(Parcelable state) {
    if (!(state instanceof SavedState)) {
        super.onRestoreInstanceState(state);
        return;
    }

    SavedState ss = (SavedState)state;
    super.onRestoreInstanceState(ss.getSuperState());

    // XXX restore buffer type too, as well as lots of other stuff
    if (ss.text != null) {
        setText(ss.text);
    }

    if (ss.selStart >= 0 && ss.selEnd >= 0) {
        if (mText instanceof Spannable) {
            int len = mText.length();

            if (ss.selStart > len || ss.selEnd > len) {
                String restored = "";

                if (ss.text != null) {
                    restored = "(restored) ";
                }

                Log.e(LOG_TAG, "Saved cursor position " + ss.selStart +
                      "/" + ss.selEnd + " out of range for " + restored +
                      "text " + mText);
            } else {
                Selection.setSelection((Spannable) mText, ss.selStart, ss.selEnd);

                if (ss.frozenWithFocus) {
                    createEditorIfNeeded();
                    mEditor.mFrozenWithFocus = true;
                }
            }
        }
    }

    if (ss.error != null) {
        final CharSequence error = ss.error;
        // Display the error later, after the first layout pass
        post(new Runnable() {
            public void run() {
                setError(error);
            }
        });
    }
}

如您所見,它將狀態保存在Parcelable對象中,然后將其傳遞到新實例中具有相同android:id的視圖中,並在新視圖上調用onRestoreInstanceState() 如果創建一個不僅僅包含其他視圖的自定義視圖,則可能需要覆蓋這些方法。

我無法為您提供代碼級別的說明。 但這是android承諾要做的事情之一。 您可以查看此重新創建活動

注意:為了使Android系統恢復您活動中視圖的狀態,每個視圖必須具有由android:id屬性提供的唯一ID。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM