回答編集履歴
1
質問の意図を勘違いして、長文で回答してしまっていたので、内容を削除しました。
test
CHANGED
@@ -1,131 +1 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
```kotlin
|
6
|
-
|
7
|
-
class DatePickk : DialogFragment(), DatePickerDialog.OnDateSetListener {
|
8
|
-
|
9
|
-
var callback: Callback? = null
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
14
|
-
|
15
|
-
val c = Calendar.getInstance()
|
16
|
-
|
17
|
-
val year = c.get(Calendar.YEAR)
|
18
|
-
|
19
|
-
val month = c.get(Calendar.MONTH)
|
20
|
-
|
21
|
-
val day = c.get(Calendar.DAY_OF_MONTH)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
return DatePickerDialog(activity, this, year, month, day)
|
26
|
-
|
27
|
-
}
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
override fun onDateSet(view: DatePicker, year: Int, month: Int, dayOfMonth: Int) {
|
32
|
-
|
33
|
-
callback?.onDatePicked(year, month, dayOfMonth)
|
34
|
-
|
35
|
-
}
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
interface Callback {
|
40
|
-
|
41
|
-
fun onDatePicked(year: Int, monthOfYear: Int, dayOfMonth: Int)
|
42
|
-
|
43
|
-
}
|
44
|
-
|
45
|
-
}
|
46
|
-
|
47
|
-
```
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
こうすることで、例えば将来、`DatePickk` が `DatePickerDialog` を使うのをやめて、別の方法で日付を選ぶように実装を変えたとしても、`DatePickk` の公開インターフェースを変える必要がないので、`kakeiboActivity` を修正せずにすみます。
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
`DatePickk` を上記のように修正した場合、`kakeiboActivity` は次のように、`DatePickerDialog.OnDateSetListener` の代わりに `DatePickk.Callback` を実装して、`onDatePicked()` で選択された日付を受け取ることになります。
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
```kotlin
|
60
|
-
|
61
|
-
class kakeiboActivity : FragmentActivity(), DatePickk.Callback {
|
62
|
-
|
63
|
-
// 中略...
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
override fun onDatePicked(year: Int, monthOfYear: Int, dayOfMonth: Int) {
|
68
|
-
|
69
|
-
val str = String.format(Locale.US, "%d/%d", year, monthOfYear+1, dayOfMonth)
|
70
|
-
|
71
|
-
calendar.text = str
|
72
|
-
|
73
|
-
}
|
74
|
-
|
75
|
-
```
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
また、`kakeiboActivity` は自身をコールバックとして `DatePickk.callback` にセットする必要があります。これは、[Androidの公式ガイド](https://developer.android.com/training/basics/fragments/communicating#DefineInterface)にも書かれているように、`FragmentActivity.onAttachFragment(Fragment)` にて行うのが良い方法です。
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
```kotlin
|
84
|
-
|
85
|
-
// 良いコールバックのセットの仕方
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
// kakeiboActivity
|
90
|
-
|
91
|
-
override fun onAttachFragment(fragment: Fragment) {
|
92
|
-
|
93
|
-
if (fragment is DatePickk) {
|
94
|
-
|
95
|
-
fragment.callback = this
|
96
|
-
|
97
|
-
}
|
98
|
-
|
99
|
-
}
|
100
|
-
|
101
|
-
```
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
普通に考えると、下のように、Fragmentを生成した直後にコールバックを設定したくなると思いますが、このコードは、画面回転をしたときなどにうまく動きません。例えば、ダイアログ表示中に画面が回転されて、その後、ダイアログで日付が選択されると、`kakeiboActivity.onDatePicked()` が呼びだされない動作となります。
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
```kotlin
|
110
|
-
|
111
|
-
// 悪いコールバックのセットの仕方
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
// kakeiboActivity
|
116
|
-
|
117
|
-
fun showDatePickerDialog1(view: View) {
|
118
|
-
|
119
|
-
val newFragment = DatePickk()
|
120
|
-
|
121
|
-
newFragment.show(supportFragmentManager, "datePicker")
|
122
|
-
|
123
|
-
newFragment.callback = this // ここでコールバックをセットしてはだめ
|
124
|
-
|
125
|
-
}
|
126
|
-
|
127
|
-
```
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
画面回転時、Activityは一度破棄されて再生成されますが、これはFragmentも同じで、画面回転時にFragmentが表示されていた場合、Fragmentの状態が保存されてから破棄され、そして自動的に再生成されます。再生成のケースでは`showDatePickerDialog1()` がよばれず、システムが自動的にFragmentのインスタンスを作成するので、上の悪いセットの仕方をしていると、Fragmentにコールバックがセットされません。一方で、`onAttachFragment()` は再生成時にも必ず呼ばれる関数なので、ここでコールバックをセットするようにすれば、自分でFragmentを作成したケースでも、システムがFragmentを再生成したケースでも、もれなくコールバックがセットできる、というわけです。
|
1
|
+
質問の意図を勘違いして、ActivityとFragmentのやりとりの仕方について長文で回答をしてしまったので、内容を削除しました。
|