20200724のAndroidに関する記事は8件です。

オレトラストネットワークでちゃっちゃとファイル共有

家にファイルサーバーってあります?動かしたいけどねえ・・って事無いですか??

  • 電気代とか置き場所とかの理由で外付けUSB使ってる
  • SaaSのファイルサービスはどうしても容量課金や通信パケ代が気になる

本来、ファイルサーバーで最重要であるべきセキュリティ要件よりも、
もっと他の理由で使ってなかったりしませんか?
でも家庭ネットは信頼してますよね?だから、もっとこう、サクっと共有してえなあ。

<!-- じゃファイル共有すりゃ良い? -->

そういう人向けにAirDopあるやん

はい。でもあれってベンダーロックされてる感がないすか?
対応してないマイコンだの機器があるとやっぱファイルサーバーあればなーって思う。
OSSが頑張って実装してる例もあるけど対応機器がどんどん増えてく気はしないし。

我々は殆どの機器がしゃべれるプロトコルを知ってるはず、そうHTTP!

有線、無線関係なく、IPがあれば準備OK。それがHTTPの破壊力のスゴさ。
HTTPベースで超簡単にファイル共有!
車輪の再発明感ありますが、UXサイドに倒した実装を念頭に作ってみました。

/* ここにいるよ! */

このツールはこんな機能があります。

  • Windows、Linux、有線ディスクトップ、無線ノート、ラズパイなど他機種対応
  • Go言語なのでバイナリいっこ置けば準備OK
  • 二重同期しないようファイルのハッシュ値を参照して同じファイルは同期除外にします
  • IPとか調べないでも同期してくれる自動同期モードを付けました

autosync.gif

詳しくはリポジトリ見てくださいな。

=begin こんな使い方もアリ! =end

単純なHTTPのクラサバ構成なので柔軟性がとても高いです。こんな使い方もできるぞ。

パーティ転送モード

メールとかSlackで
「会議の資料は以下です。各自入手してください。
 \fileserver\会議20200715\dookie.pptx

あら、面倒!?

  • 会議始まったらツールを自動サーバモードで起動
  • 会議に来た人にトークンを教えて自動クライアントで起動
  • 多人数にどんどこ転送開始!

よし、拡散!

party.gif

バケツリレー転送

A、B、Cサーバにhostsとか同じデータを配布したい。
でもA→B→Cでセグメントが違うのでrsyncとかで一発で配布できない。

あら、面倒!?

  • C→B→Aの順にポート番号を変えてサーバモードとクライアントモードで2つ起動する。
  • Aにファイルを置くと順繰りでCまで転送されていきます。

よし、多重!

relay.gif

VPN踏み台転送

SSHで入る踏み台とデータ同期しておきたい。でもWinSCPとかツールインストールするの情シスの許可要るよなー

あら、面倒!?

  • 転送先でサーバモードで起動する。バイナリ一個置くだけ。
  • お手元の端末からSSHポートフォワードで転送先のサービスポートに接続
  • バイナリ消して証拠隠滅

よし、転送!

ssh.gif

=pod ということで =cut

HTTPつよいのは分かるけど、ファイアウォールが立ちはだかってるって?
大丈夫だよ、家庭内はなんだし、全開放しようぜ。w
というか家族が同居している場合は家庭内ネットワークはゼロトラストネットワーク

次号、スマホ用クライアント開発編に続く!

追伸

「Syncthingって知ってる?参考になると思うから使ってみたらどうだい?」
というアドバイスを頂きましたので調査中・・・
プロダクトとして一㍉も敵わないが何か実装できるとこないかなーって思ってるところ。

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

大学生が1週間でFlutterアプリを学んでリリースした過程(6日目)

こんにちはシオンです。

今日で6日目、残すところあと2日となりました。
計画通りに行けば、コードをかけるのは今日が最後の日です。現状としては5画面あるうちの2画面の画面構成まで、処理はひとつもかいていなく、また書き方もわからないため、進捗率としては5%...よくて8%ほどでしょうか。

