20200122のAndroidに関する記事は4件です。

[備忘録]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

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[kotlin] RecyclerViewの実装、クリックリスナー付き

今回やること

今更だけど kotlin でRecyclerViewを実装する。(自分用の備忘録としてほしかった)
クリックイベント処理の記事が少なかったのでタップしたらトーストを表示するのものを作ってみる。
これ↓!

RecyclerViewの配置

android studio のパレットペインを使って Containersの中にある RecyclerViewをレイアウトに追加する。ドラッグしたらプロジェクトにRecyclerViewが追加され依存関係とかも最新のものが自動的に追加される。

一応、依存関係

build.gradle
dependencies {
    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.kt
class 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.kt
class 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()
            }
        })
    }
}

匿名オブジェクト作って渡したりちょっと見ずらいとこあるけど完成。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[kotlin] RecyclerViewの実装、クリックイベント付き

今回やること

今更だけど kotlin でRecyclerViewを実装する。(自分用の備忘録としてほしかった)
クリックイベント処理の記事が少なかったのでタップしたらトーストを表示するのものを作ってみる。
これ↓!

RecyclerViewの配置

android studio のパレットペインを使って Containersの中にある RecyclerViewをレイアウトに追加する。ドラッグしたらプロジェクトにRecyclerViewが追加され依存関係とかも最新のものが自動的に追加される。

一応、依存関係

build.gradle
dependencies {
    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.kt
class 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.kt
class 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()
            }
        })
    }
}

匿名オブジェクト作って渡したりちょっと見ずらいとこあるけど完成。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[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.java
import 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.java
public 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

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む