web-dev-qa-db-ja.com

ローテーションAndroidでの活動再開

私のAndroidアプリケーションでは、デバイスを回転させる(キーボードを引き出す)と、Activityが再起動されます(onCreateが呼び出されます)。さて、これはおそらくそれが想定されている方法ですが、私はonCreateメソッドで多くの初期設定をするので、私はどちらかが必要です:

  1. すべての初期設定を別の関数に設定して、デバイスの回転やデバイスの回転で失われることがないようにします。
  2. onCreateが再度呼び出されず、レイアウトが調整されるようにするか、または
  3. onCreateが呼び出されないように、アプリをポートレートだけに制限します。
1301
Isaac Waller

アプリケーションクラスの使用

初期化で何をしているかに応じて、Applicationを拡張する新しいクラスを作成し、初期化コードをそのクラス内でオーバーライドされたonCreateメソッドに移動することを検討できます。

public class MyApplicationClass extends Application {
  @Override
  public void onCreate() {
    super.onCreate();
    // TODO Put your application initialization code here.
  }
}

アプリケーションクラスのonCreateは、アプリケーション全体が作成されたときにのみ呼び出されるため、Activityが向きを変えて再起動したり、キーボードの表示設定が変更されたりすることはありません。

このクラスのインスタンスをシングルトンとして公開し、初期化しているアプリケーション変数をゲッターとセッターを使用して公開することをお勧めします。

注:登録して使用するには、マニフェストに新しいApplicationクラスの名前を指定する必要があります。

<application
    Android:name="com.you.yourapp.MyApplicationClass"

設定変更への対応 [UPDATE:これはAPI 13以降廃止予定です; 推奨される代替案を参照してください ]

さらに別の方法として、向きやキーボードの表示設定の変更など、再起動を引き起こすイベントをアプリケーションにリッスンさせ、それらをActivity内で処理することもできます。

アクティビティのマニフェストノードにAndroid:configChangesノードを追加することから始めます。

 <activity Android:name=".MyActivity"
      Android:configChanges="orientation|keyboardHidden"
      Android:label="@string/app_name">

または Android 3.2(APIレベル13)以降

<activity Android:name=".MyActivity"
      Android:configChanges="keyboardHidden|orientation|screenSize"
      Android:label="@string/app_name">

次にActivity内でonConfigurationChangedメソッドをオーバーライドし、setContentViewを呼び出してGUIレイアウトを新しい方向に強制的に再作成します。

@Override
public void onConfigurationChanged(Configuration newConfig) {
  super.onConfigurationChanged(newConfig);
  setContentView(R.layout.myLayout);
}
935
Reto Meier

Android 3.2以降用に更新します。

注意 :Android 3.2(API level 13)以降、 「画面サイズ」も変更されます デバイスが縦向きと横向きの間で切り替わるとき。したがって、(minSdkVersion属性およびtargetSdkVersion属性で宣言されているように)APIレベル13以上で開発するときに、向きの変更によるランタイムの再起動を防ぐには、"screenSize"値に加えて"orientation"値を含める必要があります。つまり、Android:configChanges="orientation|screenSize"を宣言する必要があります。ただし、アプリケーションがAPIレベル12以下をターゲットにしている場合、アクティビティは常にこの設定変更自体を処理します(Android 3.2以降のデバイスで実行している場合でも、この設定変更はアクティビティを再開しません)。

181
Gorm

onCreate()が完全に起動されないようにする代わりに、イベントに渡されているBundlesavedInstanceStateがnullかどうかを確認してみてください。

たとえば、Activityが真に作成されたときに実行する必要があるロジックがあり、すべての向きが変わると実行されるわけではない場合、savedInstanceStateがnullの場合にのみonCreate()でそのロジックを実行します。

そうでなければ、私はまだレイアウトを向きに合わせて適切に再描画したいです。

public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_game_list);

        if(savedInstanceState == null){
            setupCloudMessaging();
        }
}

これが最終的な答えであるかどうかわからないが、それは私のために働く。

117
nebulae

私がしたこと...

マニフェストのactivityセクションに、次のように追加されています。

Android:configChanges="keyboardHidden|orientation"

アクティビティのコードで、次のものを実装しました。

