Activity.onActivityResult

Activity.startActivityForResultでの処理結果は、Activity.onActivityResultで受け取る。

Activity  |  Android Developers

いまさらの感じあるけど、SampleのActivity.startActivityForResultの項をベースに、

SubActivityのButton押したら、RESULT_CANCELEDをセット。

MainActivityでは、RESULT_CANCELEDなら、"RESULT_CANCELED"とToast表示。

Buttonを押してSubActivityに
Buttonを押してSubActivityに

Buttonを押してSubActivityに。

こっちでもButtonを押すとMainActivityに戻る
こっちでもButtonを押すとMainActivityに戻る

こっちでもButtonを押すとMainActivityに戻る。

戻った時にこうなる
戻った時にこうなる

戻った時にこうなる。

Sample/android/Activity/onActivityResult/src/Activity at master · bg1bgst333/Sample · GitHub

Fragment.onDestroyView

Fragment.onDestroyViewは、FragmentのViewが破棄される時に呼ばれる。

Fragment  |  Android Developers

FragmentTransaction.removeで、Fragmentは破棄されるので、そのViewも破棄される。
よってonDestroyViewが呼ばれる。
SampleのFragmentTransaction.removeの項をベースに、

onDestroyViewにもログを残す。
MainActivity.javaは、

変わらず、Buttonを押したらremove。

起動時
起動時

起動時。

ログはonCreateViewだけ
ログはonCreateViewだけ

ログはonCreateViewだけ。

Buttonを押すと、Fragment1はremove。
Buttonを押すと、Fragment1はremove。

Buttonを押すと、Fragment1はremove。

onDestroyViewとonDestroyが呼ばれる。
onDestroyViewとonDestroyが呼ばれる。

onDestroyViewとonDestroyが呼ばれる。

Sample/android/Fragment/onDestroyView/src/Fragment at master · bg1bgst333/Sample · GitHub

Fragment.startActivityForResult

FragmentにstartActivityがあるのだから、startActivityForResultもある。

Fragment  |  Android Developers

まずは、Activity.startActivityForResultを使う。
Fragment1.javaで、

package com.bgstation0.android.sample.fragment_;

import android.app.Fragment;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;

public class Fragment1 extends Fragment implements View.OnClickListener{

    // メンバフィールド
    static final String TAG = "Fragment1";	// TAGを"Fragment1"で初期化.
	
    // ビュー生成時
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
			
        // ログを残す.
        Log.d(TAG, "Fragment1.onCreateView");	// "Fragment1.onCreateView"とログに残す.
			
        // 既定の処理.
        super.onCreateView(inflater, container, savedInstanceState);
		
        // Fragment1のButtonを取得.
        View view = inflater.inflate(R.layout.fragment1_main, null);	// inflater.inflateでR.layout.fragment1_mainからビューを作成.
        Button button1 = (Button)view.findViewById(R.id.fragment1_button);	// button1を取得.
        button1.setOnClickListener(this);	// thisをセット.
        return view;	// viewを返す.
        
    }
    
    // クリックされた時.
    @Override
    public void onClick(View v) {
    	// TODO Auto-generated method stub
    	// SubActivityを起動.
    	Intent intent = new Intent(getActivity(), SubActivity.class);	// intentを生成.
    	getActivity().startActivityForResult(intent, 1);	// Activity.startActivityForResultでintentと1を指定して起動.
    }
    
}

Buttonを押したら、getActivityで親であるMainActivityを取得し、そこからリクエストコード1を指定したstartActivityForResultでSubActivityを起動。

SubActivity.javaで、バックキーで戻る時に、messageの"ABCDE"とRESULT_OKをセットして終了。
MainActivity.javaは、

リクエストコード1なら、messageを取得。

この状態から
この状態から

この状態から、Buttonを押すと、

SubActivityが起動
SubActivityが起動

SubActivityが起動し、バックキーで戻ると、

"ABCDE"が取得出来てる
"ABCDE"が取得出来てる