やばいですね。でも期限はもう決まってしまっているのでやり切りましょう。途中までで終わらないよりも、終わらせる。今回は60点でもいいから終わらせることが大事なのです。

では、時間がないので(本当に!)やっていきます。

目次

■実装する処理の確認
■画面遷移を学ぶ
■残りの画面を作って画面遷移のルートを繋ぐ
■まとめ

■実装する処理の確認

昨日3画面の実装をしてFlutterでの画面の配置に関してはなんとなくわかってきました。
残り3画面は処理を実装するのと同時にプログラミングしていきます。
今回実装する残りの処理としては
・画面遷移
・入力した文字を読み取って表示
・カウントアップ
この3つです。

実装するためにはどうやって実装すればいいのかを知らなければいけないので、やり方を学んでいきましょう。

■画面遷移を学ぶ

まず、画面遷移をするためには遷移元の画面と遷移先の画面が必要で、これを行き来することが画面遷移になります。
Flutterではこの画面のことを「ルート(route)」、ルート同士の行き来のことを「ナビゲーション 」というらしいです。
ルートはもう用意できているので、画面遷移を実装するためにはナビゲーションを学べば良さそうです。

見てみたところ、次の画面に行くためにはNavigator.push、前の画面に戻るためにはNavigator.popというメソッドを呼び出せば良いそうです。
つまり、画面遷移をしたいタイミングでボタンを押した時にこのメソッドを呼び出してあげれば完了ですね。
早速やってみます。

1画面目から
1.png

2画面目へ
2.png

画像だと全く遷移してるからわからないですね。。
でもできています。しっかりと。
想像してください。
最初の画面で、愚痴を吐き出すボタンを押すと右にスライドして画面遷移し吐き出す画面に、そして左上の矢印をタップすると左にスライドして画面遷移しました。
ぜひ想像してください。(私には画面が遷移する瞬間をスクショで捉えるスキルも時間もありませんでした。)

これで画面遷移ができるようになりました!素直に嬉しいです。プログラミング楽しい笑

■残りの画面を作って画面遷移のルートを繋ぐ

画面遷移ができたので、最後の画面まで作って一旦表示だけ実装してしまいましょう。

まず3画面目
3.png

次の画面へ
4.png

そしてラスト
5.png

これで全ての画面を移動することができるようになりました。よしよし。

あとは細かな機能の実装をしていきます。
実装する機能としては
・2画面目でストレスLvを表示
・3画面目に2画面目で入力した愚痴タイトルを表示
・乗り越えた数のカウントと保存
これを実装すれば晴れて完成です!

■まとめ

なんとか見えてきましたね。ゴールが。
ただ、すみません。明日の朝がどうしても早いので今日はここまでにしておきます。

リリースはできなくても申請は絶対にします。
そして間に合わなかった理由をAppleとGoogleのせいにします。

明日ラストやり切りましょう!

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

Groupieでclickイベントを実装する

Groupieでのレンダリングは前に実装したんですが, Groupieでレンダリングしたリストに対してClickListenerをつけていきたいと思います.
github:

