마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

TextView.setText(array[i]) 저장방법

0 추천
<string-array name="array">
    <item>1번</item>
    <item>2번</item>
    <item>3번</item>
    <item>4번</item>
</string-array>

이렇게 배열을 만들고
textView.setText(array[index]); 
에서 버튼을 누를 때마다 index값이 1씩 증가하여 한번 눌렀을 땐 textView.setText(array[0]); 이 출력 되고 두번 눌러을 땐 textView.setText(array[1]); 이 출력되게 하였습니다.



 만약 textView.setText(array[3]); //실행화면: 4번
에서 앱내 다른 페이지를 가거나 어플을 껐다 켰을 때 TextView 실행화면 4번이 유지될 수 있도록 값을 저장하려면 어떻게 해야되나요ㅜㅜ

예제를 통해 자세하게 알려주시면 정말 감사하겠습니다.. 어떻게 해야될지 감이 도저히 잡히지가 않네요ㅜㅜ

개발개발자 (1,100 포인트) 님이 2020년 11월 17일 질문

2개의 답변

0 추천

코드를 다 짜드리는 것이 좋은 건지 아닌지 모르겠지만, 간단하게 코드를 만들어 봤습니다. 동작을 하는 코드이긴 하나 부족한 부분이 있다면 공부하셔서 채우시기 바랍니다.

public interface Settings {

    int getLastPosition();
    void setLastPosition(int value);
}


public class AppSettings implements Settings {

        private static final String KEY_LAST_POSITION = "lastPosition";

        private final Storage storage;

        public AppSettings(Storage storage) {
            this.storage = storage;
        }

        @Override
        public int getLastPosition() {
            return storage.geInt(KEY_LAST_POSITION, 0);
        }

        @Override
        public void setLastPosition(int value) {
            storage.putInt(KEY_LAST_POSITION, value);
        }
}


public interface Storage {
    int geInt(String key, int defaultValue);
    void putInt(String key, int value);
}


public class PrefsStorage implements Storage {
    private final SharedPreferences prefs;

    public PrefsStorage(SharedPreferences prefs) {
        this.prefs = prefs;
    }

    @Override
    public int geInt(String key, int defaultValue) {
        return prefs.getInt(key, defaultValue);
    }

    @Override
    public void putInt(String key, int value) {
        prefs.edit()
                .putInt(key, value)
                .apply();
    }
}

public class CircularIterator<T> {
    private int currentPosition = 0;
    private final List<T> items;

    public CircularIterator(List<T> items) {
        this.items = items;
    }

    private int lastIndex() {
        return items.size() - 1;
    }

    public T currentItem() {
        return items.get(currentPosition);
    }

    public boolean hasNext() {
        return currentPosition < lastIndex();
    }

    public T next() {
        if (hasNext()) {
            currentPosition++;
            return currentItem();
        }

        currentPosition = 0;
        return currentItem();
    }

    public boolean hasPrevious() {
        return currentPosition > 0;
    }

    public T previous() {
        if (hasPrevious()) {
            currentPosition--;
            return currentItem();
        }

        currentPosition = lastIndex();
        return currentItem();
    }

    public int getCurrentPosition() {
        return currentPosition;
    }

    public void setCurrentPosition(int position) {
        boolean outOfBound = position < 0 || position > lastIndex();
        if (outOfBound) {
            throw new IllegalArgumentException("Invalid position " + position);
        }

        currentPosition = position;
    }
}


public class TextManager {

    private final CircularIterator<String> textIt;
    private final Settings settings;
    private final TextManagerListener listener;

    public TextManager(CircularIterator<String> textIt, Settings settings, TextManagerListener listener) {
        this.textIt = textIt;
        this.settings = settings;
        this.listener = listener;

        restoreStatus();
    }

    public void restoreStatus() {
        int savedPosition = settings.getLastPosition();
        textIt.setCurrentPosition(savedPosition);
        listener.onPositionRestored(textIt.currentItem(), savedPosition);
    }

    public void saveStatus() {
        int lastPosition = textIt.getCurrentPosition();
        settings.setLastPosition(lastPosition);
        listener.onPositionSaved(lastPosition);
    }

    public String currentItem() {
        return textIt.currentItem();
    }

    public String next() {
        return textIt.next();
    }

    public String previous() {
        return textIt.previous();
    }
}


public interface TextManagerListener {
    void onPositionRestored(String text, int position);
    void onPositionSaved(int position);
}


public class MainActivity extends AppCompatActivity {

    private static final String PREFS_NAME = "my_prefs";

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

