Android
 Computer >> コンピューター >  >> システム >> Android

Dagger 2 を使用してアプリに依存性注入を実装する方法

Kriptofolio アプリ シリーズ - パート 4

依存性注入により、コードが大幅に改善されます。これにより、コードがよりモジュール化され、柔軟になり、テストしやすくなります。実際、その名前は背後にある考え方よりも複雑に聞こえます。

シリーズのこのパートでは、依存性注入について学びます。その後、「Kriptofolio」(以前の「My Crypto Coins」)アプリに実装します。 Dagger 2 を使用します。Dagger 2 は、Android 向けの最も人気のあるオープンソースの依存性注入フレームワークです。これは、学習曲線が十分に難しいとはいえ、最新のアプリを作成するための貴重なスキルです。

シリーズ コンテンツ

  • はじめに:2018 ~ 2019 年に最新の Android アプリを構築するためのロードマップ
  • パート 1:SOLID 原則の紹介
  • パート 2:Android アプリの作成方法:モックアップ、UI、XML レイアウトの作成
  • パート 3:アーキテクチャのすべて:さまざまなアーキテクチャ パターンとアプリでの使用方法を探る
  • パート 4:Dagger 2 を使用してアプリに依存性注入を実装する方法 (ここにいます)
  • パート 5:Retrofit、OkHttp、Gson、Glide、およびコルーチンを使用して RESTful Web サービスを処理する

依存性注入とは?

依存性注入を説明するには、まずプログラミングにおける依存性とは何かを理解する必要があります。依存関係とは、オブジェクトの 1 つが別のオブジェクトの具体的な実装に依存する場合です。別のオブジェクト内でオブジェクトをインスタンス化するときはいつでも、コード内の依存関係を識別できます。実際の例を見てみましょう。

class MyAppClass() {

    private val library: MyLibrary = MyLibrary(true)
    ...
}

class MyLibrary(private val useSpecialFeature: Boolean) {
    
    ...
}

この例からわかるように、クラス MyAppClass ライブラリクラス MyLibrary の具体的な構成と実装に直接依存します .ある日、代わりにサードパーティのライブラリを使用したい場合はどうしますか?まったく同じライブラリ構成を使用したい別のクラスが必要な場合はどうしますか?コードを検索する必要があるたびに、正確な場所を見つけて変更します。これはほんの一例です。

アプリケーションのコンポーネント間のこの緊密な結合により、プロジェクトが大きくなるにつれて開発作業が難しくなるという考えです。問題を回避するために、説明した結合を緩めるために依存性注入を使用しましょう。

class MyAppClass(private val library: MyLibrary) {
    
    ...
}

class MyLibrary(private val useSpecialFeature: Boolean) {
    
    ...
}

以上です。これは非常に原始的な依存性注入の例です。新しい MyLibrary を作成して構成する代わりに クラス MyAppClass 内のクラス オブジェクト 、コンストラクターに渡すか注入するだけです。だから MyAppClass MyLibrary に対して完全に無責任かもしれません .

ダガー 2 とは?

Dagger は、Java と Android の両方に対応した、完全に静的でコンパイル時のオープンソースの依存性注入フレームワークです。この記事では、Google が管理している 2 番目のバージョンについて説明します。 Square は以前のバージョンを作成しました。

Dagger 2 は、これまでに構築された最も効率的な依存性注入フレームワークの 1 つと見なされています。実際、Dagger 1、Dagger 2、および Dagger 2.10 を比較すると、それぞれの実装が異なることがわかります。著者によって大幅な変更が行われたため、毎回再学習する必要があります。この記事を書いているとき、私は Dagger 2.16 バージョンを使用しており、それにのみ焦点を当てます。

依存性注入について理解しているように、クラスは依存性を作成したり、依存関係を持ったりするべきではありません。代わりに、外部からすべてを取得する必要があります。したがって、Dagger 2 を使用する場合、このフレームワークは必要なすべての依存関係を提供します。

これは、定型コードを大量に生成することで実現します。生成されたコードは完全に追跡可能であり、ユーザーが手動で記述したコードを模倣します。 Dagger 2 は Java で書かれており、その注釈プロセッサによって生成されるコードも Java コードになります。