[https://github.com/WallyNegima/android_practice:embed:cite]

interfaceとAdapterを用意する

クリック時の振る舞いはinterfaceとしてAdapterに渡してあげます.
adapterは受け取ったinterfaceをListのそれぞれのItemに更に渡してあげる感じです.

用意するinterfaceはこんな感じです. 今回はMainActivityの中に作りました

interface MainListItemClickListener {
        fun onItemClick(
            itemId: String
        )
}

adapterはGroupAdapterを継承します.
この時, GroupieでレンダリングするItemにlistenerを渡してあげます

class ListAdapter(private val listener: MainActivity.MainListItemClickListener) :
    GroupAdapter<GroupieViewHolder>() {
    fun updateList(list: List<MainActivity.Item>) {
        update(list.map {
            TopListItem(
                text = it.text,
                itemId = it.itemId,
                listener = listener
            )
        })
    }
}

TopListItemはこんな感じです.
itemIdは, クリックしたときにどのitemがクリックされたかを判別するために用意してます. IntでもStringでも何でもOKです.
```
class TopListItem(
private val text: String,
private val itemId: String,
private val listener: MainActivity.MainListItemClickListener
) : BindableItem() {
override fun getLayout() = R.layout.item_top_list

override fun bind(viewBinding: ItemTopListBinding, position: Int) {
    viewBinding.button.text = text
    viewBinding.button.setOnClickListener {
        listener.onItemClick(
            itemId = itemId
        )
    }
}

override fun initializeViewBinding(view: View): ItemTopListBinding {
    return ItemTopListBinding.bind(view)
}

}
```

intefaceの中身を実装

onCreate関数の中でadapterを生成します. このときにinterfaceの中身を実装します.
無名クラスを使いました.

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        val adapter = ListAdapter(object : MainListItemClickListener {
            override fun onItemClick(itemId: String) {
                itemClickHandler(itemId)
            }
        })

        binding.recyclerView.adapter = adapter
}

 private fun itemClickHandler(itemId: String) {
        when (itemId) {
            VIEW_A -> {
                val intent = Intent(this, ViewAActivity::class.java)
                startActivity(intent)
            }
            VIEW_B -> {
                val intent = Intent(this, ViewBActivity::class.java)
                startActivity(intent)
            }
        }
    }

最終的にはこんな感じで動作します.

Image from Gyazo

[https://github.com/WallyNegima/android_practice:embed:cite]

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

【Android】遅延処理・非同期処理を使って時間差でViewに反映させる

Handler(遅延処理)

image.png

3つのTextViewに1秒ずつテキストをセットしてみます。

MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    private Handler handler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void btnOnClick(View view) {

        final TextView txt1 = findViewById(R.id.txt1);
        final TextView txt2 = findViewById(R.id.txt2);
        final TextView txt3 = findViewById(R.id.txt3);

        txt1.setText("開始");

        //Runnableインターフェースのrunメソッドをオーバーライドしている。
        //そしてpostDelayedメソッドの引数としてrunメソッドを利用している。
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                txt2.setText("1秒後");
            }
        }, 1000);

        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                txt3.setText("2秒後");
            }
        }, 2000);
    }


activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="開始"
        android:onClick="btnOnClick"/>

    <TextView
        android:id="@+id/txt1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/txt2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/txt3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

AsyncTask(非同期処理)

※AsyncTaskはAndroid11から非推奨になるようです。

こちらも3つのTextViewに時間差で文字セット。
activity_main.xmlは遅延処理のソースと同じ。

AsyncText.java
import android.content.Context;
import android.os.AsyncTask;
import android.widget.TextView;
import java.lang.ref.WeakReference;

public class AsyncText extends AsyncTask<String,String,String> {
    //WeakReferenceにするとリークを防げる
    private WeakReference<TextView> txt1;
    private WeakReference<TextView> txt2;
    private WeakReference<TextView> txt3;

    AsyncText(Context context) {
        //Viewの取得
        super();
        MainActivity activity = (MainActivity)context;
        txt1 = new WeakReference<>((TextView)activity.findViewById(R.id.txt1));
        txt2 = new WeakReference<>((TextView)activity.findViewById(R.id.txt2));
        txt3 = new WeakReference<>((TextView)activity.findViewById(R.id.txt3));
    }

    // 非同期処理を開始する前
    @Override
    protected void onPreExecute() {
        txt1.get().setText("開始前");
    }

    // 非同期処理の途中経過
    @Override
    protected void onProgressUpdate(String... values) {
        txt2.get().setText(values[0]);
    }

    // 非同期処理を終了した後
    @Override
    protected void onPostExecute(String result) {
        txt3.get().setText(result);

    }

    // 非同期処理をキャンセル
    @Override
    protected void onCancelled() {
    }