"ABCDE"が取得出来てる。
さて、今のはActivity.startActivityForResultを使ったわけだが、Fragment.startActivityForResultを使うとどうなるか。

こうすると、

ここから
ここから

ここから、Buttonを押して、

SubActivityに行って
SubActivityに行って

SubActivityに行って、戻ってきても、

Toast表示が出ない
Toast表示が出ない

Toast表示が出ない。
実は、MainActivityのonActivityResultには来ない。
それについては、後で扱う。

Sample/android/Fragment/startActivityForResult/src/Fragment at master · bg1bgst333/Sample · GitHub

FragmentTransaction.remove

FragmentTransaction.removeで、Fragmentを削除する。

FragmentTransaction  |  Android Developers

削除なので、Fragmentのライフサイクルに影響を及ぼし、onDestroyが呼ばれる。
strings.xmlで、

Activityにbutton1_text、Fragmentにfragment1_textview_text。
fragment1_main.xmlで、

TextView.
activity_main.xmlで、

ButtonとFrameLayout。
Fragment1.javaは、

onDestroyにログを置いてる。
MainActivity.javaで、

Button押されたら、Fragment1をremove。

最初はこう
最初はこう

最初はこう。
Buttonを押すと、

TextViewが消える
TextViewが消える

TextViewが消える。Fragmentが削除されたからである。

この時のログからonDestroyが呼ばれているのでFragmentが破棄されている。
この時のログからonDestroyが呼ばれているのでFragmentが破棄されている。

この時のログからonDestroyが呼ばれているのでFragmentが破棄されている。

FragmentTransaction  |  Android Developers

Fragment.startActivity

FragmentにもstartActivityがあり、これでActivityを起動できる。

Fragment  |  Android Developers

まずは、AndroidManifest.xml

activityタグで".SubActivity"を追加。
strings.xmlは、

Fragment1のTextViewとButton、SubActivityのTextView。
fragment1_main.xmlは、

TextViewとButton。
activity_sub.xmlは、

TextView。
activity_main.xmlは、

中にFrameLayout。
Fragment1.javaは、

Button押されたら、startActivityでSubActivityを起動。
SubActivity.javaは、

特にいじってない。
MainActivity.javaは、

単純に起動時にFragment1を追加してるだけ。

起動時
起動時

起動時はこうなっているが、Button1を押すと、

SubActivityが起動する
SubActivityが起動する

SubActivityが起動する。

Sample/android/Fragment/startActivity/src/Fragment at master · bg1bgst333/Sample · GitHub

FragmentManager.findFragmentById

FragmentManager.findFragmentByIdは、『Fragmentを挿入している可能性のあるFrameLayoutなどのLayoutのID』からFragmentを見つけるためのメソッド。

FragmentManager  |  Android デベロッパー  |  Android Developers

普通、『FragmentのID』かとおもうけど、そうではない。
となると、複数の場合はどうなるかってなるんだけど、それは今回は扱わない。
strings.xmlで、

2つのFragmentそれぞれに置くTextViewのためのテキスト。
fragment1_main.xmlは、

TextViewだけ。
fragment2_main.xmlも、

TextViewだけ。
activity_main.xmlは、

Buttonに2つのFrameLayout。
Fragment1.javaは、

Viewを普通に生成。
Fragment2.javaも、

Viewを普通に生成。
あとは、MainActivity.javaで、