ただし、問題や変更なしで Kotlin で動作します。 Kotlin は Java と完全に相互運用可能であることを忘れないでください。同様のフレームワークと比較すると、Dagger 2 はそれほど動的ではありません。リフレクションでは、実行時ではなくコンパイル時に機能します。リフレクションの使用はまったくありません。つまり、このフレームワークのセットアップと学習が難しくなるということです。これにより、コンパイル時の安全性が向上し、パフォーマンスが向上します。

ツールを使用しない手動依存性注入

前の部分の My Crypto Coins アプリのソース コードに、依存性注入ツールを使用せずにオブジェクトを注入するためのコードがあることに気付いたかもしれません。それは問題なく動作し、このような小さなアプリにはこのソリューションで十分です。ユーティリティ パッケージを見てみましょう:

/**
 * Static methods used to inject classes needed for various Activities and Fragments.
 */
object InjectorUtils {

    private fun getCryptocurrencyRepository(context: Context): CryptocurrencyRepository {
        return CryptocurrencyRepository.getInstance(
                AppDatabase.getInstance(context).cryptocurrencyDao())
    }

    fun provideMainViewModelFactory(
            application: Application
    ): MainViewModelFactory {
        val repository = getCryptocurrencyRepository(application)
        return MainViewModelFactory(application, repository)
    }

    fun provideAddSearchViewModelFactory(
            context: Context
    ): AddSearchViewModelFactory {
        val repository = getCryptocurrencyRepository(context)
        return AddSearchViewModelFactory(repository)
    }
}

ご覧のとおり、このクラスがすべての作業を行います。アクティビティまたはフラグメントを必要とする ViewModel ファクトリを作成します。

/**
 * Factory for creating a [MainViewModel] with a constructor that takes a
 * [CryptocurrencyRepository].
 */
class MainViewModelFactory(private val application: Application, private val repository: CryptocurrencyRepository) : ViewModelProvider.NewInstanceFactory() {

    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        return MainViewModel(application, repository) as T
    }

}

次に InjectorUtils を使用します 特定の ViewModel ファクトリを取得する必要があるこのようなクラス:

/**
 * A placeholder fragment containing a simple view.
 */
class MainListFragment : Fragment() {

    ...

    private lateinit var viewModel: MainViewModel

    ...

    override fun onActivityCreated(savedInstanceState: Bundle?) {

        super.onActivityCreated(savedInstanceState)

        setupList()
        ...
    }

    ...

    private fun subscribeUi(activity: FragmentActivity) {

        // This is the old way how we were injecting code before using Dagger.
        val factory = InjectorUtils.provideMainViewModelFactory(activity.application)

        // Obtain ViewModel from ViewModelProviders, using parent activity as LifecycleOwner.
        viewModel = ViewModelProviders.of(activity, factory).get(MainViewModel::class.java)

        ...
    }

}

ご覧のとおり MainListFragment クラスは CryptocurrencyRepository についてさえ知りません または AppDatabase . InjectorUtils クラスから正常に構築されたファクトリを取得します。実際、これは簡単な方法の 1 つです。それを取り除き、高度な依存性注入のために Dagger 2 ツールをセットアップする方法を学びます。このアプリの機能とコードが拡張されれば、手動のソリューションではなく、専門的な依存性注入フレームワークを使用するメリットがすぐに見られるようになることは間違いありません。

InjectorUtils を削除しましょう 今すぐクラスに参加して、My Crypto Coins アプリのソース コードで Dagger 2 をセットアップする方法を学びましょう。

Kotlin を使用した MVVM の依存性注入

ビューモデル、アクティビティ、フラグメントを使用して Dagger 2 をセットアップする方法

次に、My Crypto Coins アプリ プロジェクトで Dagger 2 を段階的にセットアップします。

まず、Kotlin 独自の注釈処理ツール (kapt) を有効にする必要があります。次に、特別な Dagger 2 の依存関係を追加します。

これを行うには、gradle ファイルに次の行を追加します:

apply plugin: 'kotlin-kapt' // For annotation processing

...

implementation "com.google.dagger:dagger:$versions.dagger"
implementation "com.google.dagger:dagger-android:$versions.dagger"
implementation "com.google.dagger:dagger-android-support:$versions.dagger"
kapt "com.google.dagger:dagger-compiler:$versions.dagger"
kapt "com.google.dagger:dagger-android-processor:$versions.dagger"
モジュール:アプリ

Kapt プラグインは、Java と Kotlin 間の相互運用性に必要なスタブ クラスをコンパイラが生成できるようにします。便宜上、Dagger 2 の具体的なバージョンを別の gradle ファイルで定義します。これは、すべての依存関係で行うためです。