    //メインスレッドとは別のスレッドで実行される
    //ここに非同期で行いたい処理を書く
    @Override
    protected String doInBackground(String... strings) {
        publishProgress("途中");// onProgressUpdateを呼び出す

        //1秒待つ
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //戻り値はonPostExecuteに引数として渡される
        return strings[0];
    }
}
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;

public class MainActivity extends AppCompatActivity {
    private Handler handler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void btnOnClick(View view) {
        AsyncText asyncText = new AsyncText(this);
        asyncText.execute("非同期処理完了");//doInBackgroundメソッドが呼び出される
    }
}

Thread.sleep(失敗例)

これだと2秒後に全TextViewが一気に表示されてしまう。

MainActivity.java
package to.msn.wings.copy;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    private Handler handler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void btnOnClick(View view) throws InterruptedException {

        final TextView txt1 = findViewById(R.id.txt1);
        final TextView txt2 = findViewById(R.id.txt2);
        final TextView txt3 = findViewById(R.id.txt3);

        txt1.setText("開始");
        Thread.sleep(1000);
        txt2.setText("1秒後");
        Thread.sleep(1000);
        txt3.setText("2秒後");
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

機種変更をするときに気をつけるべきこと

機種変更したときに,失敗したな..っと思ったことがあったため,次変更するときの備忘録として残しておきます.そんな高性能でなくても低スペックでもいいよ..って思っていたのですが,実際に普段使っている機能がなかったときにものすごく不便に感じたため,押さえておくべき機能を列挙しておきます.当たり前が当たり前じゃなかったんやな..

生体認証が付いているかどうか

携帯の解錠

今や,携帯にロックをかけるのが当たり前になってきいますが,番号やパターンを入力するのは面倒.そこで,生体認証ですぐに携帯のロックを解除することができます.
- 指紋認証
- 顔認証
実用化されている認証方式はこの2つ.特に指紋認証は便利.マスクをつけていても,暗い場所にいても安定的に認証することが可能です.

パスワード管理アプリ

また,パスワード管理アプリの認証のマスターパスワードとして,生体認証に置き換えることができます.今やさまざまなサイトやアプリで会員IDとパスワードの設定が行われており,パスワード管理アプリを使われている方も多いかと思います.そのマスターパスワードをいちいち入力するのは面倒なため,生体認証に置き換えてパスワード管理アプリを開くことができます.しかし,現在(2020/07/24)ではAndroidの場合は顔認証で置き換えることはできず,指紋認証でないと解錠することが叶いません.iPhoneだと顔認証でも対応しているアプリがあるようです.

モバイル通信のON/OFFが切り替えやすいかどうか

僕はWi-Fi環境下で作業することも多いため,あまりモバイル通信を使わないです.そのため,通信量が最も少ない契約プランに入り,基本的にモバイル通信はOFFにして,外に出かけるときのみONに切り替えています.設定から,どの機種でもモバイル通信のON/OFFは切り替えられますが,そこまで移動しなくても,たやすく移動できれば嬉しいです.そのため,ホーム画面からすぐON/OFFが切り替えられる機種を選びましょう.

イヤホンジャックがあるかどうか

ほとんど付いているかと思いますが,最近のiPhoneではなくなりましたね..ある程度妥協しないといけなくなってくるかもです.

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

android firebase Auth email&passwordでログインする処理memo

onCreateメソッド内でFirebaseAuthのインスタンスを取得しておきます

LoginActivity.kt
class LoginActivity : AppCompatActivity() {

    companion object {
        private const val RC_SIGN_IN = 120
    }

    private lateinit var loginViewModel: LoginViewModel
    private lateinit var mAuth: FirebaseAuth
    private lateinit var googleSignInClient: GoogleSignInClient

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        //onCreateメソッド内でFirebaseAuthのインスタンスを取得しておきます
        mAuth = FirebaseAuth.getInstance()

ログイン処理

TaskAuthResult 操作の結果に
public Task < AuthResult > signInWithEmailAndPassword (String email、String password)
指定されたメールアドレスとパスワードでユーザーのサインイン

LoginActivity.kt
private fun loginEmailUser() {
        val email: String = username.text.toString()
        val password: String = password.text.toString()

        //入力欄が空白だったらエラーメッセージ
        if (email == "") {
            val ts = Toast.makeText(this@LoginActivity, "please write email.", Toast.LENGTH_SHORT)
            ts.setGravity(Gravity.CENTER, 0, 0)
            ts.show()
        } else if (password == "") {
            val ts = Toast.makeText(this@LoginActivity, "please write password.", Toast.LENGTH_SHORT)
            ts.setGravity(Gravity.CENTER, 0, 0)
            ts.show()
        } else {
            //ログイン処理
            mAuth.signInWithEmailAndPassword(email, password)
                .addOnCompleteListener { task ->
                    if (task.isSuccessful) {
                        val intent = Intent(this@LoginActivity, DashboardActivity::class.java)
                        startActivity(intent)
                        finish()
                    } else {
                        val ts = Toast.makeText(
                            this@LoginActivity,
                            "Error Message: " + task.exception!!.message.toString(),
                            Toast.LENGTH_SHORT
                        )
                        ts.setGravity(Gravity.CENTER, 0, 0)
                        ts.show()
                    }
                }
        }
    }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Jetpack Navigationで最初のフラグメントでも戻るための左矢印を表示する

メイン画面から設定画面が呼ばれるアプリがあります。すべての画面をJetpack Navigationで作っていたのですが、理由あってJetpack Navigationの適用範囲を設定画面のみにしました。
そうなるとJetpack Navigation上でトップとなる画面でも、前の画面に戻るための左矢印を表示したくなります。

device-2020-07-24-060057.gif

現状のツールバー左矢印表示のためのコードはこのようになっています。
Jetpack Navigationのバージョンは2.3.0です。

SettingActivity.kt
class SettingActivity : AppCompatActivity() {

    private lateinit var appBarConfiguration: AppBarConfiguration

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_setting)
        setSupportActionBar(toolbar)

        val host = supportFragmentManager
                .findFragmentById(R.id.nav_host_fragment) as NavHostFragment
        val navController = host.navController
        appBarConfiguration = AppBarConfiguration.Builder(navController.graph).build()
        setupActionBarWithNavController(navController, appBarConfiguration)
    }

    override fun onSupportNavigateUp(): Boolean {
        return findNavController(R.id.nav_host_fragment).navigateUp(appBarConfiguration)
    }
}

