助けて欲しいです。何日もkotlinでネットワーク通信をしたいと取り組んでいるのですがうまくいきません。
参考にしているサイトは
https://qiita.com/naoi/items/5036adc8d33638911deb#buildgradleapp%E3%81%B8%E3%81%AE%E8%BF%BD%E8%A8%98
です。
やりたいことは
Android画面でボタンを押したらその時の時刻と、IDを送信する。
⬇️
ネットワーク上でphpを組んで、そこでIDと時刻をデータベースに登録する。
⬇️
そしてデータベースで登録ができたら、phpで「〇〇様登録完了」と出す。
⬇️
phpの「OO様登録完了」文字をAndroidのtextviewに表記させる。
といった流れです。いろいろ試しに試してコードがぐちゃぐちゃになったので一度スッキリさせてここにまとめておきます。
もはや組み方が分かりません。可能であれば上記の流れを達成するためのコードを下記コードに正解のコードを書き足していただけませんか?それ見て勉強していきたいです><
自分のわからないところをピックアップしました。(これで足りているか不安ですが、、、)
①そもそもサイトには【GETメソッドでHTTP通信する実装方法】のところにMyService.ktと書かれているがPOSTの場合でもこれが必要なのか。
②(上記が必要な場合)MyService.ktの定義の中身を今回の実装したいものではどのように組めばいいのかわからない。
③val postの中身の組み方がわからない。(わからないのでval post内はサイトからコピペした状態のままにしている)、そしてval postを非同期の中で宣言してみたが、この場所でいいのかわからない
④⭐️部分は非同期処理内でネットワーク通信を終えた後にTV.textに呼び出したいのだが、なんて書けばいいのかわからない。
MainActivity.kt
1import android.os.Build 2import androidx.appcompat.app.AppCompatActivity 3import android.os.Bundle 4import android.util.Log 5import android.widget.Button 6import android.widget.TextView 7import android.widget.Toast 8import kotlinx.coroutines.Dispatchers 9import kotlinx.coroutines.Job 10import kotlinx.coroutines.delay 11import kotlinx.coroutines.withContext 12import retrofit2.Retrofit 13import java.time.LocalDateTime 14 15class MainActivity : AppCompatActivity() { 16 17 // Retrofit本体 18 private val retrofit = Retrofit.Builder().apply { 19 baseUrl("http://10.0.2.2:3000/") 20 }.build() 21 22 val get = service.getRawResponseForPosts() 23 24 25 override fun onCreate(savedInstanceState: Bundle?) { 26 super.onCreate(savedInstanceState) 27 setContentView(R.layout.activity_main) 28 val TV : TextView = findViewById(R.id.TextView1) 29 30 31 32 // ボタンを押した時の処理 33 val btn : Button = findViewById(R.id.button1) 34 35 // ボタンを連打したときに何度も処理してしまうのを防ぐため。jobを設定する 36 var job: Job? = null 37 38 btn.setOnClickListener { 39 40 var nowTime = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 41 LocalDateTime.now() 42 } else { 43 TODO("VERSION.SDK_INT < O") 44 } 45 TV.text = nowTime.toString() 46 47 //下記にすることで連打したときに何度も処理されることを防げる。coroutinesが複数起動しなくなるということ。 48 if (job?.isActive == true) return@setOnClickListener 49 job = lifecycleScope.launch { 50 51 //result内のスコープがIOスレッドで実行される 52 withContext(Dispatchers.IO) { 53 val post = service.getRawResponseForPosts().also { 54 it.enqueue(object : Callback<List<Post>> { 55 override fun onFailure(call: Call<List<Post>>, t: Throwable) { 56 Toast.makeText(this@MainActivity, "通信エラー", Toast.LENGTH_SHORT).show() 57 Log.e("TEST", "通信エラー", t) 58 } 59 60 override fun onResponse(call: Call<List<Post>>, response: Response<List<Post>>) { 61 myViewModel.result.value = response.body().toString() 62 } 63 }) 64 } 65 } 66 67 //Main内のスレッドがIOスレッド内でメインスレッドも実行可能となる。 68 withContext(Dispatchers.Main) { 69 TV.text = ⭐️ 70 } 71 } 72 } 73 } 74 }
AndroidManifest.xml
1<?xml version="1.0" encoding="utf-8"?> 2<manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="com.example.myapplication"> 4 <uses-permission android:name="android.permission.INTERNET" /> 5 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> 6 7 <application 8 android:allowBackup="true" 9 android:icon="@mipmap/ic_launcher" 10 android:label="@string/app_name" 11 android:roundIcon="@mipmap/ic_launcher_round" 12 android:supportsRtl="true" 13 android:theme="@style/Theme.MyApplication"> 14 <activity 15 android:name=".MainActivity" 16 android:exported="true"> 17 <intent-filter> 18 <action android:name="android.intent.action.MAIN" /> 19 20 <category android:name="android.intent.category.LAUNCHER" /> 21 </intent-filter> 22 </activity> 23 </application> 24 25</manifest>
activity_main.xml
1<?xml version="1.0" encoding="utf-8"?> 2<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:app="http://schemas.android.com/apk/res-auto" 4 xmlns:tools="http://schemas.android.com/tools" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent" 7 tools:context=".MainActivity"> 8 9 <TextView 10 android:id="@+id/TextView1" 11 android:layout_width="wrap_content" 12 android:layout_height="wrap_content" 13 android:text="Hello World!" 14 app:layout_constraintBottom_toBottomOf="parent" 15 app:layout_constraintLeft_toLeftOf="parent" 16 app:layout_constraintRight_toRightOf="parent" 17 app:layout_constraintTop_toTopOf="parent" /> 18 19 <Button 20 android:id="@+id/button1" 21 android:layout_width="wrap_content" 22 android:layout_height="wrap_content" 23 android:text="Button" 24 app:layout_constraintBottom_toBottomOf="parent" 25 app:layout_constraintEnd_toEndOf="parent" 26 app:layout_constraintStart_toStartOf="parent" 27 app:layout_constraintTop_toBottomOf="@+id/TextView1" /> 28 29</androidx.constraintlayout.widget.ConstraintLayout>
build.gradle(:app)
1 2dependencies { 3 4 implementation 'androidx.core:core-ktx:1.7.0' 5 implementation 'androidx.appcompat:appcompat:1.4.1' 6 implementation 'com.google.android.material:material:1.5.0' 7 implementation 'androidx.constraintlayout:constraintlayout:2.1.3' 8 testImplementation 'junit:junit:4.13.2' 9 androidTestImplementation 'androidx.test.ext:junit:1.1.3' 10 androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' 11 12 def retrofit_version = "2.9.0" 13 implementation "com.squareup.retrofit2:retrofit:$retrofit_version" 14 implementation "com.squareup.retrofit2:converter-moshi:$retrofit_version" 15 implementation "com.squareup.okhttp3:logging-interceptor:4.9.0" 16 17 18 implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.1.0" 19 testImplementation 'junit:junit:4.13.2' 20 androidTestImplementation 'androidx.test.ext:junit:1.1.3' 21 androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' 22}
これより下3つのファイルは冒頭のサンプルURLを参考にして作成したファイルです。どう使うのか、そして今回僕がしたいことに必要なのか僕には理解が届きませんでしたがとりあえず作成しました。
MyService.kt
1import android.telecom.Call 2import okhttp3.RequestBody 3import okhttp3.ResponseBody 4import retrofit2.http.* 5import retrofit2.Call as Call1 6 7//URLのサブディレクトリやパスの設定 8interface MyService{ 9 10 @GET("posts") 11 fun getRawResponseForPosts(): Call<ResponseBody> 12 13 @POST("posts") 14 fun postRawRequestForPosts(@Body body:RequestBody):Call<ResponseBody> 15 16 @PUT("posts/{id}") 17 fun putRawRequestForPosts(@Path("id") id:String, @Body body:RequestBody):Call<ResponseBody> 18 19 @DELETE("posts/{id}") 20 fun deletePathParam(@Path("id") id:String ):Call<ResponseBody> 21 22}
自分が送信したい情報はIDと時間なのでここは書き換えました。⬇️
Post.kt
1data class Post( 2 3 val id: Int = 1111, 4 val time: String 5 6)
Util.kt
1object Util { 2 3 fun createJson(id:Int,time:String):String 4 ="{" + 5 " \"id\": \"${id}\"," + 6 " \"time\": \"${time}\"," + 7 "}" 8}
最後にAPI接続先のphpファイルです。これはここではざっくりとこんな感じという風に書かせていただきます。try catch やデータベース情報などこの質問に不必要なものは外しています。
php
1<?php 2 3 4$id=$_POST['id']; 5$time=$_POST['time']; 6 7 8データベース接続の処理 9データベース登録の処理 10 11登録成功なら 12echo'〇〇様登録完了'; 13
以上です。
長々とした質問ですみません。数日戦っても組み方に見当がつかないのでどなたかご教授よろしくお願いします。
なお、自分の質問にミスがあればすぐに訂正致しますので気軽にコメント下さい。

回答1件
あなたの回答
tips
プレビュー