def versions = [:]

versions.dagger = "2.16"

ext.versions = versions

利用可能な最新バージョンを見つけるには、Github の Dagger 2 の公式リポジトリでリリースを確認してください。

では、アプリケーション App を作成してください クラス。

このクラスが既に設定されている場合は、これをスキップしてください。完了後、しばらくそのままにしておきますが、後で戻ってきます。

class App : Application() {

    override fun onCreate() {
        super.onCreate()
    }

}

My Crypto Coins アプリの場合、アプリケーション クラスは既に作成済みです。

次に、マニフェスト ファイルを更新して App を有効にします クラス。

以前に行ったことがある場合は、これをスキップしてください。

<manifest xmlns:android="https://schemas.android.com/apk/res/android"
    package="com.baruckis.mycryptocoins">

    <application
        android:name=".App"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        ...

My Crypto Coins アプリの場合、App も既に設定されています 前にマニフェストのクラス。

dependencyinjection という名前の新しいパッケージを作成しましょう .

ここでは、Dagger の実装に関連するすべてのファイルを保持します。

AppModule を作成 アプリケーション全体に依存関係を提供するクラス モジュール。

/**
 * AppModule will provide app-wide dependencies for a part of the application.
 * It should initialize objects used across our application, such as Room database, Retrofit, Shared Preference, etc.
 */
@Module(includes = [ViewModelsModule::class])
class AppModule() {

    @Singleton // Annotation informs Dagger compiler that the instance should be created only once in the entire lifecycle of the application.
    @Provides // Annotation informs Dagger compiler that this method is the constructor for the Context return type.
    fun provideContext(app: App): Context = app // Using provide as a prefix is a common convention but not a requirement.

    @Singleton
    @Provides
    fun provideCryptocurrencyRepository(context: Context): CryptocurrencyRepository {
        return CryptocurrencyRepository.getInstance(AppDatabase.getInstance(context).cryptocurrencyDao())
    }
}

ご覧のとおり、Dagger モジュールを作成するには、特別な @Module で注釈を付ける必要があります。 注釈。プロジェクトには通常、複数の Dagger モジュールがあります。そのうちの 1 つがアプリ全体の依存関係を提供するのが一般的です。この AppModule Room データベース、Retrofit、Shared Preference など、アプリケーション全体で使用されるオブジェクトを初期化するために使用されます。

例として、アプリのどこからでもアクセスする必要がある場合に備えて、AppModule が Context オブジェクトを提供する非常に一般的なシナリオについて説明できます。コードを分析して、その方法を確認しましょう。

特別な Dagger アノテーション @Provides を使用する必要があります .メソッドが特定の種類の依存関係 (この場合は Context オブジェクト) を提供することを Dagger に伝えます。したがって、アプリ内のどこかで Context の注入をリクエストすると、AppModule は Dagger がそれを見つける場所になります。また、Dagger は戻り値の型だけを気にするので、メソッドの名前は問題ではありません。メソッドに provide プレフィックスを付けて名前を付けるのが一般的な方法ですが、任意の名前にすることができます。

@Singleton 同じメソッドに適用されているアノテーションは、Dagger アノテーションの一部ではありません。 javax パッケージに含まれています。この注釈は、その依存関係のインスタンスが 1 つだけであるべきであることを Dagger に伝えます。

オブジェクトの別のインスタンスが既に利用可能かどうかを確認する定型コードを記述する必要はありません。コードを生成するとき、この注釈により、Dagger がすべてのロジックを処理します。 AppModule には別のモジュール ViewModelsModule が含まれていることに注意してください。今すぐ作成しましょう。

ViewModelsModule を作成する クラスモジュール。このモジュールは、アプリケーション全体に ViewModel を提供します。

/**
 * Will be responsible for providing ViewModels.
 */
@Module
abstract class ViewModelsModule {

    // We'd like to take this implementation of the ViewModel class and make it available in an injectable map with MainViewModel::class as a key to that map.
    @Binds
    @IntoMap
    @ViewModelKey(MainViewModel::class) // We use a restriction on multibound map defined with @ViewModelKey annotation, and if don't need any, we should use @ClassKey annotation provided by Dagger.
    abstract fun bindMainViewModel(mainViewModel: MainViewModel): ViewModel