検索してみたところ、Stackoverflowに答えがありました。
https://stackoverflow.com/questions/55951871/display-back-button-on-toolbar-on-first-screen-of-navigation-graph

AppBarConfigurationのインスタンス作成時の設定を変更するだけです。

SettingActivity.kt
appBarConfiguration = AppBarConfiguration.Builder(
        /* ここを空欄にすることで、左矢印を表示するトップレベルなフラグメントを
           開始フラグメント(ナビゲーショングラフxmlファイルのstartDestination属性)にしない */)
        .setFallbackOnNavigateUpListener {
            // Jetpack Navigationで左矢印を処理できないときの処理
            // このActiivtyを閉じる
            finish()
            // 左矢印が処理できたことを伝える
            true
        }.build()
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Android ライブ壁紙アプリ作りました

Pile Up Pict Wallpaper

Screenshot_2020-07-23 ダッシュボード - Pile Up Pict Wallpaper - Google Play Console.png

写真がひらひら舞い落ちて一面に積み重なるような雰囲気のスライドショー系ライブ壁紙です。

表示できる画像はスマホ内に保存されている画像のみです。(ネットワークを利用した機能はありません。)

表示される位置や角度、順番はある程度カスタマイズできますが、基本的にランダムです。表示する画像は最初にプレイリストを作成していただく際に選択追加していただきます。

デモ

(gifでは1枚1枚の表示間隔がとても短いですが、本当はもっと長いです。また、設定で間隔は変えられます。)

demo (1).gif

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