0

configChanges を使用して向きの変更を手動で処理することを指定せずにダイアログを管理する方法を、私の人生では理解できません。だから、あなたがこの AndroidManifest を持っているとしましょう:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.testandroid"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="15" />

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

次の MainActivity.java を使用します。

package com.example.testandroid;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;

public class MainActivity extends Activity {
    private final static String TAG = "MainActivity";
    Dialog mDialog = null;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate");
        setContentView(R.layout.activity_main);
    }    
    public void doShowDialog(View b) {
        Log.d(TAG, "doShowDialog");
        showDialog(1);
    }

    private void tryDismiss() {
        Log.d(TAG, "tryDismiss");
        try {           
            dismissDialog(1);
            removeDialog(1);
            mDialog.dismiss();
        } catch(IllegalArgumentException ex) {
            Log.e(TAG, ex.getMessage());
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

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

    }
    @Override
    protected Dialog onCreateDialog(int dialog) {
        Builder b = new AlertDialog.Builder(this);
        b.setTitle("Hello").setMessage("Waiting..");
        mDialog =  b.create();
        return mDialog;

    }    
}

そしてこのレイアウト(main.xml)

<LinearLayout 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:orientation="vertical"
 >
    <Button 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Open Dialog"
        android:onClick="doShowDialog"
        />

</LinearLayout>

onDestroy から呼び出すか onPause から呼び出すかは関係ないようです。方向が切り替わった後、ダイアログが再び表示されます。しかし、なぜ?私はそれを去るように言いました。removeDialog/dismissDialog を呼び出すと、向きが変わる前に呼び出されても何もしません。これがなぜなのか、一生わからない。私が知っているこれを取り除く唯一の方法は、次を使用して向きの変更を自分で処理することです

android:configChanges="keyboardHidden|orientation"

新しい作業方法は、まだアップグレードしていない FragmentDialog のものを使用することであり、そのためにアプリ全体を書き直す準備ができていません。これが機能しないのは奇妙に思えます。

これは、ユーザーが (スピナーのデータを更新するために) リモート サーバーから一部のデータを取得するように要求できるアプリで発生している現実世界の問題の例にすぎず、方向を切り替えると、読み込みダイアログが消えません。 android:configChanges オプションで向きの変更を処理する以外に、これに対する修正はないようです。私にはできることですが、それをしなければならないのはばかげているように思えます。

-- 更新 -- ダイアログを閉じるボタンを削除しました。これは不要であり、ダイアログが一番上にあるためクリックすることはできません。

再現するには、アプリを起動し、ダイアログを開くボタンをクリックしてから、携帯電話を回転させます。

4

4 に答える 4

2

ダイアログは に保存されるonSaveInstanceStateため、起動する前に閉じてみてください。

@Override
protected void onSaveInstanceState(Bundle state)
{
  tryDismiss();
  super.onSaveInstanceState(state);
}

また、アクティビティの onCreateDialog を使用してダイアログを管理する理由がよくわかりません。設計された理由は、向きの変更を自動的に処理することでした。手動で処理したい場合は、ダイアログの関数を使用してみませんか? showDialog(id)使用しonCreateDialog(id)て直接起動する代わりに、画面を回転させても再表示されません。

    Builder b = new AlertDialog.Builder(this);
    b.setTitle("Hello").setMessage("Waiting..");
    Dialog mDialog =  b.create();
    mDialog.show(); // <-----
于 2012-07-09T10:20:17.457 に答える
1

Sebastian はそれを理解しましたが、かなり混乱する可能性があるため、状況とダイアログに関する私の調査結果についてもう少し説明したいと思います。

  1. セバスチャンが言ったように、ローテーションの前にダイアログを消したい場合は、onSaveInstanceState からDismissDialog /removeDialog を呼び出す必要があります 。
  2. onCreate からダイアログを作成できますが、向きを変更する前に閉じないと、アクティビティの再起動時に onCreate メソッドで閉じることができません。onPostCreateからdismissDialogを呼び出す必要があります
  3. 方向の変更後も onRestoreInstanceState で、 dismissDialogの呼び出しが機能しませんでした。super.onRestoreInstanceState を呼び出す前後の両方を試してみましたが、どちらも機能しませんでした (onSaveInstanceState で削除が行われるため、そうなると思いました)。

これよりもさらに重要なことは、HTTP 呼び出しなどの非同期タスクを実行していて、タスクの完了時に実行されるコールバック関数を含む内部クラスがある場合、その内部に注意する必要があることです。画面が回転している場合、class メソッドには、外側の Activity クラスの元のインスタンスへの参照が含まれます。他の多くの人が問題を抱えているため、実際には AsyncTask を使用していませんでした (私は非同期 http ライブラリを使用していました)。

私の実際のコードに似た小さな例を取ります:

     public class MyActivity extends Activity {
   private static MyActivity sThis;

   @Override
   public void onCreate(Bundle state) {
      super.onCreate(state);
      sThis = this;
      doAsyncWork();
   }

   @Override
   public void onDestroy() {
      super.onDestroy();
      sThis = null;
   }
   private void doAsyncWork() {
      showDialog(LOADING_DIALOG); 
      ExampleAsyncWorker.work(new AsyncWorkerCallback() {   
           @Override
           public void onWorkComplete() {
             dismissDialog(LOADING_DIALOG); //doesn't work if orientation change happened.
           }        
      });
   }
}

上記のコードは、CategoryManager を介して外部サーバーに接続し、カテゴリのリストをダウンロードし、完了すると onCategoriesObtained を呼び出し、次に onFetchComplete を呼び出します (簡潔にするためにいくつかのエラー処理コールバック関数も削除されています)。fetchCategories 呼び出しと onFetchComplete の間で方向の変更が発生した場合、onFetchComplete での DismissDialog への呼び出しは機能しません。その理由は、この内部クラスには、向きが変わる前に作成された Activity クラスの元のインスタンスへの暗黙的な参照があるためです。したがって、dismissDialog を呼び出すと、新しいインスタンスではなく元のインスタンスで呼び出しているため、dismissDialog は次のメッセージで失敗します。私はこれを回避する方法を見つけましたが、ちょっとしたハックです:

Activity クラスにthis参照への静的参照を含めてonCreate に設定し、onDestroy で null を設定して、次のように内部クラスからその参照を使用します。

public class MyActivity extends Activity {
   private static MyActivity sThis;

   @Override
   public void onCreate(Bundle state) {
      super.onCreate(state);
      sThis = this;
      doAsyncWork();
   }

   @Override
   public void onDestroy() {
      super.onDestroy();
      sThis = null;
   }
   private void doAsyncWork() {
      showDialog(LOADING_DIALOG); 
      ExampleAsyncWorker.work(new AsyncWorkerCallback() {   
           @Override
           public void onWorkComplete() {
              sThis.dismissDialog(LOADING_DIALOG);
           }        
      });
   }
}

これが素晴らしい習慣であるかどうかはわかりませんが、私にとってはうまくいきました。外部クラスを参照するアクティビティの内部クラスに問題が発生する可能性があることはわかっているため (コンテキストのリーク)、この問題を解決するためのより良い方法があるかもしれません。

于 2012-07-10T17:22:10.163 に答える
-1

保存されたインスタンスなしでアプリを作成するには、super.onCreate(null); を使用できます。

于 2012-11-16T14:41:04.207 に答える