带有多个改型的android stock app 2匕首柄

Part ONE < ===

第一部分 <===

The price of the Stock Exchange is depending on News. On the front page, you shall display the news for the app user. At this time, I choose RapidAPI, which has some free stock APIs. You can choose one as your additional stock news activity. I will divide one activity into three activities:

证券交易所的价格取决于新闻。 在首页上,您应为应用程序用户显示新闻。 目前,我选择RapidAPI ,它具有一些免费的库存API。 您可以选择一个作为其他股票新闻活动。 我将一个活动分为三个活动:

  • MainActivity => navigator

    MainActivity =>导航器

  • TiingoActivity => Tiingo server

    TiingoActivity => Tiingo服务器

  • BloombergActivity => Bloomberg server

    BloombergActivity =>彭博服务器

-=== MenU ===- (— ===MenU=== —)

💲1. 注册一个免费帐户
💣2。 卷曲测试
🍨3。 RestConfig和Story数据类
⌘4。 网络:拆分API服务
5英镑 拆分ApiModule:两个Api服务
🐙6。 UI:MainActivity,TiingoActivity和BloombergActivity
7英镑 测试连接和活动 (💲 1. Register A Free Account
💣2. Curl Test
🍨3. RestConfig and Story Data Class
⌘4. Network: Split the API service
🔪5. Split ApiModule: Two Api Services
🐙6. UI: MainActivity, TiingoActivity, and BloombergActivity
📳7. Test Connection and Activities)

💲1。 注册免费帐户 (💲1. Register A Free Account)

=> Menu

=> 菜单

I choose Bloomberg as my stock news API. It’s free if the requests are less than 500/month or 16/day. That is a great tool for the developer who wants to develop tools on the Stock Exchange.

我选择Bloomberg作为我的股票新闻API。 如果请求数少于500 /月或16 /天,则免费。 对于想要在联交所开发工具的开发人员来说,这是一个很好的工具。

RapidAPI also offers us some sample programming code. I am working on Android. So Java is the best fit for me.

RapidAPI还为我们提供了一些示例编程代码。 我正在使用Android。 因此Java最适合我。

Image for post

After registration, we can start to work on the App.

注册后,我们可以开始在该应用程序上工作。

💣2。 卷曲测试 (💣2. Curl Test)

=> Menu

=> 菜单

Image for post

Open a terminal, such as CMD; let’s use the code from Java.

打开一个终端,例如CMD; 让我们使用Java中的代码。

curl -v "https://bloomberg-market-and-financial-news.p.rapidapi.com/stories/list?template=CURRENCY&id=usdjpy" ^
-H "x-rapidapi-host: bloomberg-market-and-financial-news.p.rapidapi.com" ^
-H "x-rapidapi-key:YOUR API KEY"

It returns a JSON response.

它返回一个JSON响应。

>curl -v ...
*...
<
{...JSON CONTENT...}* Connection #0 to host bloomberg-market-and-financial-news.p.rapidapi.com left intact>

This is a good one.

这个不错。

🍨3。 RestConfig和Story数据类 (🍨3. RestConfig and Story Data Class)

=> Menu

=> 菜单

Add Key and Server

添加密钥和服务器

The “secret” will move into the “network” package.

秘密 ”将移至“ 网络 ”包中。

RestConfig.kt: Two sets of API server data: Tiingo and Bloomberg.

RestConfig.kt :两组API服务器数据: TiingoBloomberg

class RestConfig {
companion object {
const val DEBUG = true
// Tiingo
const val Tiingo_TEST_END = "/api/test"
const val Tiingo_TOKEN = "Your Token"
const val Tiingo_SERVER = "https://api.tiingo.com"
const val Tiingo_Header1 = "Content-Type: application/json"
const val Tiingo_Header2 = "Authorization: Token $Tiingo_TOKEN"// Bloomberg
const val Bloomberg_STORY_CURRENCY = "/stories/list?template=CURRENCY&id=usdjpy"
const val Bloomberg_SERVER = "https://bloomberg-market-and-financial-news.p.rapidapi.com"
const val Bloomberg_KEY = "Your Key"
const val Bloomberg_Header1 = "x-rapidapi-host: bloomberg-market-and-financial-news.p.rapidapi.com"
const val Bloomberg_Header2 = "x-rapidapi-key: $Bloomberg_KEY"

}
}

