- 投稿日:2020-01-22T21:16:25+09:00
[備忘録]Kotlinでシングルトンクラスの作成方法
シングルトンなクラスの作成方法
書き方その1
マルチスレッドに対応しています。
// シングルトンクラス class StatefulContext { companion object { // シングルトンインスタンスの宣言 private var instance: StatefulContext? = null // インスタンス取得 fun getInstance() = instance ?: synchronized(this) { instance ?: StatefulContext().also { instance = it } } } }書き方その2
1番目と同じです
// シングルトンクラス internal object StatefulContext { // シングルトンインスタンスの宣言 var instance: StatefulContext? = null @get:Synchronized val getInstance: StatefulContext? // インスタンス取得 get() { if (instance == null) { instance = StatefulContext() } return instance } }書き方その3
// シングルトンクラス class StatefulContext { // static領域 companion object { // シングルトンインスタンスの宣言 private var instance: StatefulContext = StatefulContext() // インスタンス取得 fun getInstance() : StatefulContext { return instance } } }これはあくまで一例ですが、みなさんが使用する場合は、StatefulContextの部分を適宜、他のクラスに変更してください。
インスタンス取得方法
以下ソースコード
StatefulContext.getInstance()getInstance()を呼べば、そのインスタンスは使い回すことができます。
参考URL
- デザインパターン「Singleton」
- 投稿日:2020-01-22T19:11:40+09:00
[kotlin] RecyclerViewの実装、クリックリスナー付き
今回やること
今更だけど kotlin でRecyclerViewを実装する。(自分用の備忘録としてほしかった)
クリックイベント処理の記事が少なかったのでタップしたらトーストを表示するのものを作ってみる。
これ↓!
RecyclerViewの配置
android studio のパレットペインを使って Containersの中にある RecyclerViewをレイアウトに追加する。ドラッグしたらプロジェクトにRecyclerViewが追加され依存関係とかも最新のものが自動的に追加される。
一応、依存関係
build.gradledependencies { implementation 'androidx.recyclerview:recyclerview:1.1.0' }レイアウトファイル
activity_main.xml<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/simpleRecyclerView" android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>RecyclerViewの中身
画像とテキストだけの簡単なレイアウト
recyclerview_item.xml<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/LinearLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="10dp" android:background="@android:color/white" android:elevation="4dp" android:orientation="horizontal"> <ImageView android:id="@+id/sampleImg" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="10dp" app:srcCompat="@mipmap/ic_launcher_round" /> <TextView android:id="@+id/sampleTxt" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center" android:text="TextView" android:textSize="30sp" /> </LinearLayout>
elevation
つけとけばいい感じに影をつけてくれる。(※minSdkVersion:21以上必須)アダプターをつくる
RecyclerView.Adapter
を継承してつくるCustomAdapter.kt//// customListはrecyclerViewのコンテンツとしてに表示するString配列のデータ class CustomAdapter(private val customList: Array<String>) : RecyclerView.Adapter<CustomAdapter.CustomViewHolder>(){ // ViewHolderクラス(別ファイルに書いてもOK) class CustomViewHolder(val view: View): RecyclerView.ViewHolder(view) { val sampleImg = view.sampleImg val sampleTxt = view.sampleTxt } // getItemCount onCreateViewHolder onBindViewHolderを実装 // 上記のViewHolderクラスを使ってViewHolderを作成 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder { val layoutInflater = LayoutInflater.from(parent.context) val item = layoutInflater.inflate(R.layout.recyclerview_item, parent, false) return CustomViewHolder(item) } // recyclerViewのコンテンツのサイズ override fun getItemCount(): Int { return customList.size } // ViewHolderに表示する画像とテキストを挿入 override fun onBindViewHolder(holder: CustomViewHolder, position: Int) { holder.view.sampleImg.setImageResource(R.mipmap.ic_launcher_round) holder.view.sampleTxt.text = customList[position] } }アダプターをセット
作ったアダプターをrecyclerViewにセットする
MainActivity.ktclass MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) /// 表示するテキスト配列を作る [テキスト0, テキスト1, ....] val list = Array<String>(10) {"テキスト$it"} val adapter = CustomAdapter(list) val layoutManager = LinearLayoutManager(this) // アダプターとレイアウトマネージャーをセット simpleRecyclerView.layoutManager = layoutManager simpleRecyclerView.adapter = adapter simpleRecyclerView.setHasFixedSize(true) } }ここまで出来たらとりあえずrecyclerViewでコンテンツの表示はできているはず。ここからクリックイベントを実装していく。
リスナーを作る
ボタンにクリックリスナーをつけるみたいに出来ないのでカスタムリスナーを作ってあとで実装する。
先ほどのCustomAdapter.kt
を以下のように修正加筆する。CustomAdapter.kt//// customListはrecyclerViewのコンテンツとしてに表示するString配列のデータ class CustomAdapter(private val customList: Array<String>) : RecyclerView.Adapter<CustomAdapter.CustomViewHolder>(){ // リスナー格納変数 lateinit var listener: OnItemClickListener // ViewHolderクラス(別ファイルに書いてもOK) class CustomViewHolder(val view: View): RecyclerView.ViewHolder(view) { val sampleImg = view.sampleImg val sampleTxt = view.sampleTxt } // getItemCount onCreateViewHolder onBindViewHolderを実装 // 上記のViewHolderクラスを使ってViewHolderを作成 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder { val layoutInflater = LayoutInflater.from(parent.context) val item = layoutInflater.inflate(R.layout.recyclerview_item, parent, false) return CustomViewHolder(item) } // recyclerViewのコンテンツのサイズ override fun getItemCount(): Int { return customList.size } // ViewHolderに表示する画像とテキストを挿入 override fun onBindViewHolder(holder: CustomViewHolder, position: Int) { holder.view.sampleImg.setImageResource(R.mipmap.ic_launcher_round) holder.view.sampleTxt.text = customList[position] // タップしたとき holder.view.setOnClickListener { listener.onItemClickListener(it, position, customList[position]) } } //インターフェースの作成 interface OnItemClickListener{ fun onItemClickListener(view: View, position: Int, clickedText: String) } // リスナー fun setOnItemClickListener(listener: OnItemClickListener){ this.listener = listener } }リスナーの実装
MainActivity.kt
で実装するMainActivity.ktclass MainActivity : AppCompatActivity(){ override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) /// 表示するテキスト配列を作る [テキスト1, テキスト2, ....] val list = Array<String>(10) {"テキスト$it"} val adapter = CustomAdapter(list) val layoutManager = LinearLayoutManager(this ) // アダプターとレイアウトマネージャーをセット simpleRecyclerView.layoutManager = layoutManager simpleRecyclerView.adapter = adapter simpleRecyclerView.setHasFixedSize(true) // インターフェースの実装 adapter.setOnItemClickListener(object:CustomAdapter.OnItemClickListener{ override fun onItemClickListener(view: View, position: Int, clickedText: String) { Toast.makeText(applicationContext, "${clickedText}がタップされました", Toast.LENGTH_LONG).show() } }) } }匿名オブジェクト作って渡したりちょっと見ずらいとこあるけど完成。
- 投稿日:2020-01-22T19:11:40+09:00
[kotlin] RecyclerViewの実装、クリックイベント付き
今回やること
今更だけど kotlin でRecyclerViewを実装する。(自分用の備忘録としてほしかった)
クリックイベント処理の記事が少なかったのでタップしたらトーストを表示するのものを作ってみる。
これ↓!
RecyclerViewの配置
android studio のパレットペインを使って Containersの中にある RecyclerViewをレイアウトに追加する。ドラッグしたらプロジェクトにRecyclerViewが追加され依存関係とかも最新のものが自動的に追加される。
一応、依存関係
build.gradledependencies { implementation 'androidx.recyclerview:recyclerview:1.1.0' }レイアウトファイル
activity_main.xml<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/simpleRecyclerView" android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>RecyclerViewの中身
画像とテキストだけの簡単なレイアウト
recyclerview_item.xml<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/LinearLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="10dp" android:background="@android:color/white" android:elevation="4dp" android:orientation="horizontal"> <ImageView android:id="@+id/sampleImg" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="10dp" app:srcCompat="@mipmap/ic_launcher_round" /> <TextView android:id="@+id/sampleTxt" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center" android:text="TextView" android:textSize="30sp" /> </LinearLayout>
elevation
つけとけばいい感じに影をつけてくれる。(※minSdkVersion:21以上必須)アダプターをつくる
RecyclerView.Adapter
を継承してつくるCustomAdapter.kt//// customListはrecyclerViewのコンテンツとしてに表示するString配列のデータ class CustomAdapter(private val customList: Array<String>) : RecyclerView.Adapter<CustomAdapter.CustomViewHolder>(){ // ViewHolderクラス(別ファイルに書いてもOK) class CustomViewHolder(val view: View): RecyclerView.ViewHolder(view) { val sampleImg = view.sampleImg val sampleTxt = view.sampleTxt } // getItemCount onCreateViewHolder onBindViewHolderを実装 // 上記のViewHolderクラスを使ってViewHolderを作成 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder { val layoutInflater = LayoutInflater.from(parent.context) val item = layoutInflater.inflate(R.layout.recyclerview_item, parent, false) return CustomViewHolder(item) } // recyclerViewのコンテンツのサイズ override fun getItemCount(): Int { return customList.size } // ViewHolderに表示する画像とテキストを挿入 override fun onBindViewHolder(holder: CustomViewHolder, position: Int) { holder.view.sampleImg.setImageResource(R.mipmap.ic_launcher_round) holder.view.sampleTxt.text = customList[position] } }アダプターをセット
作ったアダプターをrecyclerViewにセットする
MainActivity.ktclass MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) /// 表示するテキスト配列を作る [テキスト0, テキスト1, ....] val list = Array<String>(10) {"テキスト$it"} val adapter = CustomAdapter(list) val layoutManager = LinearLayoutManager(this) // アダプターとレイアウトマネージャーをセット simpleRecyclerView.layoutManager = layoutManager simpleRecyclerView.adapter = adapter simpleRecyclerView.setHasFixedSize(true) } }ここまで出来たらとりあえずrecyclerViewでコンテンツの表示はできているはず。ここからクリックイベントを実装していく。
リスナーを作る
ボタンにクリックリスナーをつけるみたいに出来ないのでカスタムリスナーを作ってあとで実装する。
先ほどのCustomAdapter.kt
を以下のように修正加筆する。CustomAdapter.kt//// customListはrecyclerViewのコンテンツとしてに表示するString配列のデータ class CustomAdapter(private val customList: Array<String>) : RecyclerView.Adapter<CustomAdapter.CustomViewHolder>(){ // リスナー格納変数 lateinit var listener: OnItemClickListener // ViewHolderクラス(別ファイルに書いてもOK) class CustomViewHolder(val view: View): RecyclerView.ViewHolder(view) { val sampleImg = view.sampleImg val sampleTxt = view.sampleTxt } // getItemCount onCreateViewHolder onBindViewHolderを実装 // 上記のViewHolderクラスを使ってViewHolderを作成 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder { val layoutInflater = LayoutInflater.from(parent.context) val item = layoutInflater.inflate(R.layout.recyclerview_item, parent, false) return CustomViewHolder(item) } // recyclerViewのコンテンツのサイズ override fun getItemCount(): Int { return customList.size } // ViewHolderに表示する画像とテキストを挿入 override fun onBindViewHolder(holder: CustomViewHolder, position: Int) { holder.view.sampleImg.setImageResource(R.mipmap.ic_launcher_round) holder.view.sampleTxt.text = customList[position] // タップしたとき holder.view.setOnClickListener { listener.onItemClickListener(it, position, customList[position]) } } //インターフェースの作成 interface OnItemClickListener{ fun onItemClickListener(view: View, position: Int, clickedText: String) } // リスナー fun setOnItemClickListener(listener: OnItemClickListener){ this.listener = listener } }リスナーの実装
MainActivity.kt
で実装するMainActivity.ktclass MainActivity : AppCompatActivity(){ override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) /// 表示するテキスト配列を作る [テキスト1, テキスト2, ....] val list = Array<String>(10) {"テキスト$it"} val adapter = CustomAdapter(list) val layoutManager = LinearLayoutManager(this ) // アダプターとレイアウトマネージャーをセット simpleRecyclerView.layoutManager = layoutManager simpleRecyclerView.adapter = adapter simpleRecyclerView.setHasFixedSize(true) // インターフェースの実装 adapter.setOnItemClickListener(object:CustomAdapter.OnItemClickListener{ override fun onItemClickListener(view: View, position: Int, clickedText: String) { Toast.makeText(applicationContext, "${clickedText}がタップされました", Toast.LENGTH_LONG).show() } }) } }匿名オブジェクト作って渡したりちょっと見ずらいとこあるけど完成。
- 投稿日:2020-01-22T10:13:35+09:00
[Android]端末からサーバへ画像のアップロード
はじめに
Androidで画像をPOSTし、サーバに保存する機能でてこずったため自分の備忘録兼、アウトプットとして書きます。プログラムのお仕事半年もしてないからいろいろおかしいかもしれないけど許してね。
追記
ご指摘を受けました。ありがとうございます!
OkHTTP2はobsoletes扱いです。最新の4.3.1を使うようにしましょう。
https://square.github.io/okhttp/changelog_3x/#version-300-rc1
https://square.github.io/okhttp/changelog/環境
AndroidStudioでOkHttpを利用しています。
OkHttp導入
- AndroidStudio画面左上の「Android」を「プロジェクト」に切り替え。
- [app]内のbuild.gradleを開く。
dependencies内にimplementation 'com.squareup.okhttp:okhttp:2.7.5'
を追記。(2.7.5はvarsionによって変えてください。)- dependencies内に
implementation 'com.squareup.okhttp:okhttp:4.3.1'
を追記。 (2020/1/24 変更)build.gradle//~~省略~~ dependencies{ //~~省略~~ implementation 'com.squareup.okhttp:okhttp:4.3.1'//追記 }完了。
AsyncTask
Http通信で送るので非同期で行う。
OkHttpTask.javaimport android.os.AsyncTask; import android.util.Log; import java.io.File; import java.io.IOException; import okhttp3.MediaType; import okhttp3.MultipartBody; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; public class HttpTask extends AsyncTask<String, Void, String> { String responseBody; public HttpTask(){} @Override protected String doInBackground(String... params) { String url = "送るURL"; MediaType media = MediaType.parse("multipart/form-data"); try { File file = new File(params[0]); String FileName = file.getName(); String boundary = String.valueOf(System.currentTimeMillis()); RequestBody requestBody = new MultipartBody.Builder(boundary).setType(MultipartBody.FORM) .addFormDataPart("file", FileName, RequestBody.create(media, file)) .build(); Request request = new Request.Builder() .url(url) .post(requestBody) .build(); OkHttpClient client = new OkHttpClient(); Response response = client.newCall(request).execute(); responseBody = response.body().string(); return responseBody; } catch (IOException e) { e.printStackTrace(); } return responseBody; } @Override protected void onPostExecute(String result) { Log.d("a",result); } }いろいろ変更したので書き直しました。また、変更に伴って
java.io.IOException: Cleartext HTTP traffic to example.com not permitted
のようなエラーが表示されることがあるかと思います。
これはデフォルトでHTTPS通信になったので、HTTP通信を許可する方法を書いておく必要があるからです。方法についてはこちらの方が詳しく書かれているのでどうぞ。
古いコード
OkHttpTask_old.java/**削除 import com.squareup.okhttp.MediaType; import com.squareup.okhttp.MultipartBuilder; import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.Request; import com.squareup.okhttp.RequestBody; import com.squareup.okhttp.Response; */ import okhttp3.MediaType; import okhttp3.MultipartBody; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; public class OkHttpTask extends AsyncTask<String, Void, String> { public OkHttpTask(){} @Override protected String doInBackground(String... params) { //ポスト先のURL String url = "http://"; File file = new File(params[0]); /**削除 *ここでPOSTする内容を設定 RequestBody requestBody = new MultipartBuilder() .type(MultipartBuilder.FORM) .addFormDataPart("file", file.getName(), RequestBody.create(MediaType.parse("image/jpg"), file)) .build(); */ //ここでPOSTする内容を設定(こっちに変更) RequestBody requestBody = new MultipartBody.Builder() .addFormDataPart("file", file.getName(), RequestBody.create(MediaType.parse("image/jpg"), file)) .build(); OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url(url) .post(requestBody) .build(); String result=""; try { Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); { result = response.body().string(); } } catch (Exception e) {} return result; } @Override protected void onPostExecute(String result) { Log.d("end:",result); } } */MainActivity
MainActivity.javapublic class MainActivity extends AppCompatActivity { //送る画像のURI private Uri _imageUri; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //ここで呼び出し new OkHttpTask().execute(url); }受け取る側
Postされたファイルを保存するだけ。
UpLoad.java@WebServlet("/Upload") @MultipartConfig(location = "保存場所") public class upload extends HttpServlet { public void doPost(HttpServletRequest req,HttpServletResponse res) throws IOException, ServletException { String name="no_name"; //multipart/form-dataによって提供されるこのリクエストのすべてのPart要素を取得 for (Part part : req.getParts()) { //名前の取得 for (String cd : part.getHeader("Content-Disposition").split(";")) { String str = cd.trim(); if (str.startsWith("filename")) { String str2 = str.substring(cd.indexOf('=') + 1).trim().replace("\"", ""); File f = new File(str2); name = f.getName(); part.write(name); } } } } }参考リンク
OkHttpを初めて使ってみた話
https://qiita.com/LyricalMaestro0/items/698c77f5a964b5658bbb