//used in onCreate() and onConfigurationChanged() to set up the UI elements
public void InitializeUI()
{
    //get views from ID's
    this.textViewHeaderMainMessage = (TextView) this.findViewById(R.id.TextViewHeaderMainMessage);

    //etc... hook up click listeners, whatever you need from the Views
}

//Called when the activity is first created.
@Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    InitializeUI();
}

//this is called when the screen rotates.
// (onCreate is no longer called when screen rotates due to manifest, see: Android:configChanges)
@Override
public void onConfigurationChanged(Configuration newConfig)
{
    super.onConfigurationChanged(newConfig);
    setContentView(R.layout.main);

    InitializeUI();
}
94

あなたが説明するのはデフォルトの振る舞いです。以下を追加して、これらのイベントを自分で検出して処理する必要があります。

Android:configChanges

あなたのマニフェスト、そしてあなたが処理したい変更に。だから、オリエンテーションのために、あなたは使うだろう:

Android:configChanges="orientation"

キーボードを開閉するには、次のようにします。

Android:configChanges="keyboardHidden"

両方を処理したい場合は、次のようにpipeコマンドでそれらを分離するだけです。

Android:configChanges="keyboardHidden|orientation"

これはあなたが呼び出すどんなActivityにおいてもonConfigurationChangedメソッドを引き起こすでしょう。メソッドをオーバーライドすると、新しい値を渡すことができます。

お役に立てれば。

62
GregD

私はちょうどこの伝承を発見しました:

向きを変えてもアクティビティを維持し、onConfigurationChangedで処理するには、 ドキュメント および 上記のコードサンプル に示すように、マニフェストファイルでこれを実行します。

Android:configChanges="keyboardHidden|orientation"

これは常に機能するという追加の利点があります。

ボーナスは、keyboardHiddenを省略することは論理的に思えるかもしれませんが(少なくともAndroid 2.1のために)失敗を引き起こすということです:orientationだけを指定すると、エミュレータはOnCreateとときどきonConfigurationChangedその他の場合にのみOnCreate

私はデバイス上の失敗を見たことがありませんが、私はエミュレータが他の人に失敗することについて聞いたことがあります。そのため、文書化する価値があります。

40
Liudvikas Bukys

また、向きを変えてもデータを保持するAndroidプラットフォームの方法(onRetainNonConfigurationInstance()およびgetLastNonConfigurationInstance())を使用することを検討することもできます。

これにより、サーバーのフェッチから取得した情報やonCreate以降で計算されたその他の情報など、構成の変更にまたがってデータを保持することができます。同時に、現在の向きにxmlファイルを使用してActivityを再レイアウトすることもできます。使用中で。

ここ または ここ を参照してください。

すべてのFragmentsに切り替えて代わりに保持したいFragmentごとにsetRetainInstance(true)を使用することをお勧めします。

34
Jon O

この方法は便利ですが、フラグメントを使用する場合は不完全です。

フラグメントは通常、設定変更時に再作成されます。これを実現したくない場合は、

フラグメントのコンストラクタ内のsetRetainInstance(true);

これにより、構成変更中にフラグメントが保持されます。

http://developer.Android.com/reference/Android/app/Fragment.html#setRetainInstance(boolean)

29
Abdo

単に追加しました

     Android:configChanges="keyboard|keyboardHidden|orientation"

マニフェストファイルで 私の活動に onConfigurationChangedメソッドを追加しませんでした。

だからキーボードが滑り出すか何も起こらないたびに /。

22
bass.t

以下のコードを<activity>Manifest.xmlタグ内に配置します。

Android:configChanges="screenLayout|screenSize|orientation"
15

AndroidのonCreateを変更してもorientationメソッドは呼び出されます。だから、この方法にすべての重い機能を移動することはあなたを助けることにはならないでしょう

15
ganesh krishnan

それはとても簡単です。

<activity
    Android:name=".Test"
    Android:configChanges="orientation|screenSize"
    Android:screenOrientation="landscape" >
</activity>

これは私のために働く:

注: オリエンテーションはあなたの必要条件によります

14
ManiTeja
 onConfigurationChanged is called when the screen rotates. 
 (onCreate is no longer called when screen rotates due to manifest, see:  
 Android:configChanges)

マニフェストのどの部分が「onCreate()を呼び出さない」と言っていますか?

また、グーグルの文書はAndroid:configChangesの使用を避けるように言っています(最後の手段としては除く)....しかしそれから彼らが提案する代わりの方法はすべてDOAndroid:configChangesを使う)。