Split Data Class

分割资料类别

At the “data” package, I create a “tiingo” package to store Message class, and I create a “bloomberg” package to store the new data.

在“数据”包中,我创建一个“ tiingo ”包来存储Message类,并创建一个“ Bloomberg ”包来存储新数据。

Image for post

JSON:

JSON:

{"stories":[...}

At data/bloomberg, the response message is “stories”. So I copy the JSON code into JK plugin to generate the Story class.

data / bloomberg,响应消息为“故事”。 因此,我将JSON代码复制到JK插件中以生成Story类。

Image for post

Story.kt,

Story.kt

data class Story(
val stories: List<StoryX>,
val title: String
)

StoryX.kt,

StoryX.kt

data class StoryX(
val card: String,
val internalID: String,
val longURL: String,
val primarySite: String,
val published: Int,
val resourceType: String,
val shortURL: String,
val thumbnailImage: String,
val title: String
)

We will insert StoryX data on a RecyclerView.

我们将StoryX数据插入RecyclerView

⌘4。 网络:拆分API服务 (⌘4. Network: Split the API service)

=> Menu

=> 菜单

I have two API services in my app. So I split them into two packages.

我的应用程序中有两个API服务。 所以我将它们分成两个包。

Image for post

At network/tiingo/:

网络/ tiingo /:

TiingoApiService.kt,

TiingoApiService.kt,

interface TiingoApiService {
// Tiingo Test Message
@Headers(
RestConfig.Tiingo_Header1,
RestConfig.Tiingo_Header2
)
@GET(RestConfig.Tiingo_TEST_END)
suspend fun getTestMessage(): Message
}

TiingoApiServiceHelper.kt,

TiingoApiServiceHelper.kt

interface TiingoApiServiceHelper {
suspend fun getTestMsg(): Message
}

TiingoApiServiceHelperImpl.kt

TiingoApiServiceHelperImpl.kt

@Singleton
class TiingoApiServiceHelperImpl @Inject constructor(
private val tiingoApiService: TiingoApiService
) : TiingoApiServiceHelper {
override suspend fun getTestMsg():
Message = tiingoApiService.getTestMessage()
}

At network/bloomberg:

网络/彭博社

BloombergApiService.kt,

BloombergApiService.kt

interface BloombergApiService {
// Bloomberg Stories: Currency
@Headers(
RestConfig.Bloomberg_Header1,
RestConfig.Bloomberg_Header2
)
@GET(RestConfig.Bloomberg_STORY_CURRENCY)
suspend fun getStory(): Story
}

BloombergApiServiceHelper.kt,

BloombergApiServiceHelper.kt

interface BloombergApiServiceHelper {
// Bloomberg Stories: Currency
suspend fun getBloombergStory(): Story
}

BloombergApiServiceHelperImpl.kt,

BloombergApiServiceHelperImpl.kt

@Singleton
class BloombergApiServiceHelperImpl @Inject constructor(
private val bloombergApiService: BloombergApiService
) : BloombergApiServiceHelper {
// Bloomberg Stories: Currency
override suspend fun getBloombergStory():
Story = bloombergApiService.getStory()
}

5英镑 拆分ApiModule:两个Api服务 (🔪5. Split ApiModule: Two Api Services)

=> Menu

=> 菜单

Image for post

I split AppModule into two modules: BloombergNetworkModule and TiingoNetworkModule.

我将AppModule分为两个模块: BloombergNetworkModuleTiingoNetworkModul e。

Qualifier: Tag Your Provides

限定词:标记您的提供

Also, I create two qualifiers to separate the API services. At dagger/qualifier:

另外,我创建了两个限定符来分隔API服务。 在匕首/限定符处

TypeEnum.kt, it contains all of the types of API service.

TypeEnum.kt ,它包含所有API服务类型。

enum class TypeEnum {URL, SERVER, GSON, OKHTTP, RETROFIT, APISERVICE, APIHELPER}

BloombergNetwork.kt,

彭博网络

@Qualifier
@Documented
@Retention(AnnotationRetention.RUNTIME)
annotation class BloombergNetwork(val value: TypeEnum)

TiingoNetwork.kt,

TiingoNetwork.kt

@Qualifier
@Documented
@Retention(AnnotationRetention.RUNTIME)
annotation class TiingoNetwork(val value: TypeEnum)

👩🏻ApiModule: 👶🏻BloombergNetworkModule 👶🏻TiingoNetworkModule

piApiModule:👶🏻BloombergNetworkModule👶🏻TiingoNetworkModule

BloombergNetworkModule.kt,

彭博网络模块.kt

@Module
@InstallIn(ApplicationComponent::class)
class BloombergNetworkModule {
@Provides @BloombergNetwork(URL)
fun provideBloombergUrl() = RestConfig.Bloomberg_SERVER @Provides @BloombergNetwork(GSON)
fun provideGson(): Gson = GsonBuilder().setLenient().create() @Provides @BloombergNetwork(OKHTTP)
fun provideOkHttpClient() =
if (RestConfig.DEBUG) { // debug ON
val logger = HttpLoggingInterceptor()
logger.level = HttpLoggingInterceptor.Level.BODYOkHttpClient.Builder()
.addInterceptor(logger)
.readTimeout(100, TimeUnit.SECONDS)
.connectTimeout(100, TimeUnit.SECONDS)
.build()
} else // debug OFF
OkHttpClient.Builder()
.readTimeout(100, TimeUnit.SECONDS)
.connectTimeout(100, TimeUnit.SECONDS)
.build() @Provides @BloombergNetwork(RETROFIT)
fun provideRetrofit(@BloombergNetwork(OKHTTP) okHttpClient: OkHttpClient,@BloombergNetwork(URL) BaseURL: String):
Retrofit = Retrofit.Builder()
.baseUrl(BaseURL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build() @Provides @BloombergNetwork(APISERVICE)
fun provideBloombergApiService(@BloombergNetwork(RETROFIT) retrofit: Retrofit):
BloombergApiService = retrofit.create(BloombergApiService::class.java) @Provides @BloombergNetwork(APIHELPER)
fun provideBloomberApiServiceHelper(apiHelper: BloombergApiServiceHelperImpl):
BloombergApiServiceHelper = apiHelper}

Please check the Bold words, it’s easy to understand qualifier. Let’s tag BloombergApiServiceHelperImpl.kt, at network/bloombBloomberg, to create the binding.

请检查粗体字,这很容易理解限定词。 让我们在network / bloombBloomberg标记BloombergApiServiceHelperImpl.kt来创建绑定。

class BloombergApiServiceHelperImpl @Inject constructor(@BloombergNetwork(APISERVICE)
private val bloombergApiService: BloombergApiService
) : BloombergApiServiceHelper {...

Use Hilt anchors to check the binding until you hit the URL tag. Next,

使用Hilt锚点检查绑定,直到您单击URL标记。 下一个,

TiingoNetworkModule.kt,

TiingoNetworkModule.kt

@Module
@InstallIn(ApplicationComponent::class)
class TiingoNetworkModule {
@Provides @TiingoNetwork(URL)
fun provideBaseUrl() = RestConfig.Tiingo_SERVER @Provides @TiingoNetwork(GSON)
fun provideGson(): Gson = GsonBuilder().setLenient().create() @Provides @TiingoNetwork(OKHTTP)
fun provideOkHttpClient() =
if (RestConfig.DEBUG) { // debug ON
val logger = HttpLoggingInterceptor()
logger.level = HttpLoggingInterceptor.Level.BODYOkHttpClient.Builder()
.addInterceptor(logger)
.readTimeout(100, TimeUnit.SECONDS)
.connectTimeout(100, TimeUnit.SECONDS)
.build()
} else // debug OFF
OkHttpClient.Builder()
.readTimeout(100, TimeUnit.SECONDS)
.connectTimeout(100, TimeUnit.SECONDS)
.build() @Provides @TiingoNetwork(RETROFIT)
fun provideRetrofit(@TiingoNetwork(OKHTTP) okHttpClient: OkHttpClient, @TiingoNetwork(URL) BaseURL: String
): Retrofit = Retrofit.Builder()
.baseUrl(BaseURL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build() @Provides @TiingoNetwork(APISERVICE)
fun provideApiService(@TiingoNetwork(RETROFIT) retrofit: Retrofit
): TiingoApiService = retrofit.create(TiingoApiService::class.java) @Provides @TiingoNetwork(APIHELPER)
fun provideApiServiceHelper(apiHelper: TiingoApiServiceHelperImpl):
TiingoApiServiceHelper = apiHelper}

Let’s fix the TiingoApiServiceHelperImpl.kt, at network/tiingo.

让我们来解决的TiingoApiServiceHelperImpl.kt,网络/ tiingo。

class TiingoApiServiceHelperImpl @Inject constructor(@TiingoNetwork(APISERVICE) private val tiingoApiService...

🐙6。 UI:MainActivity,TiingoActivity和BloombergActivity (🐙6. UI: MainActivity, TiingoActivity, and BloombergActivity)

=> Menu

=> 菜单

The MainActivity has no longer to display the Tiingo’s content. Now, it acts as a navigator to show sites that users can visit.

MainActivity不再显示Tiingo的内容。 现在,它可以充当导航器来显示用户可以访问的站点。

Image for post

AndroidManifest.xml,

AndroidManifest.xml

<application
...>
<activity android:name=".view.bloomberg.BloombergNewsActivity"></activity>
<activity android:name=".view.tiingo.TiingoActivity"></activity>
<activity android:name=".view.main.MainActivity">

It’s MVVM, so I place all the UI into the “view” package.

它是MVVM,因此我将所有UI都放在“ view ”包中。

MainActivity

主要活动

The activity_main.xml,

activity_main.xml

Image for post

That’s it: two buttons.

就是这样:两个按钮。

MainActivity.kt,

MainActivity.kt

private const val REQUEST_CODE_PERMISSIONS = 1111
private val REQUIRED_PERMISSIONS = arrayOf(...)
@AndroidEntryPoint // Hilt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)setupButton()
}
fun setupButton() {
lgd("Setup buttons")
tiingo_bt.setOnClickListener {val mIntent = Intent(this,
TiingoActivity::class.java)
startActivity(mIntent)}bloomberg_bt.setOnClickListener {val mIntent = Intent(this,
BloombergNewsActivity::class.java)
startActivity(mIntent)}}override fun onRequestPermissionsResult(...) {...}private fun allPermissionsGranted()...companion object {
private val TAG = "MYLOG MainActivity"
fun lgd(s: String) = Log.d(TAG, s)
// len: 0=>short; 1=>long
fun msg(context: Context, s: String, len: Int) =
if (len == 0)
Toast.makeText(context, s,
Toast.LENGTH_SHORT).show()
else
Toast.makeText(context, s,
Toast.LENGTH_LONG).show()
const val INTERNET = "INTERNET"
}
}

TiingoActivity

Tiingo活动

The activity_tiingo.xml,

activity_tiingo.xml,

Image for post

TiingoActivity.kt, it is as same as old MainActivity. Please rename the ViewModel to TiingoViewModel.

TiingoActivity.kt ,它与旧的MainActivity相同。 请将ViewModel重命名为TiingoViewModel

@AndroidEntryPoint  // Hilt
class TiingoActivity : AppCompatActivity() {
private val tiingoViewModel : TiingoViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_tiingo)setupObserver()
}
fun setupObserver() {
lgd("setup observer")
tiingoViewModel.message.observe(this, Observer {...})
}
companion object {
private val TAG = "MYLOG TiingoAct"
fun lgd(s: String) = Log.d(TAG, s)
// len: 0=>short; 1=>long
fun msg(context: Context, s: String, len: Int) =
if (len == 0)
Toast.makeText(context, s,
Toast.LENGTH_SHORT).show()
else
Toast.makeText(context, s,
Toast.LENGTH_LONG).show()
const val INTERNET = "INTERNET"
}
}

TiingoViewModel.kt, it is as same as old MainViewModel. Please rename the Repository to TiingoRepository.

TiingoViewModel.kt ,它与旧的MainViewModel相同。 请将存储库重命名为TiingoRepository。

class TiingoViewModel @ViewModelInject constructor(
private val tiingoRepository: TiingoRepository,
networkHelper: NetworkHelper
) : ViewModel() {...

TiingoRepository.kt, at the “room” package.

TiingoRepository.kt ,位于“ room ”包中。

@Singleton
class TiingoRepository @Inject constructor(@TiingoNetwork(APIHELPER)
private val tiingoTiingoApiHelper: TiingoApiServiceHelper
) {
suspend fun getTestMsg():
Message = tiingoTiingoApiHelper.getTestMsg()
}

Please check the Hilt link. You must be able to jump back to TiingoNetworkModule by clicking 🔨,

请检查“链接”链接。 你必须能够通过单击跳回TiingoNetworkModule🔨,

Image for post

BloombergActivity

彭博活动

The activiy_bloomberg_news.html,

activiy_bloomberg_news.html

Image for post

BloombergNewsActivity.kt,

彭博新闻活动

@AndroidEntryPoint  // Hilt
class BloombergNewsActivity : AppCompatActivity() {
private val newsViewModel : BloombergNewsViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_bloomberg_news)setupObserver()
}
fun setupObserver() {
newsViewModel.story.observe(this, Observer {when (it.status) {
Status.SUCCESS -> {
news_tv.text = it.data!!.stories.toString()
news_pb.visibility = View.GONE}
Status.LOADING -> {
news_pb.visibility = View.VISIBLE}
Status.ERROR -> {
news_pb.visibility = View.GONEval tempStr = it.message
// internet error
val foundIdx = tempStr?.indexOf(
INTERNET, 0)!!
if (foundIdx > 0) {
val spStr = SpannableString(tempStr)
val color = Color.REDspStr.setSpan(
ForegroundColorSpan(color),
foundIdx,
foundIdx+8,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
news_tv.text = spStr
} else { // other error
news_tv.text = tempStr
}
msg(this, tempStr, 1)
}
}})
} companion object {
private val TAG = "MYLOG BloombergAct"
fun lgd(s: String) = Log.d(TAG, s)
fun lge(s: String) = Log.e(TAG, s)
fun lgi(s: String) = Log.i(TAG, s)
// len: 0=>short; 1=>long
fun msg(context: Context, s: String, len: Int) =
if (len == 0)
Toast.makeText(context, s,
Toast.LENGTH_SHORT).show()
else
Toast.makeText(context, s,
Toast.LENGTH_LONG).show()
const val INTERNET = "INTERNET"
}
}

BloombergNewsViewModel.kt,

彭博新闻视图模型.kt

class BloombergNewsViewModel @ViewModelInject constructor(
private val bloombergRepository: BloombergRepository,
networkHelper: NetworkHelper
) : ViewModel() {
// cached
private val _story = MutableLiveData<Resource<Story>>()
// public
val story: LiveData<Resource<Story>> = _story
init {
_story.postValue(Resource.loading(null))
if (networkHelper.isNetworkConnected()) {
fetchStory()
} else {
_story.postValue(
Resource.error(
data = null,
message = internetErr))
}
}
fun fetchStory() {viewModelScope.launch {lgd("fetching story...")
try {
_story.value = Resource.success(
data = bloombergRepository.getCurrencyStory())
} catch (exception: Exception) {
_story.value = Resource.error(
data = null,
message = exception.message ?: otherErr
)
}}}
companion object {
private val TAG = "MYLOG BB-NewsVM"
const val otherErr = "Error Occurred!"
const val internetErr = "Internet Connection Error"
fun lgd(s: String) = Log.d(TAG, s)
}
}

BloombergRepository.kt, at the “room” package.

BloombergRepository.kt ,位于“ 房间 ”包中。

@Singleton
class BloombergRepository @Inject constructor(@BloombergNetwork(APIHELPER)
private val bloombergApiHelper: BloombergApiServiceHelper
) {
suspend fun getCurrencyStory():
Story = bloombergApiHelper.getBloombergStory()
}

7英镑 测试连接和活动 (📳7. Test Connection and Activities)

=> Menu

=> 菜单

Run,

跑,

Image for post

Tiingo Activity:

Tiingo活动:

Image for post

Bloomberg Activity:

彭博活动:

Image for post

Both activities have downloaded JSON data. That proves both network connections are working properly.

这两个活动都下载了JSON数据。 证明两个网络连接均正常工作。

😏享受! (😏Enjoy!)

===> Part THREE

===> 第三部分

翻译自: https://medium.com/@homanhuang/android-stock-app-2-dagger-hilt-with-multiple-retrofits-cc13472287dd

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值