package com.bgstation0.android.sample.fragmentmanager_;

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // Buttonの初期化.
        Button button1 = (Button)findViewById(R.id.button1);	// button1を取得.
        button1.setOnClickListener(new OnClickListener() {	// リスナーをセット.
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				// Fragment1を表示し, Fragment2を非表示にする.
				FragmentManager fragmentManager = getFragmentManager();	// fragmentManagerの取得.
		        Fragment f2 = fragmentManager.findFragmentById(R.id.framelayout2);	// f2を取得.
		        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();	// fragmentTransactionの取得.
		        fragmentTransaction.hide(f2);	// f2を非表示.
		        fragmentTransaction.commit();	// 確定.      
			}
			
		});
        
        // フラグメントの追加.
        FragmentManager fragmentManager = getFragmentManager();	// fragmentManagerの取得.
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();	// fragmentTransactionの取得.
        Fragment1 fragment1 = new Fragment1();	// fragment1の生成.
        fragmentTransaction.add(R.id.framelayout1, fragment1);	// fragment1を追加.
        Fragment2 fragment2 = new Fragment2();	// fragment2の生成.
        fragmentTransaction.add(R.id.framelayout2, fragment2);	// fragment2を追加.
        fragmentTransaction.commit();	// 確定.
        
    }
    
}

framelayout1にfragment1、framelayout2にfragment2をadd。
button1を押したら、framelayout2に紐づけられたFragmentを探して、それを非表示。

起動時
起動時

起動時。
Button1を押したら、

Fragment2が非表示になり、Fragment1だけ残る。
Fragment2が非表示になり、Fragment1だけ残る。

Fragment2が非表示になり、Fragment1だけ残る。

今度は、framelayout1に紐づけられたFragmentを探して、それを非表示。

起動時
起動時

起動時はこうだが、

Button1を押したら、今度はFragment1が消えた。
Button1を押したら、今度はFragment1が消えた。

Button1を押したら、今度はFragment1が消えた。

Sample/android/FragmentManager/findFragmentById/src/FragmentManager at master · bg1bgst333/Sample · GitHub

Fragment.onAttach

Fragment.onAttachは、FragmentがActivityにアタッチされた時に呼ばれる。

Fragment  |  Android Developers

アタッチって表現が難しい(紐付けられると言えばそう)のだが、ここに来ると、Activityを参照できるようになるらしい。
それはさておいて、Activityへのコールバックについて試してみる。
strings.xmlで、

Fragmentを2つ使うので、ButtonもTextViewもそれぞれに。
activity_main.xmlは、

FrameLayoutを中に。
fragment1_main.xmlは、

TextViewとButton。
fragment2_main.xmlも、

同じ。
CustomListener.javaを追加し、

package com.bgstation0.android.sample.fragment_;

// カスタムリスナー
public interface CustomListener {
	void onButtonClicked();	// ボタンが押された時.
}

ボタンを押された時の独自コールバック。
Fragment1.javaで、

package com.bgstation0.android.sample.fragment_;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

// フラグメント1
public class Fragment1 extends Fragment {

	// メンバフィールド
	static final String TAG = "Fragment1";	// TAGを"Fragment1"で初期化.
	private CustomListener mCustomListener = null;	// mCustomListenerをnullで初期化.
	
	// コンストラクタ
	public Fragment1(){
		
	}
	
	// ファクトリメソッド
	public static Fragment1 newInstance(){
		
		// Fragment1オブジェクトの生成.
		Fragment1 fragment1 = new Fragment1();	// fragment1を生成.
		return fragment1;	// fragment1を返す.
		
	}
	
	// カスタムリスナーのセット.
	public void setCustomListener(CustomListener listener){
		
		// リスナーのセット.
		mCustomListener = listener;	// mCustomListenerにlistenerをセット.
		
	}
	
	// ビュー生成時
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
	
		// 既定の処理.
		super.onCreateView(inflater, container, savedInstanceState);
		
		// viewを返す.
		View view = inflater.inflate(R.layout.fragment1_main, null);	// viewを作成.
		Button button = (Button)view.findViewById(R.id.fragment1_button);	// buttonを取得.
		button.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				// リスナーを実行.
				mCustomListener.onButtonClicked();
			}
			
		});
		
		return view;	// viewを返す.
		
	}
	
}

setCustomListenerで渡されたコールバックをセット。
Buttonが押されたら、実行。
Fragment2.javaも、

package com.bgstation0.android.sample.fragment_;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

// フラグメント1
public class Fragment2 extends Fragment {