私の経験では、エミュレータは常にローテーション時にonCreate()を呼び出します。
しかし、私が同じコードを実行している1〜2台のデバイスは違います。 (なぜ違いがあるのか​​わからない。)

14
Carol

この行をマニフェストに追加してください -

Android:configChanges="orientation|keyboard|keyboardHidden|screenSize|screenLayout|uiMode"

そして、このスニペットのアクティビティは次のとおりです。 -

@Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
    }
14
Parin Parikh

Androidのマニフェストに加えられる変更は次のとおりです。

Android:configChanges="keyboardHidden|orientation" 

活動の中で行われる追加事項は以下のとおりです。

public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
        Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
    }
}
13
sumit pandey

これを行うにはいくつかの方法があります。

アクティビティ状態を保存

アクティビティの状態はonSaveInstanceStateに保存できます。

@Override
public void onSaveInstanceState(Bundle outState) {
    /*Save your data to be restored here
    Example : outState.putLong("time_state", time); , time is a long variable*/
    super.onSaveInstanceState(outState);
}

そしてbundleを使って状態を復元します。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if(savedInstanceState!= null){
       /*When rotation occurs
        Example : time = savedInstanceState.getLong("time_state", 0); */
    } else {
      //When onCreate is called for the first time
    }
}

自分で向きの変更を処理する

もう1つの選択肢は、自分で向きの変更を処理することです。しかしこれは良い習慣とは考えられていません。

これをマニフェストファイルに追加してください。

Android:configChanges="keyboardHidden|orientation"

android 3.2以降の場合

Android:configChanges="keyboardHidden|orientation|screenSize"

@Override
public void onConfigurationChanged(Configuration config) {
    super.onConfigurationChanged(config);

if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
        //Handle rotation from landscape to portarit mode here
    } else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE){
        //Handle rotation from portrait to landscape mode here
    }
}

回転を制限する

回転を避けるために、あなたの活動を縦モードまたは横モードに制限することもできます。

これをマニフェストファイルのactivityタグに追加します。

        Android:screenOrientation="portrait"

あるいはあなたの活動の中でプログラム的にこれを実装する:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
12
Piyush

「Androidのやり方」ではありませんが、自分自身で向きの変更を処理し、変更された向きを考慮に入れるためにビュー内でウィジェットの位置を変更するだけで、非常に良い結果が得られました。ビューを保存して復元する必要がないため、これは他の方法よりも高速です。また、再配置されたウィジェットはまったく同じウィジェットで、移動やサイズ変更を行っただけなので、よりシームレスなエクスペリエンスをユーザーに提供します。モデルの状態だけでなくビューの状態もこの方法で保存できます。

RelativeLayoutは時々自分自身の向きを変えなければならないビューには良い選択です。それぞれの子ウィジェットに対して、それぞれに異なる相対配置規則を使用して、一連の縦型レイアウトパラメータと一連の美しいレイアウトパラメータを指定するだけです。次に、あなたのonConfigurationChanged()メソッドで、適切なものをそれぞれの子のsetLayoutParams()呼び出しに渡します。子コントロール自体が internal reorientedである必要がある場合は、その子のメソッドを呼び出して方向の変更を実行するだけです。その子も同様に、内部の向きを変更する必要がある その などの子コントロールのメソッドを呼び出します。

10
Carl

これを行うための方法は、onRestoreInstanceStateイベントとonSaveInstanceStateイベントを使用してBundleに何かを保存することです(変数を保存する必要がない場合でも、Bundleが空にならないように何かを入れるだけです)。次に、onCreateメソッドで、Bundleが空かどうかを確認し、そうでない場合は初期化を行い、そうでない場合はそれを行います。

10
Shaun

画面が回転するたびに、開かれたアクティビティは終了し、onCreate()が再度呼び出されます。

1。画面を回転させたときにアクティビティの状態を保存することで、アクティビティのonCreate()が再度呼び出されたときに古いものをすべて復元できます。参照してください これ link

2。アクティビティの再開を防ぎたい場合は、manifest.xmlファイルに次の行を追加してください。

  <activity Android:name=".Youractivity"
  Android:configChanges="orientation|screenSize"/>
6
Mansuu....