    @Binds
    @IntoMap
    @ViewModelKey(AddSearchViewModel::class)
    abstract fun bindAddSearchViewModel(addSearchViewModel: AddSearchViewModel): ViewModel

    @Binds
    abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
}

このモジュールは、Dagger 2 機能マップ マルチ バインディングを使用します。それを使用して、選択したオブジェクトをマップに提供し、アプリのどこにでも挿入できるようにします。 Dagger アノテーション @Binds の組み合わせを使用する 、 @IntoMap カスタム アノテーション @ViewModelKey (これから作成するもの)、キー MainViewModel::class でマップ内にエントリを作成します 値 MainViewModel 実例。いくつかの一般的な ViewModelFactory の助けを借りて、特定のファクトリをバインドします クラス。このクラスを作成する必要があります。

カスタム アノテーション クラス ViewModelKey を作成する .

/**
 * An annotation class which tells dagger that it can be used to determine keys in multi bound maps.
 */
@MustBeDocumented
@Target(
        AnnotationTarget.FUNCTION,
        AnnotationTarget.PROPERTY_GETTER,
        AnnotationTarget.PROPERTY_SETTER
)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>) // We might use only those classes which inherit from ViewModel.

このクラスは、ViewModelsModule で ViewModel をバインドするために使用されます。 .特定の注釈 @ViewModelKey マップのキーを表します。私たちのキーは ViewModel を継承するクラスのみです .

ViewModelFactory を作成する クラス。

/**
 * Factory to auto-generate a Class to Provider Map.
 * We use Provider<T> to create an injectable object at a later time.
 */
@Suppress("UNCHECKED_CAST")
@Singleton
class ViewModelFactory @Inject constructor(private val viewModelsMap: Map<Class<out ViewModel>,
        @JvmSuppressWildcards Provider<ViewModel>>) : ViewModelProvider.Factory {

    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        var creator: Provider<out ViewModel>? = viewModelsMap[modelClass]
        if (creator == null) {
            for (entry in viewModelsMap.entries) {
                if (modelClass.isAssignableFrom(entry.key)) {
                    creator = entry.value
                    break
                }
            }
        }
        if (creator == null) {
            throw IllegalArgumentException("Unknown model class $modelClass")
        }

        try {
            return creator.get() as T
        } catch (e: Exception) {
            throw RuntimeException(e)
        }
    }
}

この ViewModelFactory ViewModel を動的に作成するのに役立つユーティリティ クラスです。ここでは、生成されたマップを引数として指定します。 create() メソッドは、マップから適切なインスタンスを選択できます。

ActivityBuildersModule を作成する クラス モジュール。

/**
 * All activities intended to use Dagger @Inject should be listed here.
 */
@Module
abstract class ActivityBuildersModule {

    @ContributesAndroidInjector(modules = [MainListFragmetBuildersModule::class]) // Where to apply the injection.
    abstract fun contributeMainActivity(): MainActivity

    @ContributesAndroidInjector
    abstract fun contributeAddSearchActivity(): AddSearchActivity
}

このモジュールは、すべてのアクティビティの構築を担当します。 AndroidInjector を生成します このクラスで定義されたすべてのアクティビティ。その後、AndroidInjection.inject(this) を使用してオブジェクトをアクティビティに挿入できます onCreate で アクティビティ ライフサイクルから機能します。このモジュールは、フラグメントを担当する別の別のモジュールも使用することに注意してください。次にこのモジュールを作成します。

MainListFragmetBuildersModule を作成する クラス モジュール。

/**
 * All fragments related to MainActivity intended to use Dagger @Inject should be listed here.
 */
@Module
abstract class MainListFragmetBuildersModule {

    @ContributesAndroidInjector() // Attaches fragment to Dagger graph.
    abstract fun contributeMainListFragment(): MainListFragment
}

このモジュールは、MainActivity に関連するすべてのフラグメントを構築します . AndroidInjector を生成します このクラスで定義されたすべてのフラグメントに対して。オブジェクトは AndroidSupportInjection.inject(this) を使用してフラグメントに注入できます onAttach で フラグメントのライフサイクルから機能します。

AppComponent を作成する クラス コンポーネント。

/**
 * Singleton component interface for the app. It ties all the modules together.
 * The component is used to connect objects to their dependencies.
 * Dagger will auto-generate DaggerAppComponent which is used for initialization at Application.
 */