	// メンバフィールド
	static final String TAG = "Fragment2";	// TAGを"Fragment2"で初期化.
	private CustomListener mCustomListener = null;	// mCustomListenerをnullで初期化.
	
	// コンストラクタ
	public Fragment2(){
		
	}
	
	// ファクトリメソッド
	public static Fragment2 newInstance(){
		
		// Fragment2オブジェクトの生成.
		Fragment2 fragment2 = new Fragment2();	// fragment2を生成.
		return fragment2;	// fragment2を返す.
		
	}
	
	// カスタムリスナーのセット.
	public void setCustomListener(CustomListener listener){
		
		// リスナーのセット.
		mCustomListener = listener;	// mCustomListenerにlistenerをセット.
		
	}
	
	// ビュー生成時
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
	
		// 既定の処理.
		super.onCreateView(inflater, container, savedInstanceState);
		
		// viewを返す.
		View view = inflater.inflate(R.layout.fragment2_main, null);	// viewを作成.
		Button button = (Button)view.findViewById(R.id.fragment2_button);	// buttonを取得.
		button.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				// リスナーを実行.
				mCustomListener.onButtonClicked();
			}
			
		});
		
		return view;	// viewを返す.
		
	}
	
}

同じ。
MainActivity.javaは、

package com.bgstation0.android.sample.fragment_;

import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

// メインアクティビティ
public class MainActivity extends Activity {

	// メンバフィールド
	static final String TAG = "MainActivity";	// TAGを"MainActivity"で初期化.
	Context mContext = null;	// mContextをnullで初期化.
	
	// 生成時.
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    	
    	// 既定の処理.
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = this;	// mContextにthisをセット.
        
        if (savedInstanceState == null){
        	
        	// Fragmentの追加.
        	FragmentManager fragmentManager = getFragmentManager();	// fragmentManagerの取得.
        	FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();	// fragmentTransactionの開始.
        	Fragment1 fragment1 = Fragment1.newInstance();	// fragment1を生成.
        	fragment1.setCustomListener(new CustomListener(){
        		@Override
        		public void onButtonClicked(){
        			Toast.makeText(mContext, TAG + " Callback", Toast.LENGTH_LONG).show();	// Toast表示.
        		}
        	});
        	fragmentTransaction.replace(R.id.framelayout1, fragment1);	// fragment1に置換.
        	fragmentTransaction.commit();	// 確定.
        
        }
        
    }
    
}

fragment1.setCustomListenerの引数で、CustomListenerを定義してる。
Buttonが押されたらToast表示。
このFragmentを置換。

起動時
起動時

起動時。
Button押すと、

Toast表示
Toast表示

Toast表示。

回転してButtonを押す
回転してButtonを押す

回転して、Buttonを押すと、

おや?
おや?

おや?

落ちる
落ちる

落ちる。
回転するとコールバックのセットが無いから。
そこで、

package com.bgstation0.android.sample.fragment_;

import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

// メインアクティビティ
public class MainActivity extends Activity implements CustomListener{

	// メンバフィールド
	static final String TAG = "MainActivity";	// TAGを"MainActivity"で初期化.
	Context mContext = null;	// mContextをnullで初期化.
	
	// 生成時.
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    	
    	// 既定の処理.
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = this;	// mContextにthisをセット.
        
        if (savedInstanceState == null){
        	
        	// Fragmentの追加.
        	FragmentManager fragmentManager = getFragmentManager();	// fragmentManagerの取得.
        	FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();	// fragmentTransactionの開始.
        	Fragment1 fragment1 = Fragment1.newInstance();	// fragment1を生成.
        	fragmentTransaction.replace(R.id.framelayout1, fragment1);	// fragment1に置換.
        	fragmentTransaction.commit();	// 確定.
        
        }
        
    }
    
    @Override
	public void onButtonClicked(){
		Toast.makeText(mContext, TAG + " Callback", Toast.LENGTH_LONG).show();	// Toast表示.
	}
    
}

MainActivity.javaで、CustomListenerのonButtonClickedを実装してしまう。

