
Android Developers > スタートガイド > Kotlin と Android をゼロから学ぶ > Unit3 – ナビゲーション >Unit3-2 の内容をまとめたものです(翻訳ではありません)
WordListFragment クラスの書き換え
アプリのもうひとつのアクティビティも、フラグメントに移動させますね
- DetailActivity クラスの内容を WordListFragment クラスに移動させます
- 次のような手順になります
WordListFragment クラスに移植する手順
やることがいっぱい
うん。でも、さいしょに作ったフラグメントと作業はだいたい一緒。思ったよりは簡単なの
- DetailActivity から WordListFragment にコンパニオンオブジェクト(定数)をコピーします
- WordAdapter にある SEARCH_PREFIX への参照が WordListFragment への参照に更新されていることを確認します
- _binding 変数を追加します(この変数は nullable で初期値は null です)
- _binding 変数と同じ内容の binding という get-only な変数を追加します
- onCreateView() の中でレイアウトを生成します。_bindingの値をセットして、ルートview を返します
- onViewCreated() の中で次の設定をします
- RecyclerView への参照を取得します
- レイアウトマネージャとアダプターを設定します
- 項目に装飾を加えます
- インテントから文字を取得します
- フラグメントは intent プロパティを持っていません。フラグメントは通常、親となるアクティビティのインテントにアクセスすべきではありません
- ここではとりあえず extras を得るのに activity.intent(DetailActivity の intent ではなく親アクティビティの intent)を参照するように変更します
- onDestroyView() の中で _binding を null にリセットします
- DetailActivity() は onCreate() メソッドだけを残して他を削除します
- 最終的に AndroidManifest.xml を修正した上で DetailActivity.kt と activity_detail.xml は削除してしまいます
実際に DetailActivity クラスの内容を WordListFragment クラスに移動させる
さっそく行ってみますね
実際に DetailActivity の内容を WordListFragment に移動させてみます
WordListFragment に定数を移動する
プログラムで使う定数ですね
- コンパニオンオブジェクトを WordListFragment に移動します
companion object {
val LETTER = "letter"
val SEARCH_PREFIX = "https://www.google.com/search?q="
}
定数を使っているクラスの方も修正します

