Development record of developer who study hard everyday.

레이블이 안드로이드인 게시물을 표시합니다. 모든 게시물 표시
레이블이 안드로이드인 게시물을 표시합니다. 모든 게시물 표시
,

How to use safe args of navigation in android

 How to use safe args of navigation in android

android blog

1. Add dependency in build.gradle file(project level)

repositories {
google()
jcenter()
maven {url "https://maven.google.com"}
}
dependencies {

//navigation
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.8.0"

}


2. Add plugin

plugins {
id 'dagger.hilt.android.plugin'
}


3. Add argument's attribute in navigation graph which is xml file

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main_navigation_graph"
app:startDestination="@id/homeFragment">

<fragment
android:id="@+id/homeFragment"
android:name="org.techtown.volleyball.fragments.HomeFragment"
android:label="HomeFragment" >

<action
android:id="@+id/action_homeFragment_to_teamNewsFragment"
app:destination="@id/teamNewsFragment" >
            <!-- add argument tag in action tag -->
<argument
android:name="newsUrl"
app:argType="string"
android:defaultValue=""
/>
</action>


</fragment>

<fragment
android:id="@+id/teamNewsFragment"
android:name="org.techtown.volleyball.fragments.TeamNewsFragment"
android:label="TeamNewsFragment">
        <!--Add argument tag in destination fragment-->
<argument
android:name="newsUrl"
app:argType="string"
android:defaultValue=""
/>

</fragment>

</navigation>


4. Navigate with argument

val action = HomeFragmentDirections.actionHomeFragmentToTeamNewsFragment(link)
findNavController().navigate(action)


5. Receive argument in destination fragment.

class TeamNewsFragment : BaseFragment<FragmentTeamNewsBinding>(){
override val layoutResID: Int
get() = R.layout.fragment_team_news
private val args : TeamNewsFragmentArgs by navArgs()

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Log.d(TAG, "onViewCreated")


binding.webView.loadUrl(args.newsUrl)
}



}

We can receive argument with "by navArgs()" which fragment-ktx library provides.






Share:
Read More
,

Android Generic UiState

 Android Generic UiState



sealed class UiState<out T> {
data class Success<out T>(val data: T) : UiState<T>()
data class Error(val exception: Throwable) : UiState<Nothing>()
object Loading : UiState<Nothing>()
}
Share:
Read More
, ,

How to use Java and Kotlin together in android

 How to use Java and Kotlin together in android 




1. Download Kotlin plugin

download kotlin plugin


2. Add dependencies of "kotlin-gradle-plugin" in build.gradle (Project level)

dependencies {
classpath "com.android.tools.build:gradle:$agp_version"
classpath 'com.google.gms:google-services:4.3.5'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files

// Add the Crashlytics Gradle plugin
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.7.1'

//kotlin
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0'    //here
}


3. Add kotlin plugin id in build.gradle (App level)

plugins {
id 'com.android.application'
id 'kotlin-android'
}


4.  Add sourceSets for kotlin file