onSavedInstanceStateメソッドを使用して、そのパラメータにすべての値を格納する必要があります。

@Override
    public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
        super.onSaveInstanceState(outState, outPersistentState);
        outPersistentState.putBoolean("key",value);
    }

そして使う

@Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        savedInstanceState.getBoolean("key");
    } 

オブジェクトを表示するために値を取得して設定するには、画面の回転を処理します。

6
koteswara D K

注: /将来、誰かが私と同じ問題に直面した場合、この回答を投稿します。私にとっては、次の行では不十分でした。

Android:configChanges="orientation"

画面を回転させたときに、メソッド `onConfigurationChanged(Configuration newConfig)が呼び出されませんでした。

解決策: オリエンテーションに問題があったとしても、 "screenSize"を追加しなければならなかった。 AndroidManifest.xmlファイルで、これを追加します。

Android:configChanges="keyboardHidden|orientation|screenSize"

それからメソッドonConfigurationChanged(Configuration newConfig)を実装します

6
iHank

manifestのactivityセクションに、以下を追加してください。

Android:configChanges="keyboardHidden|orientation"
5

マニフェストに次の行を追加します。 Android:configChanges="orientation|screenSize"

5

人々はあなたが使うべきだと言っています

Android:configChanges="keyboardHidden|orientation"

しかし、Androidで回転を処理するための最善かつ最も専門的な方法は、Loaderクラスを使用することです。それは有名なクラスではありません(私はその理由がわかりません)が、AsyncTaskよりもずっと優れています。詳細については、UdacityのAndroidコースにあるAndroidチュートリアルを読むことができます。

もちろん、別の方法として、onSaveInstanceStateを使用して値またはビューを格納し、onRestoreInstanceStateを使用してそれらを読み取ることもできます。それは本当にあなた次第です。

4
Theo

以下のコードをAndroid ManifestActivityに入れます。

Android:configChanges="orientation"

向きを変えても、これによってアクティビティが再開されることはありません。

3
Pratik Dasa

異なる方向で異なるタスクを実行するには、orientationリスナーを使用してください。

@Override
public void onConfigurationChanged(Configuration myConfig) 
{
    super.onConfigurationChanged(myConfig);
    int orient = getResources().getConfiguration().orientation; 
    switch(orient) 
    {
       case Configuration.ORIENTATION_LANDSCAPE:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                    break;
       case Configuration.ORIENTATION_PORTRAIT:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                    break;
       default:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
    }
}
3
Akshay Paliwal

画面の向き(横または縦)をAndroidManifest.xmlで修正

Android:screenOrientation="portrait"またはAndroid:screenOrientation="landscape"

このためあなたのonResume()メソッドは呼び出されません。

3

試行錯誤の後、私はほとんどの状況で私のニーズに合った解決策を見つけました。これがコードです:

マニフェスト設定:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
          package="com.pepperonas.myapplication">

    <application
        Android:name=".App"
        Android:allowBackup="true"
        Android:icon="@mipmap/ic_launcher"
        Android:label="@string/app_name"
        Android:supportsRtl="true"
        Android:theme="@style/AppTheme">
        <activity
            Android:name=".MainActivity"
            Android:configChanges="orientation|keyboardHidden|screenSize">
            <intent-filter>
                <action Android:name="Android.intent.action.MAIN"/>

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

</manifest>

MainActivity:

import Android.content.res.Configuration;
import Android.os.Bundle;
import Android.support.v4.app.Fragment;
import Android.support.v4.app.FragmentManager;
import Android.support.v4.app.FragmentTransaction;
import Android.support.v7.app.AppCompatActivity;
import Android.util.Log;
import Android.view.View;
import Android.widget.Button;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "MainActivity";

    private Fragment mFragment;

    private int mSelected = -1;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate  " + "");

        // null check not realy needed - but just in case...
        if (savedInstanceState == null) {

            initUi();

            // get an instance of FragmentTransaction from your Activity
            FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

            /*IMPORTANT: Do the INITIAL(!) transaction only once!
            * If we call this everytime the layout changes orientation,
            * we will end with a messy, half-working UI.
            * */
            mFragment = FragmentOne.newInstance(mSelected = 0);
            fragmentTransaction.add(R.id.frame, mFragment);
            fragmentTransaction.commit();
        }
    }


    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.d(TAG, "onConfigurationChanged  " +
                   (newConfig.orientation
                    == Configuration.ORIENTATION_LANDSCAPE
                    ? "landscape" : "portrait"));

        initUi();

        Log.i(TAG, "onConfigurationChanged - last selected: " + mSelected);
        makeFragmentTransaction(mSelected);
    }


    /**
     * Called from {@link #onCreate} and {@link #onConfigurationChanged}
     */
    private void initUi() {
        setContentView(R.layout.activity_main);
        Log.d(TAG, "onCreate  instanceState == null / reinitializing..." + "");
        Button btnFragmentOne = (Button) findViewById(R.id.btn_fragment_one);
        Button btnFragmentTwo = (Button) findViewById(R.id.btn_fragment_two);
        btnFragmentOne.setOnClickListener(this);
        btnFragmentTwo.setOnClickListener(this);
    }


    /**
     * Not invoked (just for testing)...
     */
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.d(TAG, "onSaveInstanceState  " + "YOU WON'T SEE ME!!!");
    }


    /**
     * Not invoked (just for testing)...
     */
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.d(TAG, "onSaveInstanceState  " + "YOU WON'T SEE ME, AS WELL!!!");
    }


    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume  " + "");
    }


    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "onPause  " + "");
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy  " + "");
    }


    @Override
    public void onClick(View v) {

        switch (v.getId()) {
            case R.id.btn_fragment_one:
                Log.d(TAG, "onClick btn_fragment_one " + "");
                makeFragmentTransaction(0);
                break;

            case R.id.btn_fragment_two:
                Log.d(TAG, "onClick btn_fragment_two " + "");
                makeFragmentTransaction(1);
                break;

            default:
                Log.d(TAG, "onClick  null - wtf?!" + "");
        }
    }


    /**
     * We replace the current Fragment with the selected one.
     * Note: It's called from {@link #onConfigurationChanged} as well.
     */
    private void makeFragmentTransaction(int selection) {

        switch (selection) {
            case 0:
                mFragment = FragmentOne.newInstance(mSelected = 0);
                break;
            case 1:
                mFragment = FragmentTwo.newInstance(mSelected = 1);
                break;
        }

        // Create new transaction
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

        // Replace whatever is in the fragment_container view with this fragment,
        // and add the transaction to the back stack
        transaction.replace(R.id.frame, mFragment);

        /*This would add the Fragment to the backstack...
        * But right now we comment it out.*/
        //        transaction.addToBackStack(null);

        // Commit the transaction
        transaction.commit();
    }

}

そしてサンプルフラグメント:

import Android.os.Bundle;
import Android.support.v4.app.Fragment;
import Android.util.Log;
import Android.view.LayoutInflater;
import Android.view.View;
import Android.view.ViewGroup;

/**
 * @author Martin Pfeffer (pepperonas)
 */
public class FragmentOne extends Fragment {

    private static final String TAG = "FragmentOne";


    public static Fragment newInstance(int i) {
        Fragment fragment = new FragmentOne();
        Bundle args = new Bundle();
        args.putInt("the_id", i);
        fragment.setArguments(args);
        return fragment;
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.d(TAG, "onCreateView  " + "");
        return inflater.inflate(R.layout.fragment_one, container, false);
    }

}

github にあります。

3
Martin Pfeffer

Googleによって導入されたAndroidアーキテクチャの最も優れたコンポーネントの1つは、ViewModelであるあなたのすべての要件を満たします。

それはライフサイクルの方法でUI関連のデータを保存して管理するように設計されています。それに加えて、画面が回転してもデータは生き残ることができます。

class MyViewModel : ViewModel() {

これを参照してください: https://developer.Android.com/topic/libraries/architecture/viewmodel

1
Android Geek

あなたの活動の中でViewModelオブジェクトを使うことができます。

ViewModelオブジェクトは、設定の変更中に自動的に保持されるため、保持しているデータはすぐに次のアクティビティまたはフラグメントインスタンスで利用できるようになります。続きを読む:

https://developer.Android.com/topic/libraries/architecture/viewmodel

1
Gregory Buiko

あなたはこのコードを使って画面の現在の向きに固定することができます...

int currentOrientation =context.getResources().getConfiguration().orientation;
        if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) {
            ((Activity) context).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        } else {
            ((Activity) context). setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        }
0
Rashid