        setupView();
        setupDependencies();
    }

    private TextView numberTxt;

    private void setupView() {
        numberTxt = findViewById(R.id.numberTxt);

        findViewById(R.id.leftBtn).setOnClickListener(v -> {
            updateText(textManager.previous());
        });

        findViewById(R.id.rightBtn).setOnClickListener(v -> {
            updateText(textManager.next());
        });
    }

    private TextManager textManager;

    private void setupDependencies() {
        final CircularIterator<String> textIterator = new CircularIterator<>(
                Arrays.asList(getResources().getStringArray(R.array.numbers))
        );
        final PrefsStorage storage = new PrefsStorage(getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE));
        final AppSettings settings = new AppSettings(storage);

        textManager = new TextManager(textIterator, settings, new TextManagerListener() {
            @Override
            public void onPositionRestored(String text, int position) {
                try {
                    numberTxt.setText(text);
                } catch (IllegalArgumentException e) {
                    // Do something on your requirement
                }
            }

            @Override
            public void onPositionSaved(int position) {
                // Do something if you want
            }
        });
    }

    private void updateText(String next) {
        numberTxt.setText(next);
    }

    @Override
    protected void onStop() {
        super.onStop();
        textManager.saveStatus();
    }
}

추가적인 설명을 드리자면 마지막에 선택한 텍스트의 배열 인덱스를 SharedPreferences를 이용하여 저장하고 앱이 시작되면 자동으로 복구합니다. MainActivity의 onStop은 앱이 백그라운드로 가기 전에 호출되므로, 여기에서 현재 선택된 텍스트의 배열인덱스를 저장합니다. 그리고 복구는 TextManager의 생성자에서 restoreStatus 메소드를 호출하여 하게 됩니다. 따라서 MainActivity에서 TextManager를 생성할 때 자동으로 호출되게 됩니다.

도움이 되시길.

 

spark (226,380 포인트) 님이 2020년 11월 17일 답변
성심성의껏 답변해주셔서 정말 감사합니다.. 코드를 정말 잘 짜주신 것 같은데 제가 이미 짜놓은 코드와 달라서 원하는 방향으로 재해석 하려면 공부가 더 필요할 것 같네요ㅜㅜ다시 한 번 감사드립니다..!
TextView의 값만 저장하고 싶은데......
Storage인터페이스에 getString, putString을 추가하시고 Settings에서 getLastPosition, setLastPosition 대신에 버튼에서 선택했던 텍스트를 저장하도록  변경하시고 getLastText/setLastText, TextManager의 restoreStatus, saveStatus 에서 Settings의 getLastText, setLastText을 호출하도록 변경하시면 됩니다.
코드가 복잡할 수도 있는데, 이렇게 생각하시면 쉬워집니다.  Delegation(위임)이라고 들어보셨죠. 누군가에게 대신 일을 맡기는 것을 위임이라고 하는데, 위의 코드에서 마찬가지입니다.
데이터를  파일에 저장하는 것은  Store가 전담하고  어떤 것을 저장하는 지는 Settings가 전담하고, Text를 위치에 맞게 선택되도록 하는 것은 CircularIterator가 담당하고, 종합적인 지휘는 TextManager가 하도록 하는 겁니다. 각자 자기가 담당하는 하나의 일을 잘 수행하도록 해주는 거죠. 이렇게 하면 수정사항이 생기거나 해도 어떤 클래스를 손대야 하는지 명확하기 때문에 그 외의 코드는 건드릴 필요가 없게 됩니다. 훨씬 유연하고 안전한 구조가 되는거죠.
근데, 텍스트를 바로 저장하는 것 보다는 인덱스만 저장하는 더 올바른 방법 같아 보이네요. 텍스트를 바로저장하시면 리소스의 배열에서 해당 텍스트를 가지고 배열에서 일치하는 값이 있는지 체크하셔야 하거든요. 텍스트 배열이 고정된 문자열이므로, 제가 보기에는 선택된 텍스트의 인덱스를 저장하는 것이 더 효율적인 방법같아 보이네요.
답변 정말 감사드립니다! 선택된 텍스트의 인덱스를 저장해두면 (만약, array[3])이렇게 저장해놓고 나갔다 들어오면 array[3]에 해당하는 문자열이 textview에 출력되어 보인다는 말씀이시죠?!

그렇다면 spark님이 짜주신 코드 처럼 PrefStorage클래스를 따로 만들어서 거기에 값을 넣어놓으라는 말씀이신 것 같은데,,,제가 fragment로 4페이지를 이용하는데 fragment마다 array[indext], arrayTwo[index] 등 짜놔서 변수가 다릅니다 ㅜ

전 나갔다 들어왔을 때 만약(array[4])에서 나갔다 들어왔다면, 그대로 array[4]의 문자열이 출력되어 있고 버튼을 누르면 바로 array[5]로 넘어 갈 수 있도록 코드를 짜고 싶은 건데... 이부분에 있어서 아직 이해가 잘 되지 않아서 고충입니다ㅜㅜㅜ sharedpreferens도 많이 찾아보고 했는데 어떤식으로 짜야될지,,,

지금 버튼을 눌렀을 때 배열이 값이 하나씩 증가하면서 하나씩 출력 되는 것은 잘 구현 했는데, 문제는 나갔다 들어오면 초기화 되는 것입니다ㅜㅜ
@Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.fragment_1, container, false);

SharedPreferences sharedPreferences = getActivity().getSharedPreferences(shared, 0);
        String value = sharedPreferences.getString("textview", "");
        textView.setText(value);

}