android {
compileSdkVersion 34
buildToolsVersion "30.0.3"

defaultConfig {
applicationId "org.techtown.volleyball"
minSdkVersion 21
targetSdkVersion 34
multiDexEnabled true
versionCode 16
versionName "1.2.11"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
buildFeatures {
viewBinding true
}

sourceSets {
main.java.srcDirs += 'src/main/kotlin'    //here
}
}


5. Add kotlin dependencies in build.gradle (App level)

dependencies {
//kotlin
implementation 'org.jetbrains.kotlin:kotlin-stdlib:1.6.0'

}


6. Sync gradle file and wrie kotlin code.








Share:
Read More
, ,

How to watch CPU usage using adb in android

 How to watch CPU usage using adb in android


1. Show CPU usage respectively in apps.

adb shell top -n 1 -s cpu


->details about top options

-m num : Maximum number of processes to display

-n num : Updates to show before exiting

-d num : Seconds to wait between updates

-s col : Column to sort by (cpu, vss, rss, thr)

-H : Show threads instead of prcesses

-h : Display this help screen


2. Show CPU usage in specific app

adb shell top -n 60 -d 1 | FINDSTR <package name>

This command shows CPU usages during 60 seconds by 1 second.





Share:
Read More
,

(Sloved) Android Studio APK install error: "local path doesn't exist"

 


I encounter the error "Android Studio APK install error: "local path doesn't exist" while building android source.

The solution is

  • Go to your project directory.In that directory search for .apk file....
  • You will find a apk with name of your project+debug-unalighned.apk.
  • Open .iml file insideyour project folder that contain project source directory.
  • Open and add write <option name="APK_PATH" value="/build/apk/(apk file name that was found earlier with apk extension)" /> inside <configration> <configration/> tags.
  • Now go and run your project...


Share:
Read More
, ,

How to separate string data by sentences

How to separate string data by sentences

안드로이드 블로그

When I am developing android app using Kotlin, I had to separate string data by one sentence.

There might be so many solutions, but I want short code using regular expression.

My solution is

1
2
3
4
5
6
7
8
9
10
fun main() {
    val text = "감오리는 사막이나 농촌지역에서 주로 발견되며, 땅속에 다닐 수 있는 능력이 있어 땅속에서 먹이를 찾기 위해 파묻기를 합니다. 감오리는 매우 활발한 동물로 매일 새로운 먹이를 찾으며 유혈자로 알려져 있습니다. 감오리는 오래 살아 가는 동물이며, 50년에서 70년까지 살 수 있습니다. 감오리의 수명은 종류에 따라 다르지만, 평균적으로 10년 정도입니다. 감오리는 인간과 친밀한 관계를 맺을 수 있는 동물로, 그들은 상호 의존적인 관계에서 존재합니다."
 
    val pattern = Regex("[^.!?]+[.!?]")        
    val matches = pattern.findAll(text)
 
    val sentences = matches.map { it.value.trim() }.toList()
 
    println(sentences)
}
cs


Share:
Read More
,

Text-To-Speech(TTS) not worked above Android 13

 Text-To-Speech(TTS) not worked above Android 13

Android development blog


Text-to-speech(TTS) is the underlying software used by screen readers when they convert text into spoken content..

However, you can not have TTS service basically from Android 13.

You must take action following below guide.

  1. Open your device Settings .
  2. Select Accessibility and then Text-to-speech output.
  3. Choose your preferred engine, language, speech rate, and pitch.
    • The default text-to-speech engine choices vary by device. Options can include Google's Text-to-speech engine, the device manufacturer's engine, and any third-party text-to-speech engines that you've downloaded from the Google Play Store.





Share:
Read More
,

Variety of Stream in Java(자바 스트림 종류)

Variety of Stream in Java

자바 스트림 종류

Android development blog


종류IO 대상 기준자료의 종류 기준스트림의 기능 기준
FileInputStream입력 스트림바이트 단위기반 스트림
FileReader입력 스트림문자 단위기반 스트림
BufferedInputStream입력 스트림바이트 단위보조 스트림
BufferedReader입력 스트림문자 단위보조 스트림
FileOutputStream출력 스트림바이트 단위기반 스트림
FileWriter출력 스트림문자 단위기반 스트림
BufferedOutputStream출력 스트림바이트 단위보조 스트림
BufferedWriter출력 스트림문자 단위보조 스트림


✊ 문자 기반 스트림

자바의 Char 형은 2 byte를 사용하는데, 바이트 단위는 입출력 단위가 1 byte이므로 문자를 처리하기 어려웠다.

이를 보완하기 위해 등장한 것이 바로 문자 기반 스트림이다.


✋ 보조 스트림

기반 스트림은 대상에 직접 자료를 읽고 쓰는 기능의 스트림이다.

보토 스트림은 스트림의 기능을 향상시키거나 새로운 기능을 추가할 수 있는 스트림을 말한다.

오로지 보완하는 용도이기에 실제데이터를 주고 받지 않고, 데이터를 입출력하는 기능은 없다.

따라서 스트림을 먼저 생성한 후, 보조 스트림을 생성하여 사용한다.


출처: 여기











Share:
Read More
,

Get Uri from android drawable resource

 Get Uri from android drawable resource

Android development blog

1. What I have in my android drawable folder

android project drawable folder


2. Get Uri from drawable

val imgResourceId = context.resources.getIdentifier("album" + song.image.substringBefore("."), "drawable", context.packageName)
val imageUri = Uri.Builder().scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
.authority(context.resources.getResourcePackageName(imgResourceId))
.appendPath(context.resources.getResourceTypeName(imgResourceId))
.appendPath(context.resources.getResourceEntryName(imgResourceId))
.build()


3. Result

android.resource://net.twobeone.battlesinger/drawable/album00290

android.resource://net.twobeone.battlesinger/drawable/album01468

android.resource://net.twobeone.battlesinger/drawable/album49492


Share:
Read More
, , ,

SideEffect in Android Composable(collectAsStateWithLifecycle, LaunchedEffect, rememberCoroutineScope)

 SideEffect in Android Composable


Android developer blog

✋✋✋ SideEffect

A side-effect in Compose is a change to the state of the app that happens outside the scope of a composable function.

For example, opening a new screen when the user taps on a button, or showing a message when the app doesn't have Internet connection.


1. collectAsStateWithLifecycle

dependencies {
implementation "androidx.lifecycle:lifecycle-runtime-compose:2.6.0"
}

First, add dependency of "androidx.lifecycle:lifecycle-runtime-compose"


@OptIn(ExperimentalMaterialApi::class)
@Composable
fun CraneHomeContent(
onExploreItemClicked: OnExploreItemClicked,
openDrawer: () -> Unit,
modifier: Modifier = Modifier,
viewModel: MainViewModel = viewModel(),
) {
// TODO Codelab: collectAsStateWithLifecycle step - consume stream of data from the ViewModel
// val suggestedDestinations: List<ExploreModel> = remember { emptyList() }
val suggestedDestinations by viewModel.suggestedDestinations.collectAsStateWithLifecycle()

val onPeopleChanged: (Int) -> Unit = { viewModel.updatePeople(it) }
var tabSelected by remember { mutableStateOf(CraneScreen.Fly) }

BackdropScaffold(
modifier = modifier,
scaffoldState = rememberBackdropScaffoldState(BackdropValue.Revealed),
frontLayerScrimColor = Color.Unspecified,
appBar = {
HomeTabBar(openDrawer, tabSelected, onTabSelected = { tabSelected = it })
},
backLayerContent = {
SearchContent(
tabSelected,
viewModel,
onPeopleChanged
)
},
frontLayerContent = {
when (tabSelected) {
CraneScreen.Fly -> {
ExploreSection(
title = "Explore Flights by Destination",
exploreList = suggestedDestinations,
onItemClicked = onExploreItemClicked
)
}
CraneScreen.Sleep -> {
ExploreSection(
title = "Explore Properties by Destination",
exploreList = viewModel.hotels,
onItemClicked = onExploreItemClicked
)
}
CraneScreen.Eat -> {
ExploreSection(
title = "Explore Restaurants by Destination",
exploreList = viewModel.restaurants,
onItemClicked = onExploreItemClicked
)
}
}
}
)
}

Second, in CrameHomeContent composable, you can consume the list of destinations as form of state using collectAsstateWithLifecycle() method.


💪💪💪 Compose also offers APIs for Android's most popular stream-based solutions:

- LiveData.observeAsState() in "androidx.compose.runtime:runtime-livedata"

- Observable.subscribeAsState() in "androidx.compose.runtime:runtime-rxjava2"


2. LaunchedEffect and rememberUpdatedState

To call suspend functions safely from inside a composable, use the LaunchedEffect API, which triggers a coroutine scoped side-effect in Compose.

When LaunchedEffect enters the Composition, it launches a coroutine with the block of code passed as a key parameter.

The coroutine will be canceled if LaunchedEffect leaves the composition.


LaunchedEffect take a variable number of keys as a parameter that are used to restart the effect whenever one of those keys changes.

@Composable
fun LandingScreen(onTimeout: () -> Unit, modifier: Modifier = Modifier) {
Box(modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
val currentOnTimeOut by rememberUpdatedState(onTimeout)    //1

LaunchedEffect(key1 = Unit) {    //2
delay(SplashWaitTime)
onTimeout.invoke()
}
Image(painterResource(id = R.drawable.ic_crane_drawer), contentDescription = null)
}
}

1 => The rememberUpdatedState() make us refer to the latest onTimeout function that LandingScreen was recomposed with

2 => Create an coroutine scope that matches the lifecycle of LandingScreen.

Because the key parameter is Unit that is not changed, the delay shouldn't start again.


3. rememberCoroutineScope

API to open the navigation drawer is suspend function.

How do we call suspend function in callback function?

@Composable
fun CraneHome(
onExploreItemClicked: OnExploreItemClicked,
modifier: Modifier = Modifier,
) {
val scaffoldState = rememberScaffoldState()
Scaffold(
scaffoldState = scaffoldState,
modifier = Modifier.statusBarsPadding(),
drawerContent = {
CraneDrawer()
}
) { padding ->
val scope = rememberCoroutineScope()
CraneHomeContent(
modifier = modifier.padding(padding),
onExploreItemClicked = onExploreItemClicked,
openDrawer = {
scope.launch {
scaffoldState.drawerState.open()
}
}
)
}
}

We want a CoroutineScope that follows the lifecycle of its call-site.

The rememberCoroutineScope API returns a CoroutineScope bound to the point in the Composition where you call it.

The scope will be automatically canceled once it leaves the Composition.


✊✊✊ LaunchedEffect vs rememberCoroutineScope

Using LauncedEffect is not possible to use in regular callback which is outside of the Composition.

Both can produce CoroutineScope but, LaunchedEffect can control when the side-effect would be called.


Share:
Read More