@Singleton
@Component(
        modules = [
            // AndroidSupportInjectionModule is a class of Dagger and we don't need to create it.
            // If you want to use injection in fragment then you should use AndroidSupportInjectionModule.class else use AndroidInjectionModule.
            AndroidSupportInjectionModule::class,
            AppModule::class,
            ActivityBuildersModule::class
        ]
)
interface AppComponent {

    @Component.Builder // Used for instantiation of a component.
    interface Builder {

        @BindsInstance // Bind our application instance to our Dagger graph.
        fun application(application: App): Builder

        fun build(): AppComponent
    }

    // The application which is allowed to request the dependencies declared by the modules
    // (by means of the @Inject annotation) should be declared here with individual inject() methods.
    fun inject(app: App)
}

コンポーネントは非常に重要なクラスです。上記のすべてが連携して機能するようになります。これは、オブジェクトをその依存関係に接続することによって行われます。 Dagger はこのインターフェースを使用して、依存性注入を実行するために必要なコードを生成します。

コンポーネント クラスを作成するには、Dagger アノテーション @Component を使用する必要があります。 .モジュールのリストを入力として受け取ります。別の注釈 @Component.Builder インスタンスをコンポーネントにバインドできます。

次に、グラフ オブジェクトを生成します。

この時点で、すべてのモジュールとコンポーネントのセットアップが完了しました。 Android Studio IDE 内で Build -> Make Module を選択すると、グラフ オブジェクトを生成できます。今後のステップでこの世代が必要になります。

Injectable を作成します インターフェース。

/**
 * It is just a plain empty marker interface, which tells to automatically inject activities or fragments if they implement it.
 */
interface Injectable

これは、今後の手順でも必要になります。 Injectable インターフェイスは、自動的に注入可能にしたいアクティビティまたはフラグメントによって実装する必要があります。

AppInjector という名前の新しいヘルパー クラスを作成します .

/**
 * It is simple helper class to avoid calling inject method on each activity or fragment.
 */
object AppInjector {
    fun init(app: App) {
        // Here we initialize Dagger. DaggerAppComponent is auto-generated from AppComponent.
        DaggerAppComponent.builder().application(app).build().inject(app)

        app.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks {
            override fun onActivityPaused(activity: Activity) {

            }

            override fun onActivityResumed(activity: Activity) {

            }

            override fun onActivityStarted(activity: Activity) {

            }

            override fun onActivityDestroyed(activity: Activity) {

            }

            override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle?) {

            }

            override fun onActivityStopped(activity: Activity) {

            }

            override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
                handleActivity(activity)
            }
        })
    }

    private fun handleActivity(activity: Activity) {
        if (activity is HasSupportFragmentInjector || activity is Injectable) {
            // Calling inject() method will cause Dagger to locate the singletons in the dependency graph to try to find a matching return type.
            // If it finds one, it assigns the references to the respective fields.
            AndroidInjection.inject(activity)
        }

        if (activity is FragmentActivity) {
            activity.supportFragmentManager.registerFragmentLifecycleCallbacks(object : FragmentManager.FragmentLifecycleCallbacks() {
                override fun onFragmentCreated(fragmentManager: FragmentManager, fragment: Fragment, savedInstanceState: Bundle?) {
                    if (fragment is Injectable) {
                        AndroidSupportInjection.inject(fragment)
                    }
                }
            }, true)
        }
    }

}

これは、各アクティビティまたはフラグメントで inject メソッドを呼び出さないようにする単純なヘルパー クラスです。

次に、App をセットアップします 以前に作成したクラスです。

class App : Application(), HasActivityInjector {

    @Inject // It implements Dagger machinery of finding appropriate injector factory for a type.
    lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity>

    override fun onCreate() {
        super.onCreate()

        // Initialize in order to automatically inject activities and fragments if they implement Injectable interface.
        AppInjector.init(this)

        ...
    }


    // This is required by HasActivityInjector interface to setup Dagger for Activity.
    override fun activityInjector(): AndroidInjector<Activity> = dispatchingAndroidInjector
}

アプリケーションにはアクティビティがあるため、HasActivityInjector を実装する必要があります インターフェース。 DaggerAppComponent で Android Studio によって呼び出されたエラーが表示される場合 、前の手順で指摘したように、新しいファイルを生成していないためです。

それでは、MainActivity をセットアップします メインの ViewModel ファクトリを挿入し、フラグメント インジェクションのサポートを追加します。

