0

ACTION_VIEWまたはACTION_EDITでインテントを受け取ることで別のアプリから起動できるアプリを書いています。たとえば、電子メールの添付ファイルを表示して開くことができます。問題は、ホーム ボタンをクリックして、使用していたメール アプリの起動アイコンをもう一度クリックすると、アクティビティが強制終了され、ユーザーが行った編集が失われることです。私がしたいことは、ユーザーがホームボタンをクリックすると、アクティビティが再親化され、ユーザーがアプリの起動アイコンをクリックしたときに再開されるようにすることです。manifest.xml で android:allowTaskReparenting="true" を設定しようとしましたが、これは機能しません。まったく効果がない場合もあれば、アクティビティが起動アイコンに移動しても、メール アプリのアイコンをもう一度クリックすると強制終了される場合があります。allowTaskReparenting に関するドキュメントは非常に曖昧です。プロパティの意味は次のとおりです。

「アクティビティが、それを開始したタスクからアフィニティを持つタスクに移動 できるかどうか。」</p>

ここでできるという言葉はどういう意味ですか?私が欲しいのは、アクティビティ移動する (そしてそこにとどまる) という保証です。これを達成する方法はありますか?

助けていただける方、よろしくお願いします。

編集

以下のコメントに応えて、私が直面している問題を示す赤ちゃんバージョンをまとめました。別のアプリでファイル (電子メールの添付ファイルなど) をクリックして EditFileActivity を開始すると、そのファイルを編集できます。ただし、ホーム アイコンをクリックしてからメール アプリ アイコンをもう一度クリックすると、ファイルに加えた変更が失われます。ユーザーが明示的にクリックして「はい」または「いいえ」と言った場合にのみ、Android システムに EditFileActivity のインスタンスを忘れさせたいと思います。理想的には、EditFileActivity のすべてのインスタンスをアプリの起動アイコンに積み上げたいと考えています。singleTask または singleInstance を使用して、開いているすべてのファイルをタブに表示する何らかのアクティビティを作成することで、これに似たものを実装できますが、Android システム自体に助けてもらうことができれば、はるかに簡単になります。

これは、問題を示す完全なプロジェクトです。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.example.Example"
         android:versionCode="1"
         android:versionName="1.0">
   <uses-sdk
       android:minSdkVersion="11"
       android:targetSdkVersion="11"/>
   <application
       android:label="Example"
       android:icon="@drawable/ic_launcher">
       <activity
           android:name=".LaunchActivity"
           android:label="LaunchActivity"
           android:screenOrientation="portrait">
           <intent-filter>
               <action android:name="android.intent.action.MAIN"/>
               <category android:name="android.intent.category.LAUNCHER"/>
           </intent-filter>
       </activity>
       <activity
           android:name=".EditFileActivity"
           android:label="EditFileActivity"
           android:screenOrientation="portrait">
           <!-- This is just an example. I wouldn't use this intent filter in a real app! -->
           <intent-filter>
               <action android:name="android.intent.action.VIEW"/>
               <action android:name="android.intent.action.EDIT"/>
               <category android:name="android.intent.category.DEFAULT"/>
               <category android:name="android.intent.category.BROWSABLE"/>
               <data android:scheme="file"/>
               <data android:scheme="content"/>
               <data android:mimeType="*/*"/>
               <data android:host="*"/>
           </intent-filter>
       </activity>
   </application>
</manifest>` 

起動アクティビティ:

public class LaunchActivity extends Activity {

   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       TextView textView = new TextView(this);
       textView.setText("This is the activity you see when you click on the application's launch icon. It does absolutely nothing.");
       textView.setTextSize(18);
       setContentView(textView);
   }
}

編集ファイル アクティビティ:

public class EditFileActivity extends Activity {

   // This String represents the contents of the file.
   // In a "real" app the String would be initialised by reading the data from the Intent that started the activity.
   // However, for the purposes of this example, the initial value is "Default".
   private String fileContents = "Default";
   private boolean editsMade = false;
   private TextView textView;

   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       textView = new TextView(this);
       textView.setText(fileContents);
       textView.setTextSize(18);
       textView.setPadding(10, 10, 10, 10);
       setContentView(textView);
       textView.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               makeEdits();
           }
       });     
   }

   @Override
   public void onBackPressed() {
       if (editsMade) {
           savePrompt();
       } else {
           finish();
       }
   }

   private void savePrompt() {
       DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
           @Override
           public void onClick(DialogInterface dialog, int which) {
               if (which == Dialog.BUTTON_POSITIVE) {
                   // Here is where I would save the edited file.
                   Toast.makeText(EditFileActivity.this, "File saved", Toast.LENGTH_LONG).show();
               }
               finish();
           }
       };
       new AlertDialog.Builder(this)
               .setTitle("Close File")
               .setMessage("Do you want to save the changes you made?")
               .setPositiveButton("Yes", listener)
               .setNegativeButton("No", listener)
               .show();
   }

   private void makeEdits() {
       final EditText editText = new EditText(this);
       editText.setText(fileContents);
       new AlertDialog.Builder(this)
               .setTitle("Edit File")
               .setView(editText)
               .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                   @Override
                   public void onClick(DialogInterface dialog, int whichButton) {
                       Editable editable = editText.getText();
                       assert editable != null;
                       String newContents = editable.toString();
                       if (!fileContents.equals(newContents)) {
                           editsMade = true;
                           fileContents = newContents;
                           textView.setText(fileContents);
                       }
                   }
               })
               .setNegativeButton("Cancel", null)
               .show();
   }
}

2014 年 10 月 12 日更新

発生した問題は、インテント フラグ FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET の使用が原因でした。幸いなことに、API レベル 21 の時点で、Google はこのフラグを廃止しました。

4

2 に答える 2

1

問題:

問題は、ホーム ボタンをクリックして、使用していたメール アプリの起動アイコンをもう一度クリックすると、アクティビティが強制終了され、ユーザーが行った編集が失われることです。

これは、アクティビティの起動中に電子メール アプリケーションがFLAG_ACTIVITY_CLEAR_WHEN_TASK_RESETインテント フラグを設定したために発生します。このフラグが設定されている場合、次にタスクがフォアグラウンドに移動したときにアクティビティが終了し、ユーザーは前のアクティビティに戻ります。

ドキュメントから:

これは、アプリケーションに論理的なブレークがある場合に役立ちます。たとえば、電子メール アプリケーションには、添付ファイルを表示するためのコマンドが含まれている場合があります。このコマンドは、添付ファイルを表示するためのイメージ ビュー アクティビティを起動します。このアクティビティは、ユーザーが関与しているタスクの一部であるため、電子メール アプリケーションのタスクの一部である必要があります。ただし、ユーザーがそのタスクを離れ、後で自宅から電子メール アプリを選択した場合は、紛らわしいので、写真の添付ファイルではなく、表示していた会話に戻るようにします。画像ビューアーを起動するときにこのフラグを設定すると、そのビューアーとそれが開始するすべてのアクティビティは、ユーザーが次にメールに戻ったときに削除されます。

解決策:singleTaskアクティビティに launchMode を使用します。アクティビティは現在別のタスクに属しているため、メール アプリはアクティビティを強制終了しません。

アクティビティ インスタンスが既にタスク内にあり、アクティビティを再度起動しようとした場合、新しいインスタンスは作成されません。代わりonNewIntentに呼び出されます。ここで、新しいコンテンツを表示する前に、以前の編集があればそれを保存するようにユーザーに促すことができます。

于 2014-09-03T02:18:55.443 に答える