package com.bgstation0.android.sample.fragment_;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

// フラグメント1
public class Fragment1 extends Fragment {

	// メンバフィールド
	static final String TAG = "Fragment1";	// TAGを"Fragment1"で初期化.
	
	// コンストラクタ
	public Fragment1(){
		
	}
	
	// ファクトリメソッド
	public static Fragment1 newInstance(){
		
		// Fragment1オブジェクトの生成.
		Fragment1 fragment1 = new Fragment1();	// fragment1を生成.
		return fragment1;	// fragment1を返す.
		
	}
	
	// ビュー生成時
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
	
		// 既定の処理.
		super.onCreateView(inflater, container, savedInstanceState);
		
		// viewを返す.
		View view = inflater.inflate(R.layout.fragment1_main, null);	// viewを作成.
		Button button = (Button)view.findViewById(R.id.fragment1_button);	// buttonを取得.
		button.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				// リスナーを実行.
				((MainActivity)getActivity()).onButtonClicked();
			}
			
		});
		
		return view;	// viewを返す.
		
	}
	
}

getActivityで取得したActivityをMainActivityにキャストして、onButtonClickedを呼べば、コールバック呼べてしまう。
setCustomListenerもいらないし。

package com.bgstation0.android.sample.fragment_;

import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

// フラグメント1
public class Fragment1 extends Fragment {

	// メンバフィールド
	static final String TAG = "Fragment1";	// TAGを"Fragment1"で初期化.
	private CustomListener mCustomListener = null;	// mCustomListenerをnullで初期化.
	
	// コンストラクタ
	public Fragment1(){
		
	}
	
	// ファクトリメソッド
	public static Fragment1 newInstance(){
		
		// Fragment1オブジェクトの生成.
		Fragment1 fragment1 = new Fragment1();	// fragment1を生成.
		return fragment1;	// fragment1を返す.
		
	}
	
	// アタッチ時
	@Override
	public void onAttach(Activity activity){
		
		// 既定の処理.
		super.onAttach(activity);
		mCustomListener = (CustomListener)activity;	// activityをmCustomListenerに渡す.
		
	}
	
	// ビュー生成時
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
	
		// 既定の処理.
		super.onCreateView(inflater, container, savedInstanceState);
		
		// viewを返す.
		View view = inflater.inflate(R.layout.fragment1_main, null);	// viewを作成.
		Button button = (Button)view.findViewById(R.id.fragment1_button);	// buttonを取得.
		button.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				// リスナーを実行.
				mCustomListener.onButtonClicked();
			}
			
		});
		
		return view;	// viewを返す.
		
	}
	
}

onArrachでActivityが渡されるので、それをmCustomListenerに保持しておいてもいい。
ここにonAttachの使いどころがある。

回転前もToastが出る
回転前もToastが出る

回転前もToastが出る。

回転後も落ちずにToast出る
回転後も落ちずにToast出る

回転後も落ちずにToast出る。
これで、コールバックはできたけど、最後にFragmentの中からActivityに飛んで、ActivityからFragmentの存在に関わる処理をしても、問題ないか試す。

CustomListener.javaで、

intの引数noをもらう。
Fragment1.javaで、

mCustomListener.onButtonClickedで1を渡す。
Fragment2.javaでは、

2を渡す。
MainActivity.javaでは、

1の時は2に置換、2の時は1を置換。
Buttonを押したら、別の片方に切り替わるということ。

Button1を押すと
Button1を押すと

Button1を押すと、

Fragment2に切り替わる
Fragment2に切り替わる

Fragment2に切り替わる。

横にしてButton2を押すと
横にしてButton2を押すと

横にしてButton2を押すと、

Fragment1に戻る
Fragment1に戻る

Fragment1に戻る。
このような切り替えができるので、ActivityからFragmentの存在に関わる処理が出来る。

Sample/android/Fragment/onAttach/src/Fragment at master · bg1bgst333/Sample · GitHub