// To support injecting fragments which belongs to this activity we need to implement HasSupportFragmentInjector.
// We would not need to implement it, if our activity did not contain any fragments or the fragments did not need to inject anything.
class MainActivity : AppCompatActivity(), HasSupportFragmentInjector {

    @Inject
    lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Fragment>

    @Inject
    lateinit var viewModelFactory: ViewModelProvider.Factory
    private lateinit var mainViewModel: MainViewModel


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

        // Obtain ViewModel from ViewModelProviders, using this activity as LifecycleOwner.
        mainViewModel = ViewModelProviders.of(this, viewModelFactory).get(MainViewModel::class.java)

        ...
    }

    ...

    override fun supportFragmentInjector(): AndroidInjector<Fragment> = dispatchingAndroidInjector

    ...
}

アクティビティには子フラグメントがあるため、HasSupportFragmentInjector を実装する必要があります インターフェース。フラグメントに注入する予定があるため、これも必要です。私たちのアクティビティは、それがどのように注入されるかを知る必要はありません。 AndroidInjection.inject(this) を使用します onCreate() のオーバーライド内のコード行 メソッド。

inject() を呼び出す メソッドは、Dagger 2 が依存関係グラフ内のシングルトンを見つけて、一致する戻り値の型を見つけようとします。ただし、以前に作成した AppInjector によってコードが作成されているため、ここにコードを記述する必要はありません。 アプリケーション クラス内で初期化したヘルパー クラス。

次に、MainListFragment を設定します メインの ViewModel ファクトリを注入します。

/**
 * A placeholder fragment containing a simple view.
 */
class MainListFragment : Fragment(), Injectable {

    ...

    @Inject
    lateinit var viewModelFactory: ViewModelProvider.Factory
    private lateinit var viewModel: MainViewModel

    ...

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

        ...
        subscribeUi(activity!!)
    }

    ...

    private fun subscribeUi(activity: FragmentActivity) {

        // Obtain ViewModel from ViewModelProviders, using parent activity as LifecycleOwner.
        viewModel = ViewModelProviders.of(activity, viewModelFactory).get(MainViewModel::class.java)
        
        ...

    }

}

アクティビティと同様に、フラグメントを注入可能にしたい場合は、その onAttach に コード AndroidSupportInjection.inject(this) を書くべきメソッド .しかし、これも AppInjector の仕業です。 ヘルパーなので、スキップできます。 Injectable を追加する必要があることに注意してください。 ヘルパーが機能するように以前に作成したインターフェイス。

おめでとうございます。My Crypto Coins アプリ プロジェクトに Dagger 2 を実装しました。もちろん、この記事はアプリに Dagger 2 をすぐにデプロイするためのクイック ガイドですが、詳細な説明ではありません。基本に迷ったら、このトピックの調査を続けることをお勧めします。

リポジトリ

更新された「Kriptofolio」(以前の「My Crypto Coins」)アプリのソース コードを GitHub で確認してください。

GitHub でソースを表示

あちゅ!読んでくれてありがとう!この投稿は、2018 年 10 月 7 日に個人ブログ www.baruckis.com で最初に公開したものです。


  1. iPhone で指紋認証または FaceID を使用して WhatsApp をロックする方法

    セキュリティ上の理由からアプリをロックする方法を探すとき、ユーザーは常に懸念を抱いています。 Apple はサードパーティのアプリにセキュリティを引き継がせたくない可能性があるため、App Store で利用できるアプリ ロック アプリケーションはありません。アプリのロックは主に、ソーシャル メディア アプリに必要です。チャットや共有メディアを覗き見されることは誰も望まないからです。 最後に、WhatsApp では、iOS アプリの FaceID または Touch ID でアプリをロックできるようになりました。 WhatsApp をロックし、FaceID または Touch ID でチャッ

  2. Android フォンで友人の iPhone を追跡する方法

    スマートフォンを紛失することは最悪の悪夢です。連絡先、メディア ファイル、銀行や電子メールなどの排他的アクセスを失うからです。ありがたいことに、GPS と位置情報技術により、紛失したスマートフォンを追跡できるようになりました。 Android と iPhone の両方で動作する Google Play ストアと App Store には、多数のジオトラッキング アプリがあります。ただし、作業の手順とスタイルは両方の OS で同じですが、UI にわずかな違いがあります。これらのアプリの最も優れた点は、紛失した電話の追跡に役立つだけでなく、友人の紛失したスマートフォンも追跡できることです。 以下に