定数を参照している LetterAdapter クラスを修正する
- LetterAdapter クラスを開きます
- onClickListener() のところに移動します
- DetailActivity をインテントで起動するようになっています。putExtra() で DetailActivity.LETTER を参照していますが、定数は移動したのでこれを WordListFragment.LETTER に書き換えます
intent.putExtra(WordListFragment.LETTER, holder.button.text.toString())
定数を参照している WordAdapter クラスを修正する
- WordAdapter クラスを開きます
- onClickListener() のところに移動します
- DetailActivity.SEARCH_PREFIX を WordListFragment.SEARCH_PREFIX に置き換えます
val queryUrl: Uri = Uri.parse("${WordListFragment.SEARCH_PREFIX}${item}")
WordListFragment に View Binding のプロパティを設定する
View Binding でUI部品を参照できるように設定しますね
- WordListFragmentに戻って、FragmentWordListBinding?型の _binding を追加します
private var _binding: FragmentWordListBinding? = null
- つづけて次のように binding を get-only(取得専用)で設定します。これによって ? を使わずに view を参照できるようになります
private val binding get() = _binding!!
onCreateView() でレイアウトを生成する
レイアウトを生成しますね
- WordListFragment クラスに onCreateView() を実装します
- レイアウトを生成(inflate)して _binding 変数を割り当ててます
- ルートview を返します
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentWordListBinding.inflate(inflater, container, false)
return binding.root
}
onViewCreated() にUI部品への処理を記述する
UI部品を操作したときの処理はここに記述するんですね
うん。インテントが直接扱えなくなるので注意してくださいね
- WordListFragment クラスに onViewCreated() を実装します
- DetailActivity クラスの onCreate() にある recyclerView の設定をほぼそのまま移動させます
- インテントの extras からデータを取得している部分を activity?.intent?.extras? に修正します
- フラグメントには intent プロパティがありません
- かわりに、親になるアクティビティのインテントを activity?.intent? で参照できるようになっています
- onCreateView() でのレイアウト生成時に activity?.intent? で参照するデータが利用されます。しかし onCreateView() の時点でアクティビティが存在している保証はないのでこのコードは要注意です
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val recyclerView = binding.recyclerView
recyclerView.layoutManager = LinearLayoutManager(requireContext())
recyclerView.adapter = WordAdapter(activity?.intent?.extras?.getString(LETTER).toString(), requireContext())
recyclerView.addItemDecoration(
DividerItemDecoration(context, DividerItemDecoration.VERTICAL)
)
}
onDestroyView() を実装する(バインディングのリセット)
さいごにバインディングをリセットしますね
onDestroyView() で _binding 変数をリセットするようにします
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
おもったより簡単に書き換えられたかも
DetailActivity クラスを整理する
- すべての機能を DetailActivity クラスから WordListFragment クラスに移動しました
- onCreate() メソッド以外の部分を削除してしまいます
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityDetailBinding.inflate(layoutInflater)
setContentView(binding.root)
}
おおっ、すっきり
ここまでのまとめ
Android Studio でメニューから Run を選択して、エラーが出ないか確認しておくといいですね
この時点でビルドして実行することは可能です。ただし、期待するようには動作しません
書き換えたファイルはこんなかんじになりました
WordListFragment.kt
class WordListFragment : Fragment() { companion object { val LETTER = "letter" val SEARCH_PREFIX = "https://www.google.com/search?q=" } private var _binding: FragmentWordListBinding? = null private val binding get() = _binding!! override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { _binding = FragmentWordListBinding.inflate(inflater, container, false) return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val recyclerView = binding.recyclerView recyclerView.layoutManager = LinearLayoutManager(requireContext()) recyclerView.adapter = WordAdapter(activity?.intent?.extras?.getString(LETTER).toString(), requireContext()) recyclerView.addItemDecoration( DividerItemDecoration(context, DividerItemDecoration.VERTICAL) ) } override fun onDestroyView() { super.onDestroyView() _binding = null } }
LetterAdapter.kt
class LetterAdapter : RecyclerView.Adapter<LetterAdapter.LetterViewHolder>() { // Generates a [CharRange] from 'A' to 'Z' and converts it to a list private val list = ('A').rangeTo('Z').toList() /** * Provides a reference for the views needed to display items in your list. */ class LetterViewHolder(val view: View) : RecyclerView.ViewHolder(view) { val button = view.findViewById<Button>(R.id.button_item) } override fun getItemCount(): Int { return list.size } /** * Creates new views with R.layout.item_view as its template */ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LetterViewHolder { val layout = LayoutInflater .from(parent.context) .inflate(R.layout.item_view, parent, false) // Setup custom accessibility delegate to set the text read layout.accessibilityDelegate = Accessibility return LetterViewHolder(layout) } /** * Replaces the content of an existing view with new data */ override fun onBindViewHolder(holder: LetterViewHolder, position: Int) { val item = list.get(position) holder.button.text = item.toString() // Assigns a [OnClickListener] to the button contained in the [ViewHolder] holder.button.setOnClickListener { val context = holder.view.context // Create an intent with a destination of DetailActivity val intent = Intent(context, DetailActivity::class.java) // Add the selected letter to the intent as extra data // The text of Buttons are [CharSequence], a list of characters, // so it must be explicitly converted into a [String]. // intent.putExtra(DetailActivity.LETTER, holder.button.text.toString()) intent.putExtra(WordListFragment.LETTER, holder.button.text.toString()) // Start an activity using the data and destination from the Intent. context.startActivity(intent) } } // Setup custom accessibility delegate to set the text read with // an accessibility service companion object Accessibility : View.AccessibilityDelegate() { @RequiresApi(Build.VERSION_CODES.LOLLIPOP) override fun onInitializeAccessibilityNodeInfo( host: View?, info: AccessibilityNodeInfo? ) { super.onInitializeAccessibilityNodeInfo(host, info) // With `null` as the second argument to [AccessibilityAction], the // accessibility service announces "double tap to activate". // If a custom string is provided, // it announces "double tap to <custom string>". val customString = host?.context?.getString(R.string.look_up_words) val customClick = AccessibilityNodeInfo.AccessibilityAction( AccessibilityNodeInfo.ACTION_CLICK, customString ) info?.addAction(customClick) } } }
DetailActivity を削除する
MainActivity とちがって、DetailActivity はアプリの中でもうまったく使わないので削除してしまいますね
ファイルを消しちゃうだけじゃだめ?
うん、使っていたファイルを消したときは AndroidManifest.xml を修正するの
- DetailActivity のすべての機能を WordListFragment に移したので DetailActivity は削除できます
- DetailActivity.kt と activity_detail.xml を削除して、AndroidManifest.xml を修正します
削除の手順
- Project ペインで DetailActivity.kt を右クリックして Delete を選択します。ダイアログがでたら Safe Delete のチェックを外して OK します
- activity_detail.xml も同様に削除します
- AndroidManifest.xml を開いて次の DetailActivity の部分を削除します
<activity
android:name=".DetailActivity"
android:parentActivityName=".MainActivity" />
- DetailActivity.kt を削除したので、フラグメント2つ(LetterListFragment , WordListFragment)とアクティビティひとつ(MainActivity)になりました
- コードには DetailActivity を参照する部分がある(LetterAdapterクラスの中)ので、この時点でビルドしようとするとエラーになります
次回はナビゲーションを作成しちゃいますね