In my app, I have integrated Mapbox and It was working fine. But now It's not loading a map in NavigationView. It is working fine in master branch but not working on the BLE features branch even though I have not changed anything in that Activity. Please find below code here, I am launching this NavigationActivity from MainActivity where user select origin and destination locations.
NavigationActivity-Screen:
NavigationActivity.java:
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.mapbox.api.directions.v5.models.BannerText;
import com.mapbox.api.directions.v5.models.DirectionsRoute;
import com.mapbox.api.directions.v5.models.LegStep;
import com.mapbox.services.android.navigation.ui.v5.NavigationViewOptions;
import com.mapbox.services.android.navigation.ui.v5.OnNavigationReadyCallback;
import com.mapbox.services.android.navigation.ui.v5.instruction.InstructionLoader;
import com.mapbox.services.android.navigation.v5.milestone.BannerInstructionMilestone;
import com.mapbox.services.android.navigation.v5.milestone.Milestone;
import com.mapbox.services.android.navigation.v5.milestone.MilestoneEventListener;
import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress;
import java.math.BigDecimal;
import java.util.List;
public class NavigationActivity extends AppCompatActivity implements MilestoneEventListener, OnNavigationReadyCallback {
private TextView myBanner;
ImageView next, previous;
List<LegStep> steps;
TextView tv_step;
int currentStepIndex = 0;
DirectionsRoute currentRoute = null ;
com.mapbox.services.android.navigation.ui.v5.NavigationView navigationView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_navigations);
navigationView = findViewById(R.id.navigationView);
myBanner = findViewById(R.id.dummyBanner);
tv_step = findViewById(R.id.tv_step);
next = findViewById(R.id.iv_next);
previous = findViewById(R.id.iv_previous);
navigationView.onCreate(savedInstanceState);
navigationView.initialize(this);
try{
currentRoute = (DirectionsRoute) getIntent().getSerializableExtra("route");
if(currentRoute != null){
steps = currentRoute.legs().get(0).steps();
if(steps.size() > 0){
setup();
}
}
}catch (Exception e){}
}
private void setup(){
loadText( 0);
next.setOnClickListener((View v )-> {
if (currentStepIndex < steps.size() - 2)
loadText(++currentStepIndex);
});
previous.setOnClickListener((View v )-> {
if (currentStepIndex > 0)
loadText(--currentStepIndex);
});
}
private void loadText( int index){
BannerText bannerText = steps.get(index).bannerInstructions().get(0).primary();
InstructionLoader loader = new InstructionLoader(tv_step, bannerText );
loader.loadInstruction();
String text = tv_step.getText().toString();
String modifier = bannerText.modifier();
String directionArrow = getDirectionArrow(text, modifier);
if(!directionArrow.equals(""))
tv_step.setText(directionArrow + text);
tv_step.append(" " + getDistanceStr(steps.get(index).distance()));
Log.d("Debugging modifier", bannerText.toJson());
}
#Override
public void onNavigationReady(boolean isRunning) {
DirectionsRoute directionsRoute = (DirectionsRoute) getIntent().getSerializableExtra("route");
NavigationViewOptions options = NavigationViewOptions.builder()
.directionsRoute(directionsRoute)
.shouldSimulateRoute(false)
.milestoneEventListener(this)
.build();
navigationView.startNavigation(options);
}
#Override
public void onMilestoneEvent(RouteProgress routeProgress, String instruction, Milestone milestone) {
try {
if (milestone instanceof BannerInstructionMilestone) {
BannerText primaryInstruction = ((BannerInstructionMilestone) milestone).getBannerInstructions().primary();
primaryInstruction.text();
InstructionLoader loader = new InstructionLoader(myBanner, primaryInstruction);
loader.loadInstruction();
String text = myBanner.getText().toString();
String modifier = primaryInstruction.modifier();
String directionArrow = getDirectionArrow(text, modifier);
if(!directionArrow.equals(""))
myBanner.setText(directionArrow + text);
double distance = routeProgress.currentLegProgress().currentStep().distance();
String distanceStr = getDistanceStr(distance);
String milestoneString = myBanner.getText().toString() + distanceStr;
}
}catch (Exception e){
e.printStackTrace();
}
}
private String getDirectionArrow(String text, String modifier){
Log.e("Debugging", text + " " + modifier);
if (text.contains("right") || modifier.contains("right"))
return "> ";
else if (text.contains("left") || modifier.contains("left"))
return "< ";
else if (text.contains("straight") || modifier.contains("straight"))
return "^ ";
return "";
}
private String getDistanceStr(double distance){
if(distance > 1000)
return " " + formatAmount(distance/1000) + " km";
else return " " + distance + " m";
}
#Override
public void onStart() {
super.onStart();
navigationView.onStart();
}
#Override
public void onResume() {
super.onResume();
navigationView.onResume();
}
#Override
public void onLowMemory() {
super.onLowMemory();
navigationView.onLowMemory();
}
#Override
public void onBackPressed() {
if (!navigationView.onBackPressed()) {
super.onBackPressed();
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
navigationView.onSaveInstanceState(outState);
super.onSaveInstanceState(outState);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
navigationView.onRestoreInstanceState(savedInstanceState);
}
#Override
public void onPause() {
super.onPause();
navigationView.onPause();
}
#Override
public void onStop() {
super.onStop();
navigationView.onStop();
}
#Override
protected void onDestroy() {
super.onDestroy();
navigationView.onDestroy();
}
public static String formatAmount(Double str){
BigDecimal bd = new BigDecimal(str);
bd = bd.setScale(2, BigDecimal.ROUND_HALF_UP);
return bd.toString();
}
}
activity_navigations.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:mapbox="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="talha.niazi.hudlitenav.MainActivity"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:id="#+id/dummyBanner"
android:background="#color/design_default_color_primary"
android:textColor="#color/mapboxWhite"
android:padding="10dp"
android:layout_height="wrap_content" />
<RelativeLayout
android:layout_width="match_parent"
android:background="#color/button_red"
android:id="#+id/ll_nav"
android:padding="15dp"
android:layout_height="wrap_content">
<ImageView
android:layout_width="30sp"
android:tint="#color/white_color"
android:id="#+id/iv_previous"
mapbox:srcCompat="#drawable/previous"
android:layout_height="30sp" />
<TextView
android:layout_width="wrap_content"
android:textColor="#color/white_color"
android:layout_marginStart="10sp"
android:textStyle="bold"
android:layout_marginEnd="10sp"
android:layout_centerVertical="true"
android:id="#+id/tv_step"
android:layout_centerHorizontal="true"
android:layout_height="wrap_content" />
<ImageView
android:layout_width="30sp"
android:layout_alignParentEnd="true"
android:id="#+id/iv_next"
android:tint="#color/white_color"
mapbox:srcCompat="#drawable/next"
android:layout_height="30sp" />
</RelativeLayout>
<com.mapbox.services.android.navigation.ui.v5.NavigationView
android:id="#+id/navigationView"
android:layout_below="#id/ll_nav"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
It would be great if you can help me to fix this weird issue.
Can you try to set the content theme
super.onCreate(savedInstanceState)
setTheme(R.style.Theme_AppCompat_Light_NoActionBar);
before setting the contentView?
Also where did you set the style of NavigationView? You can do that in the layout XML file:
<com.mapbox.services.android.navigation.ui.v5.NavigationView
android:id="#+id/navigationView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:navigationDarkTheme="#style/CustomNavigationView"
app:navigationLightTheme="#style/CustomNavigationView"
app:navigationViewMapStyle="mapbox://styles/StyleURL"/>
Please use your custom styleURL.
Please let me know if it helped!
Solution in Kotlin
For more information
This issue has been resolved here Can’t start turn-by-turn navigation within custom NavigationViewActivity/NavigationViewFragment #1524
First I updated the SDK version from 0.13.0 to 0.23.0
implementation 'com.mapbox.mapboxsdk:mapbox-android-navigation-ui:0.23.0'
The dependency will transitively bring in the Maps SDK and the core navigation libraries. This helps prevents conflicts.
In project root build.gradle don't forget to add
maven { url 'https://mapbox.bintray.com/mapbox' }
in fragment_navigation.xml
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="NavigationViewFragment">
<com.mapbox.navigation.ui.NavigationView
android:id="#+id/navigationView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
In NavigationViewFragment
originPoint and destinationPoint is variable type Point.fromLngLat(longitude,latitude)
class NavigationViewFragment : Fragment(), OnNavigationReadyCallback, NavigationListener {
private lateinit var navigationView: NavigationView
var directionsRoute: DirectionsRoute? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
.....
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
navigationView = view.findViewById(R.id.navigationView) as NavigationView
navigationView.onCreate(savedInstanceState)
val initialPosition = CameraPosition.Builder()
.target(LatLng(originPoint.longitude(), originPoint.latitude()))
.zoom(18.0)
.build()
navigationView.initialize(this, initialPosition)
}
override fun onNavigationReady(isRunning: Boolean) {
val origin = Point.fromLngLat(originPoint.longitude() , originPoint.latitude())
val destination = Point.fromLngLat(destinationPoint.longitude(), destinationPoint.latitude())
calculateRoute(origin, destination)
}
override fun onCancelNavigation() {
// Do something
}
override fun onNavigationFinished() {
// Do something
}
override fun onNavigationRunning() {
// Do something
}
private fun calculateRoute(origin: Point , destination: Point) {
NavigationRoute.builder(this.context)
.accessToken(Mapbox.getAccessToken()!!)
.origin(origin)
.destination(destination)
.build()
.getRoute( object : Callback<DirectionsResponse> { //import retrofit2.Callback
// Send request to Direction API
override fun onFailure(call: Call<DirectionsResponse>? , t: Throwable?) {
}
override fun onResponse(call: Call<DirectionsResponse>? ,
response: Response<DirectionsResponse>?) {
if (response?.body() == null || response.body()?.routes()?.size!! < 1) {
return
}
directionsRoute = response.body()!!.routes()[0]
startNavigation()
}
})
}
private fun startNavigation() {
if (directionsRoute == null) return
val options = NavigationViewOptions.builder()
.directionsRoute(directionsRoute)
.shouldSimulateRoute(true)
.navigationListener(this)
.build()
// start camera zooms to the beginning of the route
navigationView.startCamera(directionsRoute)
navigationView.startNavigation(options)
}
}
Related
I tried different ways untill I figured out that the problem is with the bellow these textViews:
name.text = user.name+" "+user.lastName
phoneNumber.text = user.phoneNumber
I used them into a Datasnapshot to retrive {user name and last name and phone number} data on navigationdrawer header like bellow:
private fun getUserData() {
val scoresRef = Firebase.database.getReference("Users")
scoresRef.child(uid).addValueEventListener(object : ValueEventListener {
#SuppressLint("SetTextI18n")
override fun onDataChange(snapshot: DataSnapshot) {
user = snapshot.getValue(User::class.java)!!
val name = findViewById<TextView>(R.id.tvFirstNameAndLastName)
val phoneNumber = findViewById<TextView>(R.id.tvPhoneNumber)
name.text = user.name+" "+user.lastName
phoneNumber.text = user.phoneNumber
getUserProfile()
}
override fun onCancelled(error: DatabaseError) {
finish()
}
})
}
when I remove that two lines, everything works fine and no problem with theme and changing language, but by using them data fetching is OK and no problem too, I just want to change app theme or language but this error shows in logcat after app crashed :
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
at af.azdreams.myconquer.DashboardActivity$getUserData$1.onDataChange(DashboardActivity.kt:293)
1- this is my activity_dashboard.xml :
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout
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:id="#+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".DashboardActivity">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/Orange"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageButton
android:id="#+id/btnSearchUsers"
android:layout_width="wrap_content"
android:background="#0000"
android:layout_height="wrap_content"
app:srcCompat="#drawable/icon_search"
android:contentDescription="#string/todo" />
</androidx.appcompat.widget.Toolbar>
<com.google.android.material.tabs.TabLayout
app:tabTextAppearance="#style/MineCustomTabText"
android:id="#+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager.widget.ViewPager
android:id="#+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.navigation.NavigationView
android:id="#+id/navView"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="#layout/header"
app:itemTextAppearance="#style/menu"
app:menu="#menu/nav_menu" />
</androidx.drawerlayout.widget.DrawerLayout>
2- this is the DashboardActivity.kt :
import af.azdreams.myconquer.databinding.ActivityDashboardBinding
import af.azdreams.myconquer.fragments.ExploreFragment
import af.azdreams.myconquer.fragments.FlightsFragment
import af.azdreams.myconquer.fragments.TravelFragment
import android.annotation.SuppressLint
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.content.res.Configuration
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Bundle
import android.preference.PreferenceManager
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.appcompat.widget.Toolbar
import androidx.drawerlayout.widget.DrawerLayout
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentPagerAdapter
import androidx.viewpager.widget.ViewPager
import com.google.android.material.badge.BadgeDrawable
import com.google.android.material.navigation.NavigationView
import com.google.android.material.tabs.TabLayout
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.*
import com.google.firebase.database.ktx.database
import com.google.firebase.ktx.Firebase
import com.google.firebase.storage.FirebaseStorage
import com.google.firebase.storage.StorageReference
import java.io.File
import java.util.*
class DashboardActivity : AppCompatActivity() {
private lateinit var storageReference: StorageReference
private lateinit var databaseReference: DatabaseReference
private lateinit var user: User
private lateinit var uid: String
private var toolbar: Toolbar? = null
private var viewPager: ViewPager? = null
private var tabLayout: TabLayout? = null
private var exploreFragment: ExploreFragment? = null
private var flightsFragment: FlightsFragment? = null
private var travelFragment: TravelFragment? = null
private lateinit var auth: FirebaseAuth
private lateinit var binding: ActivityDashboardBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
auth = FirebaseAuth.getInstance()
uid = auth.currentUser?.uid.toString()
databaseReference = FirebaseDatabase.getInstance().getReference("Users")
if (uid.isNotEmpty()){
getUserData()
}
loadLocale()
binding = ActivityDashboardBinding.inflate(layoutInflater)
setContentView(binding.root)
onClickListenerSearchUser()
val scoresRef = Firebase.database.getReference("Users")
scoresRef.keepSynced(true)
initData()
checkTheme()
findViewById<Toolbar>(R.id.toolbar).also { toolbar = it }
setSupportActionBar(toolbar)
findViewById<ViewPager>(R.id.viewPager).also { viewPager = it }
findViewById<TabLayout>(R.id.tabLayout).also { tabLayout = it }
exploreFragment = ExploreFragment()
flightsFragment = FlightsFragment()
travelFragment = TravelFragment()
with(tabLayout) { this?.setupWithViewPager(viewPager) }
val viewPagerAdapter = ViewPagerAdapter(supportFragmentManager, 0)
viewPagerAdapter.addFragment(exploreFragment!!,resources.getString(R.string.home))
viewPagerAdapter.addFragment(flightsFragment!!, "Flights")
viewPagerAdapter.addFragment(travelFragment!!,resources.getString(R.string.dictionary))
with(viewPager) {
this!!.adapter = viewPagerAdapter
}
val tabLayout = tabLayout
tabLayout?.getTabAt(0)?.setIcon(R.drawable.icon_home)
tabLayout?.getTabAt(1)?.setIcon(R.drawable.icon_flights)
tabLayout?.getTabAt(2)?.setIcon(R.drawable.icon_dictionary)
val badgeDrawable: BadgeDrawable = tabLayout?.getTabAt(0)!!.orCreateBadge
badgeDrawable.isVisible = true
badgeDrawable.number = 12
val drawerLayout = findViewById<DrawerLayout>(af.azdreams.myconquer.R.id.drawerLayout)
val toolbar = findViewById<Toolbar>(R.id.toolbar)
val navView = findViewById<NavigationView>(R.id.navView)
val toggle = ActionBarDrawerToggle(this,drawerLayout,toolbar, R.string.open,
R.string.close)
toggle.isDrawerIndicatorEnabled = true
supportActionBar?.setDisplayShowTitleEnabled(false)
drawerLayout.addDrawerListener(toggle)
toggle.syncState()
navView.setNavigationItemSelectedListener {
when(it.itemId){
R.id.itmFetch ->startActivity(Intent(this,UserProfileActivity::class.java))
R.id.itmProfile ->startActivity(Intent(this,Profile::class.java))
R.id.itmLanguage ->showChangeLanguageDialog()
R.id.itmAppearance ->chooseThemeDialog()
R.id.itmSignOut ->basicAlert()
R.id.itmRateAndComments ->{
val url = "https://play.google.com/store/apps/details?id=org.telegram.plus"
if (url.startsWith("https://") || url.startsWith("http://")) {
val uri = Uri.parse(url)
val intent = Intent(Intent.ACTION_VIEW, uri)
startActivity(intent)
}
}
R.id.itmAbout ->startActivity(Intent(this,About::class.java))
}
true
}
}
private var backPressedTime:Long = 0
private lateinit var backToast: Toast
override fun onBackPressed() {
backToast = Toast.makeText(this,resources.getString(R.string.press_back_again_to_leave_the_app), Toast.LENGTH_SHORT)
if (backPressedTime + 2000 > System.currentTimeMillis()) {
backToast.cancel()
super.onBackPressed()
return
} else {
backToast.show()
}
backPressedTime = System.currentTimeMillis()
}
private fun showChangeLanguageDialog() {
val pref = getSharedPreferences("Settings", MODE_PRIVATE)
val mBuilder = AlertDialog.Builder(this)
val listItems = arrayOf("English", "فارسی دری", "پښتو")
var checkedItem = 0
when {
pref.getString("My_Lang", "en").equals("en") -> {
checkedItem = 0
}
pref.getString("My_Lang", "en").equals("fa") -> {
checkedItem = 1
}
pref.getString("My_Lang", "en").equals("ps") -> {
checkedItem = 2
}
}
mBuilder.setSingleChoiceItems(listItems, checkedItem) { dialogInterface: DialogInterface, i: Int ->
when (i) {
0 -> {
setLocale("en")
startActivity(Intent(this,SplashScreen::class.java))
}
1 -> {
setLocale("fa")
startActivity(Intent(this,SplashScreen::class.java))
}
2 -> {
setLocale("ps")
startActivity(Intent(this,SplashScreen::class.java))
}
}
dialogInterface.dismiss()
}
val mDialog = mBuilder.create()
mDialog.show()
}
private fun setLocale(lang: String?) {
val locale = Locale(lang)
Locale.setDefault(locale)
val config = Configuration()
config.locale = locale
baseContext.resources.updateConfiguration(config, baseContext.resources.displayMetrics)
val editor = getSharedPreferences("Settings", MODE_PRIVATE).edit()
editor.putString("My_Lang", lang)
editor.apply()
}
private fun loadLocale() {
val prefs = getSharedPreferences("Settings", MODE_PRIVATE)
val language = prefs.getString("My_Lang", "")
setLocale(language)
}
private fun basicAlert(){
val positiveButtonClick = { _: DialogInterface, _: Int -> }
val negativeButtonClick = { _: DialogInterface, _: Int -> }
val builder = AlertDialog.Builder(this)
with(builder) {
setMessage(R.string.do_you_want_to_sign_out_from_your_my_conquer_account)
setPositiveButton(R.string.yes, positiveButtonClick)
setPositiveButton(R.string.yes) { _: DialogInterface, _: Int ->
auth.signOut()
startActivity(Intent(this#DashboardActivity, SignInActivity::class.java))
finish()
}
setNegativeButton(R.string.no, negativeButtonClick)
show()
}
}
private fun initData(){
auth = FirebaseAuth.getInstance()
setUserEmail()
}
private fun setUserEmail(){
getCurrentUserEmail()
}
private fun getCurrentUserEmail():String? {
return auth.currentUser?.email
}
private fun chooseThemeDialog() {
val builder = AlertDialog.Builder(this)
val styles = arrayOf(resources.getString(R.string.light),resources.getString(R.string.dark),resources.getString(
R.string.system_default))
val checkedItem = MyPreferences(this).darkMode
builder.setSingleChoiceItems(styles, checkedItem) { dialog, which ->
when (which) {
0 -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
MyPreferences(this).darkMode = 0
delegate.applyDayNight()
dialog.dismiss()
}
1 -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
MyPreferences(this).darkMode = 1
delegate.applyDayNight()
dialog.dismiss()
}
2 -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
MyPreferences(this).darkMode = 2
delegate.applyDayNight()
dialog.dismiss()
}
}
}
val dialog = builder.create()
dialog.show()
}
class MyPreferences(context: Context?) {
companion object {
private const val DARK_STATUS = ""
}
private val preferences = PreferenceManager.getDefaultSharedPreferences(context)
var darkMode = preferences.getInt(DARK_STATUS, 0)
set(value) = preferences.edit().putInt(DARK_STATUS, value).apply()
}
private fun checkTheme() {
when (MyPreferences(this).darkMode) {
0 -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
delegate.applyDayNight()
}
1 -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
delegate.applyDayNight()
}
2 -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
delegate.applyDayNight()
}
}
}
private class ViewPagerAdapter(fm: FragmentManager, behavior: Int) :
FragmentPagerAdapter(fm, behavior) {
private val fragments: MutableList<Fragment> = ArrayList()
private val fragmentTitle: MutableList<String> = ArrayList()
fun addFragment(fragment: Fragment, title: String) {
fragments.add(fragment)
fragmentTitle.add(title)
}
override fun getItem(position: Int): Fragment {
return fragments[position]
}
override fun getCount(): Int {
return fragments.size
}
override fun getPageTitle(position: Int): CharSequence {
return fragmentTitle[position]
}
}
private fun getUserData() {
val scoresRef = Firebase.database.getReference("Users")
scoresRef.child(uid).addValueEventListener(object : ValueEventListener {
#SuppressLint("SetTextI18n")
override fun onDataChange(snapshot: DataSnapshot) {
user = snapshot.getValue(User::class.java)!!
val name = findViewById<TextView>(R.id.tvFirstNameAndLastName)
val phoneNumber = findViewById<TextView>(R.id.tvPhoneNumber)
name.text = user.name+" "+user.lastName
phoneNumber.text = user.phoneNumber
getUserProfile()
}
override fun onCancelled(error: DatabaseError) {
finish()
}
})
}
private fun getUserProfile() {
val navigationView = binding.navView
val header: View = navigationView.getHeaderView(0)
storageReference = FirebaseStorage.getInstance().reference.child("Users/$uid")
val localeFile = File.createTempFile("tempFile","")
storageReference.getFile(localeFile).addOnSuccessListener {
val bitmap = BitmapFactory.decodeFile(localeFile.absolutePath)
val picture = header.findViewById<ImageView>(R.id.circleImageView)
picture.setImageBitmap(bitmap)
}.addOnFailureListener{
finish()
}
}
private fun onClickListenerSearchUser(){
binding.btnSearchUsers.setOnClickListener{
startActivity(Intent(this,SearchUsers::class.java))
}
}
}
the header.xml in layout folder :
<?xml version="1.0" encoding="utf-8"?>
<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="150dp"
android:id="#+id/header"
android:background="#color/Orange">
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/circleImageView"
android:layout_width="67dp"
android:layout_height="67dp"
android:layout_marginStart="5dp"
app:civ_border_width="1dp"
android:src="#drawable/profile"
app:civ_border_color="#color/White"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.047"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.213" />
<TextView
android:id="#+id/tvFirstNameAndLastName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:layout_marginTop="13dp"
android:text=""
android:textColor="#color/White"
android:textSize="15dp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.05"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/circleImageView" />
<TextView
android:id="#+id/tvPhoneNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:text=""
android:textColor="#color/Black"
android:textSize="13dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.05"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tvFirstNameAndLastName"
app:layout_constraintVertical_bias="0.0" />
</androidx.constraintlayout.widget.ConstraintLayout>
the user.class that is for user profile information :
package af.azdreams.myconquer
data class User(var name : String ?= null, var lastName : String ?= null, var educationLevel : String ?= null, var province : String ?= null, var age : String ?= null, var phoneNumber : String ?= null)
please help me on this issue.
thank you!
I try to implement MVVM by Mindorks to show data from here :(https://api.themoviedb.org/3/movie/384018?api_key=67bc513a7a353631119fdffe5f7377a8&language=en-US) in my Activity. I try using databinding for update UI, but after the data is update, databinding not update my textview. here my Detail Activity Class :
public class DetailActivity extends BaseActivity<ActivityDetailBinding, DetailViewModel> implements DetailNavigator {
#Inject
DetailViewModel detailViewModel;
public static final String INTENT_ID = "id_intent";
public static final String INTENT_FLAG = "id_flag";
private ActivityDetailBinding mActivityDetailBinding;
public static Intent newIntent(Context context) {
return new Intent(context, DetailActivity.class);
}
#Override
public int getBindingVariable() {
return BR.viewModel;
}
#Override
public int getLayoutId() {
return R.layout.activity_detail;
}
#Override
public DetailViewModel getViewModel() {
return detailViewModel;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
detailViewModel.setNavigator(this);
mActivityDetailBinding = getViewDataBinding();
initView();
initData(savedInstanceState);
}
private void initData(Bundle savedInstanceState) {
Bundle extras = getIntent().getExtras();
if (extras != null) {
int id = extras.getInt(INTENT_ID, 0);
int flag = extras.getInt(INTENT_FLAG, 0);
detailViewModel.fetchDetail(id, flag);
}
}
private void initView() {
if (getSupportActionBar() != null) {
getSupportActionBar().hide();
}
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
#Override
public void ShowProgressDialog(Boolean loading) {
if (loading) {
showLoading();
} else {
hideLoading();
}
}
}
and my BaseActivity like this :
public abstract class BaseActivity<T extends ViewDataBinding, V extends BaseViewModel> extends AppCompatActivity
implements BaseFragment.Callback {
// TODO
// this can probably depend on isLoading variable of BaseViewModel,
// since its going to be common for all the activities
private ProgressDialog mProgressDialog;
private T mViewDataBinding;
private V mViewModel;
/**
* Override for set binding variable
*
* #return variable id
*/
public abstract int getBindingVariable();
/**
* #return layout resource id
*/
public abstract
#LayoutRes
int getLayoutId();
/**
* Override for set view model
*
* #return view model instance
*/
public abstract V getViewModel();
#Override
public void onFragmentAttached() {
}
#Override
public void onFragmentDetached(String tag) {
}
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
performDependencyInjection();
super.onCreate(savedInstanceState);
performDataBinding();
}
public T getViewDataBinding() {
return mViewDataBinding;
}
#TargetApi(Build.VERSION_CODES.M)
public boolean hasPermission(String permission) {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.M ||
checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
}
public void hideKeyboard() {
View view = this.getCurrentFocus();
if (view != null) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
}
}
public void hideLoading() {
if (mProgressDialog != null && mProgressDialog.isShowing()) {
mProgressDialog.cancel();
}
}
public void showLoading() {
hideLoading();
mProgressDialog = CommonUtils.showLoadingDialog(this);
}
public boolean isNetworkConnected() {
return NetworkUtils.isNetworkConnected(getApplicationContext());
}
public void performDependencyInjection() {
AndroidInjection.inject(this);
}
#TargetApi(Build.VERSION_CODES.M)
public void requestPermissionsSafely(String[] permissions, int requestCode) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(permissions, requestCode);
}
}
// public void showLoading() {
// hideLoading();
// mProgressDialog = CommonUtils.showLoadingDialog(this);
// }
private void performDataBinding() {
mViewDataBinding = DataBindingUtil.setContentView(this, getLayoutId());
this.mViewModel = mViewModel == null ? getViewModel() : mViewModel;
mViewDataBinding.setVariable(getBindingVariable(), mViewModel);
mViewDataBinding.setLifecycleOwner(this);
mViewDataBinding.executePendingBindings();
}
#Override
protected void onResume() {
super.onResume();
}
#Override
protected void onDestroy() {
super.onDestroy();
}
}
this is my ViewModel class :
public class DetailViewModel extends BaseViewModel<DetailNavigator> {
private final ObservableField<String> originalName = new ObservableField<>();
private final ObservableField<String> releaseDate = new ObservableField<>();
private final ObservableField<String> overview = new ObservableField<>();
private final ObservableField<String> genreMovie = new ObservableField<>();
private final ObservableField<String> posterPath = new ObservableField<>();
private final ObservableField<String> voteAverage = new ObservableField<>();
public DetailViewModel(DataManager dataManager, SchedulerProvider schedulerProvider) {
super(dataManager, schedulerProvider);
}
public void fetchDetail(int id, int flag) {
if (flag == 1) {
getNavigator().ShowProgressDialog(true);
getCompositeDisposable().add(getDataManager()
.getApiHelper().doDetailMovie(id, URLConfig.API_KEY, getDataManager().getLanguage())
.subscribeOn(getSchedulerProvider().io())
.observeOn(getSchedulerProvider().ui())
.subscribe(detailResponse -> {
setUpData(detailResponse);
getNavigator().ShowProgressDialog(false);
}, throwable -> {
getNavigator().ShowProgressDialog(false);
}));
} else if (flag == 2) {
getNavigator().ShowProgressDialog(true);
getCompositeDisposable().add(getDataManager()
.getApiHelper().doDetailTV(id, URLConfig.API_KEY, getDataManager().getLanguage())
.subscribeOn(getSchedulerProvider().io())
.observeOn(getSchedulerProvider().ui())
.subscribe(detailResponse -> {
setUpData(detailResponse);
getNavigator().ShowProgressDialog(false);
}, throwable -> {
getNavigator().ShowProgressDialog(false);
}));
}
}
private void setUpData(DetailResponse detailResponse) {
if (detailResponse.getOriginal_name() != null) {
originalName.set(detailResponse.getOriginal_name());
} else {
originalName.set(detailResponse.getOriginal_title());
}
originalName.notifyChange();
if (detailResponse.getFirst_air_date() != null) {
releaseDate.set(detailResponse.getFirst_air_date());
} else {
releaseDate.set(detailResponse.getRelease_date());
}
overview.set(String.valueOf(detailResponse.getOverview()));
posterPath.set(String.valueOf(detailResponse.getPoster_path()));
voteAverage.set(String.valueOf(detailResponse.getVote_average()));
String genres = "";
for (int i = 0;i<detailResponse.getGenreList().size();i++){
genres = genres+detailResponse.getGenreList().get(i);
}
genreMovie.set(genres);
}
public ObservableField<String> getOriginalName() {
return originalName;
}
public ObservableField<String> getReleaseDate() {
return releaseDate;
}
public ObservableField<String> getOverview() {
return overview;
}
public ObservableField<String> getGenreMovie() {
return genreMovie;
}
public ObservableField<String> getPosterPath() {
return posterPath;
}
public ObservableField<String> getVoteAverage() {
return voteAverage;
}
}
and this is my DetailResponse Class :
public class DetailResponse {
#SerializedName("original_name")
private String original_name ;
#SerializedName("original_title")
private String original_title ;
#SerializedName("release_date")
private String release_date ;
#SerializedName("first_air_date")
private String first_air_date ;
#SerializedName("vote_average")
private Double vote_average ;
#SerializedName("overview")
private String overview ;
#SerializedName("poster_path")
private String poster_path;
#SerializedName("genres")
private List<Genre> genreList;
public String getOriginal_name() {
return original_name;
}
public String getOriginal_title() {
return original_title;
}
public String getRelease_date() {
return release_date;
}
public String getFirst_air_date() {
return first_air_date;
}
public Double getVote_average() {
return vote_average;
}
public String getOverview() {
return overview;
}
public String getPoster_path() {
return poster_path;
}
public List<Genre> getGenreList() {
return genreList;
}
public static class Genre{
#SerializedName("name")
private String name ;
public String getName() {
return name;
}
}
}
and last one, here how I try to get data in my UI using databinding, this is my layout :
<?xml version="1.0" encoding="utf-8"?>
<layout 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"
tools:context=".ui.detail.DetailActivity">
<data>
<variable
name="viewModel"
type="test.ui.detail.DetailViewModel" />
</data>
<androidx.core.widget.NestedScrollView
android:id="#+id/nestedScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:animateLayoutChanges="true">
<com.github.florent37.shapeofview.shapes.ArcView
android:id="#+id/shape_header"
android:layout_width="match_parent"
android:layout_height="#dimen/size300dp"
android:alpha="0.7"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:shape_arc_cropDirection="outside"
app:shape_arc_height="#dimen/size30dp"
app:shape_arc_position="bottom">
<com.flaviofaria.kenburnsview.KenBurnsView
android:id="#+id/image_header"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="#drawable/poster_avengerinfinity"
android:tint="#6F000000" />
</com.github.florent37.shapeofview.shapes.ArcView>
<com.github.florent37.shapeofview.shapes.RoundRectView
android:id="#+id/shape_poster"
android:layout_width="#dimen/size150dp"
android:layout_height="#dimen/size200dp"
android:layout_marginTop="#dimen/margin250dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/shape_header"
app:shape_roundRect_bottomLeftRadius="#dimen/corner10dp"
app:shape_roundRect_bottomRightRadius="#dimen/corner10dp"
app:shape_roundRect_topLeftRadius="#dimen/corner10dp"
app:shape_roundRect_topRightRadius="#dimen/corner10dp">
<ImageView
android:id="#+id/image_poster"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="#string/hint_poster"
android:scaleType="fitXY"
app:imageDetailUrl="#{viewModel.posterPath}"
android:src="#drawable/poster_avengerinfinity" />
</com.github.florent37.shapeofview.shapes.RoundRectView>
<TextView
android:id="#+id/text_title"
style="#style/FontText.Title.Detail"
android:layout_marginTop="#dimen/margin15dp"
android:textSize="#dimen/font_large_size"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/shape_poster"
android:text="#{viewModel.originalName}"
tools:text="#string/hint_title" />
<TextView
android:id="#+id/text_title_release"
style="#style/FontText"
android:layout_marginTop="#dimen/margin10dp"
android:text="#string/text_release"
app:layout_constraintEnd_toStartOf="#+id/guideline"
app:layout_constraintTop_toBottomOf="#+id/text_title" />
<TextView
android:id="#+id/text_release"
style="#style/FontText"
android:layout_marginStart="#dimen/margin2dp"
android:layout_marginTop="#dimen/margin10dp"
app:layout_constraintStart_toEndOf="#+id/text_title_release"
app:layout_constraintTop_toBottomOf="#+id/text_title"
tools:text="#string/hint_release" />
<TextView
android:id="#+id/text_genres"
style="#style/FontText.Normal"
android:layout_marginStart="#dimen/margin15dp"
android:layout_marginTop="#dimen/margin10dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/text_release"
tools:text="#string/hint_genres" />
<TextView
android:id="#+id/text_duration"
style="#style/FontText.Normal.White"
android:layout_marginTop="#dimen/margin10dp"
android:layout_marginEnd="#dimen/margin15dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/text_release"
tools:text="#string/hint_duration" />
<RatingBar
android:id="#+id/rating_bar"
android:layout_width="wrap_content"
android:layout_height="45dp"
android:layout_marginStart="#dimen/margin15dp"
android:layout_marginTop="#dimen/margin5dp"
android:isIndicator="true"
android:numStars="5"
android:rating="3.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/text_duration" />
<TextView
android:id="#+id/text_rating"
style="#style/FontText.Rating.Orange"
android:layout_marginStart="#dimen/margin5dp"
app:layout_constraintRight_toLeftOf="parent"
app:layout_constraintStart_toEndOf="#+id/rating_bar"
app:layout_constraintTop_toBottomOf="#+id/text_duration"
tools:text="#string/hit_rating" />
<TextView
android:id="#+id/text_default_rating"
style="#style/FontText.Rating"
android:textStyle="normal"
app:layout_constraintRight_toLeftOf="parent"
app:layout_constraintStart_toEndOf="#+id/text_rating"
app:layout_constraintTop_toBottomOf="#+id/text_duration"
tools:text="#string/hint_default_rating" />
<TextView
android:id="#+id/text_desc"
style="#style/FontText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/margin15dp"
android:layout_marginTop="#dimen/margin25dp"
android:layout_marginEnd="#dimen/margin15dp"
android:paddingBottom="#dimen/padding100dp"
app:layout_constraintTop_toBottomOf="#+id/rating_bar"
tools:text="#string/hint_desc" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</layout>
I try to show one data first, that is OriginalName for text_title, went I debug my application
public ObservableField<String> getOriginalName() {
return originalName;
}
getOriginalName in class ViewModel, just called before I retrieve my response, but after OriginalName is set, the UI not update and getOriginalName is never called again.I already add originalName.notifyChange(); after the data is set, but it doesn't seem change anything.
I already frustased.. so please... I hope anybody can help me to show me what to do. Thank you very much.
Remove this below line from Detail Activity
setContentView(R.layout.activity_detail);
In your base activity you have performDataBinding method which set the layout id using DataBindingUtil class.
mViewDataBinding = DataBindingUtil.setContentView(this, getLayoutId());
this.mViewModel = mViewModel == null ? getViewModel() : mViewModel;
mViewDataBinding.setVariable(getBindingVariable(), mViewModel);
mViewDataBinding.setLifecycleOwner(this);
mViewDataBinding.executePendingBindings();
I am trying to bind a boolean through the viewmodel to the view, but Android Studio throws an error, and I can't find the problem. The viewModel.infilltype is a boolean, and android:checked should also be a boolean.
"error: '#{viewModel.infillType}' is incompatible with attribute android:checked (attr) boolean.
Message{kind=ERROR, text=error: '#{viewModel.infillType}' is incompatible with attribute android:checked (attr) boolean., sources=[E:\SportveldOnderhoud\app\src\main\res\layout\list_item_check.xml:14], original message=, tool name=Optional.of(AAPT)}"
I have the following code (I will paste snippets which are relevant)
Check.java (Model)
public class Check {
private UUID mId;
private String mTitle;
private Date mDate;
....
private boolean mInfilltype;
....
public Check() {
this(UUID.randomUUID());
}
public Check(UUID id) {
mId = id;
mDate = new Date();
}
public UUID getId() {
return mId;
}
....
public boolean isInfilltype() {
return mInfilltype;
}
public void setInfilltype(boolean infilltype) {
mInfilltype = infilltype;
}
}
ViewModel:
public class CheckViewModel extends BaseObservable {
private Check mCheck;
private Activity mActivity;
public CheckViewModel(Activity activity) {
mActivity = activity;
}
#Bindable
public String getTitle() {
return mCheck.getTitle();
}
#Bindable
public String getRenderedDate() {
return mCheck.getDate().toString();
}
#Bindable
public boolean infillType() {
return mCheck.isInfilltype();
}
public Check getCheck() {
return mCheck;
}
public void setCheck(Check crime) {
mCheck = crime;
List<String> strings;
notifyChange();
}
public void onCheckClicked() {
Intent intent = CheckPagerActivity.newIntent(mActivity, mCheck.getId());
mActivity.startActivity(intent);
}
}
View:
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable name="viewModel" type="nl.lekolkman.android.sportveldonderhoud.CheckViewModel" />
</data>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="#{() -> viewModel.onCheckClicked()}"
>
<CheckBox
android:id="#+id/solved_check_box"
android:checked="#{viewModel.infillType}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"/>
<TextView
android:id="#+id/title_text_view"
android:text="#{viewModel.title}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="#id/solved_check_box"
android:textStyle="bold"
tools:text="Crime Title"/>
<TextView
android:id="#+id/date_text_view"
android:text="#{`Date solved: ` + viewModel.renderedDate ?? `(not solved)`}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="#id/solved_check_box"
android:layout_below="#id/title_text_view"
tools:text="Check Date"/>
</RelativeLayout>
</layout>
It turned out that I had to add:
android {
...
dataBinding {
enabled = true
}
in build.gradle
Then it still didn't work however, but after adding maven to the repositories in the build.gradle files it did work
I'm not super familiar with java, but I'm pretty sure in C# your boolean needs an initial value (not null) to bind properly.
Try changing
private boolean mInfilltype;
to
private boolean mInfilltype = false;
You can use or expand Android Compound View Binding Adapter
import androidx.databinding.BindingAdapter;
import androidx.databinding.BindingMethod;
import androidx.databinding.BindingMethods;
import androidx.databinding.InverseBindingListener;
import androidx.databinding.InverseBindingMethod;
import androidx.databinding.InverseBindingMethods;
import androidx.annotation.RestrictTo;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
/**
* #hide
*/
#RestrictTo(RestrictTo.Scope.LIBRARY)
#BindingMethods({
#BindingMethod(type = CompoundButton.class, attribute = "android:buttonTint", method = "setButtonTintList"),
#BindingMethod(type = CompoundButton.class, attribute = "android:onCheckedChanged", method = "setOnCheckedChangeListener"),
})
#InverseBindingMethods({
#InverseBindingMethod(type = CompoundButton.class, attribute = "android:checked"),
})
public class CompoundButtonBindingAdapter {
#BindingAdapter("android:checked")
public static void setChecked(CompoundButton view, boolean checked) {
if (view.isChecked() != checked) {
view.setChecked(checked);
}
}
#BindingAdapter(value = {"android:onCheckedChanged", "android:checkedAttrChanged"},
requireAll = false)
public static void setListeners(CompoundButton view, final OnCheckedChangeListener listener,
final InverseBindingListener attrChange) {
if (attrChange == null) {
view.setOnCheckedChangeListener(listener);
} else {
view.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (listener != null) {
listener.onCheckedChanged(buttonView, isChecked);
}
attrChange.onChange();
}
});
}
}
}
Ref: https://android.googlesource.com/platform/frameworks/data-binding/+/refs/heads/studio-master-dev/extensions/baseAdapters/src/main/java/androidx/databinding/adapters/CompoundButtonBindingAdapter.java
I have a problem with my setOnClickListener method for one of the buttons in my code. What basically happens is that I call a typeFinder inside the setOnClickListener method, but the first time I press the button the values do not get updated. I have used the debugger and from my understanding what happens is that even though the function is called, the program does not actually go through the function until after setOnClickListener, which means when I press the button the second time it has the right values to show from the previous button press. I have tried using TypesTask as well (as seen in commented part at the bottom of the page), but doing so resulted in the same outcome.
Here is the code for the class:
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private DatabaseReference myRef;
private ArrayList<String> recipesList = new ArrayList<String>();
private String[] types = {"pizza", "ice cream", "sandwich", "salad", "steak"};
private void typeFinder(String type) {
myRef.orderByChild("type").equalTo(type).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// This method is called once with the initial value and again
// whenever data at this location is updated.
String word = "";
boolean wordAdded = false;
String value = dataSnapshot.getValue().toString();
for (int i = 0; i < value.length(); i++) {
if (wordAdded == false) {
if (value.charAt(i) == '=') {
recipesList.add(word);
wordAdded = true;
word = "";
} else if (value.charAt(i) != '{' && value.charAt(i) != ',') {
if (word.length() == 0 && value.charAt(i) == ' ') {
} else {
word = word + value.charAt(i);
}
}
}
if (value.charAt(i) == '}')
if (i + 2 == value.length()) {
wordAdded = false;
break;
} else
wordAdded = false;
}
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.w(TAG, "Failed to read value.", error.toException());
}
});
}
#Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_main);
myRef = FirebaseDatabase.getInstance().getReference();
Button saladsB = (Button) findViewById(R.id.saladButton);
Button pizzaB = (Button) findViewById(R.id.pizzaButton);
Button iceCreamB = (Button) findViewById(R.id.iceCreamButton);
Button steakB = (Button) findViewById(R.id.steakButton);
Button sandwichB = (Button) findViewById(R.id.sandwichButton);
final TextView testTextView = (TextView) findViewById(R.id.test_text_view);
testTextView.setText(Integer.toString(recipesList.size()));
super.onCreate(savedInstanceState);
saladsB.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// recipesList.clear();
// t.typeFinder("salad")
typeFinder("salad");
// new TypesTask().execute("salad");
String recipes = "";
for (int i = 0; i < recipesList.size(); i++) {
recipes = recipes + recipesList.get(i) + "\n";
}
testTextView.setText(recipes);
// Intent intent = new Intent(MainActivity.this, ListviewActivity.class);
// intent.putStringArrayListExtra("FOOD_LIST", recipesList);
// startActivity(intent);
}
});
}
/*
public class TypesTask extends AsyncTask<String, Void, Void> {
#Override
protected void onPreExecute() {
myRef = FirebaseDatabase.getInstance().getReference();
}
#Override
protected Void doInBackground(String... params) {
typeFinder(params[0]);
return null;
}
}
*/
}
Here is the xml for the page
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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="com.example.thevash.recipes.MainActivity">
<LinearLayout
android:layout_width="0dp"
android:layout_height="810dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="458dp"
android:orientation="horizontal"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:layout_constraintLeft_creator="1"
tools:layout_constraintRight_creator="1"
tools:layout_constraintTop_creator="1">
<TextView
android:id="#+id/test_text_view"
android:layout_width="585dp"
android:layout_height="248dp"
android:layout_weight="1"
android:text="TextView"
tools:layout_editor_absoluteX="8dp"
tools:layout_editor_absoluteY="-377dp" />
</LinearLayout>
<Button
android:id="#+id/saladButton"
android:layout_width="0dp"
android:layout_height="48dp"
android:text="Salads"
tools:layout_constraintTop_creator="1"
tools:layout_constraintRight_creator="1"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginTop="5dp"
tools:layout_constraintLeft_creator="1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/pizzaButton"
android:layout_width="0dp"
android:layout_height="48dp"
android:text="Pizzas"
tools:layout_constraintTop_creator="1"
tools:layout_constraintRight_creator="1"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginTop="52dp"
tools:layout_constraintLeft_creator="1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/iceCreamButton"
android:layout_width="0dp"
android:layout_height="48dp"
android:text="ice cream"
tools:layout_constraintTop_creator="1"
tools:layout_constraintRight_creator="1"
app:layout_constraintRight_toRightOf="#+id/pizzaButton"
app:layout_constraintTop_toBottomOf="#+id/pizzaButton"
tools:layout_constraintLeft_creator="1"
app:layout_constraintLeft_toLeftOf="#+id/pizzaButton" />
<Button
android:id="#+id/steakButton"
android:layout_width="0dp"
android:layout_height="48dp"
android:text="steaks"
tools:layout_constraintTop_creator="1"
tools:layout_constraintRight_creator="1"
app:layout_constraintRight_toRightOf="#+id/iceCreamButton"
app:layout_constraintTop_toBottomOf="#+id/iceCreamButton"
tools:layout_constraintLeft_creator="1"
app:layout_constraintLeft_toLeftOf="#+id/iceCreamButton" />
<Button
android:id="#+id/sandwichButton"
android:layout_width="0dp"
android:layout_height="48dp"
android:text="sandwiches"
tools:layout_constraintTop_creator="1"
tools:layout_constraintRight_creator="1"
app:layout_constraintRight_toRightOf="#+id/steakButton"
app:layout_constraintTop_toBottomOf="#+id/steakButton"
tools:layout_constraintLeft_creator="1"
app:layout_constraintLeft_toLeftOf="#+id/steakButton" />
</android.support.constraint.ConstraintLayout>
you can do this using TypesTask but you need to modify TypesTask class like below
public class TypesTask extends AsyncTask<String, Void, Void> {
#Override
protected void onPreExecute() {
myRef = FirebaseDatabase.getInstance().getReference();
}
#Override
protected Void doInBackground(String... params) {
typeFinder(params[0]);
return null;
}
#Override
onPostExecute(Void result){
String recipes = "";
for (int i = 0; i < recipesList.size(); i++) {
recipes = recipes + recipesList.get(i) + "\n";
}
testTextView.setText(recipes);
}
}
and your onClick should be like this
saladsB.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new TypesTask().execute("salad");
}
});
As mentioned in the comments both of the answers provided work. I either had to add the UI update to the typeFinder function itself, or use AsyncTask to update the UI inside onPostExecute method. For the latter I had to put the program to sleep for one second after the line typeFinder(params[0]) to give it enough time to update the variables.
Your method in which you are building the reciepeList is an asynchronous call. You need to update the changes to Ui after the OnSuccess() call of EventListener. Relocate the Ui updation code to OnDataChange See the code below :
private void typeFinder(String type) {
myRef.orderByChild("type").equalTo(type).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// This method is called once with the initial value and again
// whenever data at this location is updated.
String word = "";
boolean wordAdded = false;
String value = dataSnapshot.getValue().toString();
for (int i = 0; i < value.length(); i++) {
if (wordAdded == false) {
if (value.charAt(i) == '=') {
recipesList.add(word);
wordAdded = true;
word = "";
} else if (value.charAt(i) != '{' && value.charAt(i) != ',') {
if (word.length() == 0 && value.charAt(i) == ' ') {
} else {
word = word + value.charAt(i);
}
}
}
if (value.charAt(i) == '}')
if (i + 2 == value.length()) {
wordAdded = false;
break;
} else
wordAdded = false;
}
// Update the Ui Here
String recipes = "";
for (int i = 0; i < recipesList.size(); i++) {
recipes = recipes + recipesList.get(i) + "\n";
}
this.testTextView.setText(recipes);
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.w(TAG, "Failed to read value.", error.toException());
}
});
}
#Update
When i create new project everything its fine. But i don't know what is wrong. I just refactor all names with e-mail to login, change type of textview e-mail to normal.
I have problem with simple app. I made default loading activity. And change e-mail to login. So there will be login and password.
But app stop on device. There is error EGL_BAD_MATCH
Android monitor error
01-03 18:43:35.591 4738-4757/com.example.rachel.safemessenger E/EGL_emulation: tid 4757: eglSurfaceAttrib(1174): error 0x3009 (EGL_BAD_MATCH)
01-03 18:43:35.591 4738-4757/com.example.rachel.safemessenger W/OpenGLRenderer: Failed to set EGL_SWAP_BEHAVIOR on surface 0x923a4660, error=EGL_BAD_MATCH
Please help.
LoginActivity.java
package com.example.rachel.safemessenger;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.TargetApi;
import android.content.pm.PackageManager;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.inputmethod.EditorInfo;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import static android.Manifest.permission.READ_CONTACTS;
/**
* A login screen that offers login via email/password.
*/
public class LoginActivity extends AppCompatActivity implements LoaderCallbacks<Cursor>
{
/**
* Id to identity READ_CONTACTS permission request.
*/
private static final int REQUEST_READ_CONTACTS = 0;
/**
* A dummy authentication store containing known user names and passwords.
* TODO: remove after connecting to a real authentication system.
*/
private static final String[] DUMMY_CREDENTIALS = new String[]{
"foo#example.com:hello", "bar#example.com:world"
};
/**
* Keep track of the login task to ensure we can cancel it if requested.
*/
private UserLoginTask mAuthTask = null;
// UI references.
private AutoCompleteTextView mLoginView;
private EditText mPasswordView;
private View mProgressView;
private View mLoginFormView;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
// Set up the login form.
mLoginView = (AutoCompleteTextView) findViewById(R.id.activityLogin_login);
populateAutoComplete();
mPasswordView = (EditText) findViewById(R.id.activityLogin_password);
mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener()
{
#Override
public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent)
{
if (id == R.id.login || id == EditorInfo.IME_NULL)
{
attemptLogin();
return true;
}
return false;
}
});
Button mLoginSignInButton = (Button) findViewById(R.id.activityLogin_name_sign_in_button);
mLoginSignInButton.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View view)
{
attemptLogin();
}
});
mLoginFormView = findViewById(R.id.activityLogin_login_form);
mProgressView = findViewById(R.id.activityLogin_login_progress);
}
private void populateAutoComplete()
{
if (!mayRequestContacts())
{
return;
}
getLoaderManager().initLoader(0, null, this);
}
private boolean mayRequestContacts()
{
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
{
return true;
}
if (checkSelfPermission(READ_CONTACTS) == PackageManager.PERMISSION_GRANTED)
{
return true;
}
if (shouldShowRequestPermissionRationale(READ_CONTACTS))
{
Snackbar.make(mLoginView, R.string.permission_rationale, Snackbar.LENGTH_INDEFINITE)
.setAction(android.R.string.ok, new View.OnClickListener()
{
#Override
#TargetApi(Build.VERSION_CODES.M)
public void onClick(View v)
{
requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
}
});
} else
{
requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
}
return false;
}
/**
* Callback received when a permissions request has been completed.
*/
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions,
#NonNull int[] grantResults)
{
if (requestCode == REQUEST_READ_CONTACTS)
{
if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
{
populateAutoComplete();
}
}
}
/**
* Attempts to sign in or register the account specified by the login form.
* If there are form errors (invalid email, missing fields, etc.), the
* errors are presented and no actual login attempt is made.
*/
private void attemptLogin()
{
if (mAuthTask != null)
{
return;
}
// Reset errors.
mLoginView.setError(null);
mPasswordView.setError(null);
// Store values at the time of the login attempt.
String login = mLoginView.getText().toString();
String password = mPasswordView.getText().toString();
boolean cancel = false;
View focusView = null;
// Check for a valid password, if the user entered one.
if (!TextUtils.isEmpty(password) && !isPasswordValid(password))
{
mPasswordView.setError(getString(R.string.error_invalid_password));
focusView = mPasswordView;
cancel = true;
}
// Check for a valid login address.
if (TextUtils.isEmpty(login))
{
mLoginView.setError(getString(R.string.error_field_required));
focusView = mLoginView;
cancel = true;
} else if (!isLoginValid(login))
{
mLoginView.setError(getString(R.string.error_invalid_login));
focusView = mLoginView;
cancel = true;
}
if (cancel)
{
// There was an error; don't attempt login and focus the first
// form field with an error.
focusView.requestFocus();
} else
{
// Show a progress spinner, and kick off a background task to
// perform the user login attempt.
showProgress(true);
mAuthTask = new UserLoginTask(login, password);
mAuthTask.execute((Void) null);
}
}
private boolean isLoginValid(String login)
{
//TODO: Replace this with your own logic
return login.contains("#");
}
private boolean isPasswordValid(String password)
{
//TODO: Replace this with your own logic
return password.length() > 4;
}
/**
* Shows the progress UI and hides the login form.
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
private void showProgress(final boolean show)
{
// On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
// for very easy animations. If available, use these APIs to fade-in
// the progress spinner.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2)
{
int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
mLoginFormView.animate().setDuration(shortAnimTime).alpha(
show ? 0 : 1).setListener(new AnimatorListenerAdapter()
{
#Override
public void onAnimationEnd(Animator animation)
{
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
}
});
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
mProgressView.animate().setDuration(shortAnimTime).alpha(
show ? 1 : 0).setListener(new AnimatorListenerAdapter()
{
#Override
public void onAnimationEnd(Animator animation)
{
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
}
});
} else
{
// The ViewPropertyAnimator APIs are not available, so simply show
// and hide the relevant UI components.
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
}
}
#Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle)
{
return new CursorLoader(this,
// Retrieve data rows for the device user's 'profile' contact.
Uri.withAppendedPath(ContactsContract.Profile.CONTENT_URI,
ContactsContract.Contacts.Data.CONTENT_DIRECTORY), ProfileQuery.PROJECTION,
// Select only email addresses.
ContactsContract.Contacts.Data.MIMETYPE +
" = ?", new String[]{ContactsContract.CommonDataKinds.Email
.CONTENT_ITEM_TYPE},
// Show primary email addresses first. Note that there won't be
// a primary email address if the user hasn't specified one.
ContactsContract.Contacts.Data.IS_PRIMARY + " DESC");
}
#Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor)
{
List<String> logins = new ArrayList<>();
cursor.moveToFirst();
while (!cursor.isAfterLast())
{
logins.add(cursor.getString(ProfileQuery.ADDRESS));
cursor.moveToNext();
}
addLoginsToAutoComplete(logins);
}
#Override
public void onLoaderReset(Loader<Cursor> cursorLoader)
{
}
private void addLoginsToAutoComplete(List<String> loginAddressCollection)
{
//Create adapter to tell the AutoCompleteTextView what to show in its dropdown list.
ArrayAdapter<String> adapter =
new ArrayAdapter<>(LoginActivity.this,
android.R.layout.simple_dropdown_item_1line, loginAddressCollection);
mLoginView.setAdapter(adapter);
}
private interface ProfileQuery
{
String[] PROJECTION = {
ContactsContract.CommonDataKinds.Email.ADDRESS,
ContactsContract.CommonDataKinds.Email.IS_PRIMARY,
};
int ADDRESS = 0;
int IS_PRIMARY = 1;
}
/**
* Represents an asynchronous login/registration task used to authenticate
* the user.
*/
public class UserLoginTask extends AsyncTask<Void, Void, Boolean>
{
private final String mLogin;
private final String mPassword;
UserLoginTask(String login, String password)
{
mLogin = login;
mPassword = password;
}
#Override
protected Boolean doInBackground(Void... params)
{
// TODO: attempt authentication against a network service.
try
{
// Simulate network access.
Thread.sleep(2000);
} catch (InterruptedException e)
{
return false;
}
for (String credential : DUMMY_CREDENTIALS)
{
String[] pieces = credential.split(":");
if (pieces[0].equals(mLogin))
{
// Account exists, return true if the password matches.
return pieces[1].equals(mPassword);
}
}
// TODO: register the new account here.
return true;
}
#Override
protected void onPostExecute(final Boolean success)
{
mAuthTask = null;
showProgress(false);
if (success)
{
finish();
} else
{
mPasswordView.setError(getString(R.string.error_incorrect_password));
mPasswordView.requestFocus();
}
}
#Override
protected void onCancelled()
{
mAuthTask = null;
showProgress(false);
}
}
}
activity_login.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.example.rachel.safemessenger.LoginActivity">
<!-- Login progress -->
<ProgressBar
android:id="#+id/activityLogin_login_progress"
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:visibility="gone" />
<ScrollView
android:id="#+id/activityLogin_login_form"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/activityLogin_name_login_form"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<AutoCompleteTextView
android:id="#+id/activityLogin_login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/prompt_email"
android:maxLines="1"
android:singleLine="true" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="#+id/activityLogin_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/prompt_password"
android:imeActionId="#+id/login"
android:imeActionLabel="#string/action_sign_in_short"
android:imeOptions="actionUnspecified"
android:inputType="textPassword"
android:maxLines="1"
android:singleLine="true" />
</android.support.design.widget.TextInputLayout>
<Button
android:id="#+id/activityLogin_name_sign_in_button"
style="?android:textAppearanceSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="#string/action_sign_in"
android:textStyle="bold" />
</LinearLayout>
</ScrollView>
</LinearLayout>
strings.xml
<resources>
<string name="app_name">SafeMessenger</string>
<!-- Strings related to login -->
<string name="prompt_email">Nick</string>
<string name="prompt_password">Password </string>
<string name="action_sign_in">Sign in or register</string>
<string name="action_sign_in_short">Sign in</string>
<string name="error_invalid_login">This login is invalid</string>
<string name="error_invalid_password">This password is too short</string>
<string name="error_incorrect_password">This password is incorrect</string>
<string name="error_field_required">This field is required</string>
<string name="permission_rationale">"Contacts permissions are needed for providing email
completions."
</string>
</resources>
ok, now it works. I think somehow to correct without my participation.
I update android devices and reset computer and now it works.