@Override
    public void onDestroy() {
        super.onDestroy();

        SharedPreferences sharedPreferences = getActivity().getSharedPreferences(shared, 0);
        SharedPreferences.Editor editor = sharedPreferences.edit();
        String value = textView.getText().toString();
        editor.putString("textview", value);
        editor.commit();
    }

이렇게 앱을 나가기전에 textview 화면만 저장하는 건 했습니다..  String value = textView.getText().toString();
        editor.putString("textview", value); //이부분에서 array[index]를 입력주면 되는 것이 아닌가 싶은데,,, 그렇게 하는 방법도 아직 잘 모르겠네요ㅜ
onDestroy는 상황에 따라 호출이 보장되지 않습니다. 제가 onStop을 대신에 사용한 이유이기도 합니다.

SharedPreferences sharedPreferences = getActivity().getSharedPreferences(shared, 0);
        SharedPreferences.Editor editor = sharedPreferences.edit();
        String value = textView.getText().toString();
        editor.putString("key_for_screen", value);
        editor.apply();

"textview" 대신에 화면에 해당하는 고유한 키값을 사용하세요.
0 추천

제일 심플한 방법은 키를 화면 별로 생성하는 겁니다.  아래는 변경된 코드입니다.

public class AppSettings implements Settings {

    private static final String KEY_LAST_POSITION = "%stPosition";

    private final Storage storage;

    public AppSettings(Storage storage) {
        this.storage = storage;
    }

    private String getLastPositionKeyPerScreen(String screeName) {
        return String.format(KEY_LAST_POSITION, screeName);
    }

    @Override
    public int getLastPosition(String screenName) {
        String key = getLastPositionKeyPerScreen(screenName);
        return storage.geInt(key, 0);
    }

    @Override
    public void setLastPosition(String screenName, int value) {
        String key = getLastPositionKeyPerScreen(screenName);
        storage.putInt(key, value);
    }

}


public class TextManager {

    private final CircularIterator<String> textIt;
    private final Settings settings;
    private final TextManagerListener listener;

    public TextManager(CircularIterator<String> textIt, Settings settings, TextManagerListener listener) {
        this.textIt = textIt;
        this.settings = settings;
        this.listener = listener;
    }

    public void restoreStatus(String screenName) {
        int savedPosition = settings.getLastPosition(screenName);
        textIt.setCurrentPosition(savedPosition);
        listener.onPositionRestored(textIt.currentItem(), savedPosition);
    }

    public void saveStatus(String screenName) {
        int lastPosition = textIt.getCurrentPosition();
        settings.setLastPosition(screenName, lastPosition);
        listener.onPositionSaved(lastPosition);
    }

    public String currentItem() {
        return textIt.currentItem();
    }

    public String next() {
        return textIt.next();
    }

    public String previous() {
        return textIt.previous();
    }
}


public class MainActivity extends AppCompatActivity {

    private static final String PREFS_NAME = "my_prefs";
    private static final String SCREEN_NAME = MainActivity.class.getSimpleName();

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

        setupView();
        setupDependencies();
    }

    private TextView numberTxt;

    private void setupView() {
        numberTxt = findViewById(R.id.numberTxt);

        findViewById(R.id.leftBtn).setOnClickListener(v -> {
            updateText(textManager.previous());
        });

        findViewById(R.id.rightBtn).setOnClickListener(v -> {
            updateText(textManager.next());
        });
    }

    private TextManager textManager;


    private void setupDependencies() {
        final CircularIterator<String> textIterator = new CircularIterator<>(
                Arrays.asList(getResources().getStringArray(R.array.numbers))
        );
        final PrefsStorage storage = new PrefsStorage(getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE));
        final AppSettings settings = new AppSettings(storage);

        textManager = new TextManager(textIterator, settings, new TextManagerListener() {
            @Override
            public void onPositionRestored(String text, int position) {
                try {
                    numberTxt.setText(text);
                } catch (IllegalArgumentException e) {
                    // Do something on your requirement
                }
            }

            @Override
            public void onPositionSaved(int position) {
                // Do something if you want
            }
        });

        textManager.restoreStatus(SCREEN_NAME);
    }

    private void updateText(String next) {
        numberTxt.setText(next);
    }

    @Override
    protected void onStop() {
        super.onStop();
        textManager.saveStatus(SCREEN_NAME);
    }
}

편의상 클래스 이름을 키값으로 사용하고 있습니다. 님이 화면에 따라 상수로 정의하신 문자열을 사용하셔도 됩니다. MainActivity를 클래스에 따라 바꾸면 자동으로 SCREEN_NAME도 바뀌겠죠. 
 

private static final String SCREEN_NAME = MainActivity.class.getSimpleName();

한가지 생각해 볼 수 있는 방법으로는  BaseFragment를 하나 생성하시고 공통적인 코드를 넣으신 다음, 상속을 받아 사용할 수도 있습니다.

public abstract class BaseFragment extends Fragment {

    private String getScreenName() {
        return this.getClass().getSimpleName();
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        textManager.restoreStatus(getScreenName());
    }

}

여기서 키포인트는 키값을 화면에 따라 사용하는 겁니다.

spark (226,380 포인트) 님이 2020년 11월 17일 답변
...