Observable DataBinding ObservableInt vs. LiveData with different results On Confguration change - java

I am testing the behavior of DataBinding observable when it comes to use a LiveData vs. ObservableInt.
I have simple layout with a button that triggers a counter for both LiveData & ObservableInt variables that I store in the ViewModel, I update their values using BindingAdapter
Both LiveData & ObservableInt variables count up normally; but when there is a device configuration change (screen rotation for my test), the ObservableInt countinues count up with button hits, although the LiveData dismisses one or two counts.
Below gif will illustrate more
My question is how to solve this problem?
I mainly need a LiveData for further Transformations
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">
<data>
<variable
name="viewmodel"
type="com.example.android.databindingobservableintlivedata.MyViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
<TextView
android:id="#+id/observableint_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ObservableInt: " />
<TextView
android:id="#+id/observableint_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
app:textValueForObservableInt="#{viewmodel.countObservableInt}" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center">
<TextView
android:id="#+id/livedata_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="LiveData: " />
<TextView
android:id="#+id/livedata_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
app:textValueForLiveData="#{viewmodel.countLiveData}" />
</LinearLayout>
<Button
android:id="#+id/btn_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="16dp"
android:onClick="#{() -> viewmodel.onCount()}"
android:text="Count" />
</LinearLayout>
</layout>
Activity
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
MyViewModel viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
mBinding.setViewmodel(viewModel);
mBinding.setLifecycleOwner(this);
}
}
ViewModel
public class MyViewModel extends ViewModel {
public MutableLiveData<Integer> countLiveData = new MutableLiveData<>(0);
public ObservableInt countObservableInt = new ObservableInt(0);
public void onCount() {
countObservableInt.set(countObservableInt.get() + 1);
int value = countLiveData.getValue() == null ? 0 : countLiveData.getValue();
countLiveData.postValue(value + 1);
}
}
BindingAdapters
public class BindingAdapters {
#BindingAdapter("textValueForObservableInt")
public static void bindObservableIntInText(TextView text, ObservableInt value) {
text.setText(String.valueOf(value.get()));
}
#BindingAdapter("textValueForLiveData")
public static void bindLiveDataIntegerInText(TextView text, MutableLiveData<Integer> value) {
text.setText(String.valueOf(value.getValue()));
}
}

Post value of LiveData:
Basically this method indicates that, any value given to LiveData can be/should be called from background thread (other than main thread) would reflect on main thread with updated value.
Meaning that, if you've got two consecutive calls to LiveData about postValue() then only last value would be dispatched!
In your case, countLiveData.postValue(value + 1) this line gets impacted on post-increment of value if there're too frequent calls to this method, which in case only gets updated for last value but not on consecutive ones.
Set Value of LiveData:
This method requires that call must be made from Main thread, resulting UI gets reflected/updated every time no matter how many calls you've made. None of intermediate calls get discarded.
TL;DR
If you've to update/set value from background thread then use postValue() method otherwise use setValue() when on Main thread.
It takes a while for device rotation when I have continuous hits on the button, and suddenly rotate the device.
Reason is that when you call setValue() on main thread before rotating device, each calls must update the UI consecutively, resulting delay on rotation stuff (Holds the UI updates before configuration change happen). That's why it lags/delay on rotation before all setValue() call completes UI updates (this line in your particular case: app:textValueForLiveData="#{viewmodel.countLiveData}").

Related

How to add a badge above a button?

In my MainActivity class, I have this button:
<Button
android:id="#+id/target"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/speak"
android:layout_marginTop="20dp"
android:background="#drawable/button_red"
android:text="#string/target" />
I now want to add a badge with the number 1, using Material Design (see the documentation).
This is how I tried:
public void setBadge() {
BadgeDrawable badgeDrawable = BadgeDrawable.create(MainActivity.this);
badgeDrawable.setNumber(1);
BadgeUtils.attachBadgeDrawable(badgeDrawable, findViewById(R.id.target));
}
but what I get is the error
'attachBadgeDrawable(com.google.android.material.badge.BadgeDrawable, android.view.View, android.widget.FrameLayout)' in 'com.google.android.material.badge.BadgeUtils' cannot be applied to '(com.google.android.material.badge.BadgeDrawable, android.view.View)'
If you tried this on a device with <18 API this might work;
In your XML wrap the button with a FrameLayout;
<FrameLayout
android:id="#+id/frame"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="HELLO"/>
</FrameLayout>
In your Activity;
//I've used post to eliminate race condition between the button and its badge.
button.post(() -> {
BadgeDrawable badgeDrawable = BadgeDrawable.create(MainActivity.this);
badgeDrawable.setNumber(1);
//Note that there is a third argument which is our FrameLayout
BadgeUtils.attachBadgeDrawable(badgeDrawable, findViewById(R.id.button), findViewById(R.id.frame));
});

How can I save and restore the last Image View seen by the user?

I am currently developing an android music reading app in Android Studio. The language I am using is Java but I am a beginner (sorry for my English too).
The app has several exercises. Ideally, people can click on the next or back button to see one exercise or another. The problem is that I am also looking for the user, even if he exits the application, to continue in the last exercise (image) seen.
I have read about the cycle of activities and I understand it, but since I am a beginner in the language I cannot do what I need to do. I have learned that OnSaveInstanceState or OnRestoreInstanceState do not solve my problem and that the solution may be by using SharedPreferences but I don't know how to apply it to the code I currently have. With SharedPreferences I hope I can save and restore the last imageview seen and that I can continue from there by clicking next or back.
This is the current code and it allows me to: show the initial exercise and go from one exercise to another.
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.View;
import android.widget.ImageView;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private int image_index = 0 ;
private static final int MAX_IMAGE_COUNT = 3;
private int[] mImageIds = {
R.raw.image1,
R.raw.image2,
R.raw.image3};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
showImage();
}
private void showImage() {
ImageView imgView = (ImageView) findViewById(R.id.myimage);
imgView.setImageResource(mImageIds[image_index]);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case (R.id.previous_btn):
image_index--;
if (image_index == -1) {
image_index = MAX_IMAGE_COUNT - 1;
} else {
}
showImage();
break;
case (R.id.next_btn):
image_index++;
if (image_index == MAX_IMAGE_COUNT) {
image_index = 0;
} else {
}
showImage();
break;
}
}
}
This is the xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView 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"
android:background="#android:color/background_light"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:fontFamily="#font/gilroyextrabold"
android:text="Ejercicios"
android:textColor="#android:color/black"
android:textSize="24sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="#+id/myimage"
android:layout_width="wrap_content"
android:layout_height="370dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textView" />
<LinearLayout
android:id="#+id/linearLayout5"
android:layout_width="match_parent"
android:layout_height="54dp"
android:layout_marginStart="10dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="40dp"
android:layout_marginEnd="10dp"
android:layout_marginRight="10dp"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/myimage">
<Button
android:id="#+id/previous_btn"
android:layout_width="190dip"
android:layout_height="wrap_content"
android:background="#drawable/btnatsslf"
android:onClick="onClick" />
<Button
android:id="#+id/next_btn"
android:layout_width="190dip"
android:layout_height="wrap_content"
android:background="#drawable/btnsgtslf"
android:onClick="onClick" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
</ScrollView>
As I don't have that much knowledge, I seek your help and I also receive alternatives.
put these lines after setContentView, but before showImage in onCreate
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
image_index = sp.getInt("image_index", image_index);
and save this value inside showImage just after setImageResource line
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
sp.edit().putInt("image_index", image_index).apply();
you may keep reference to SharedPreferences sp as class member, so it won't be needed to obtain every time when showImage is called (also ImageView should be stored same way without need of findViewById everytime). also the key ("image_index") may be stored as some private static final String class member
also remember for future use: this is index in some array you have declared static. when you change it, e.g. stored value is 2 and you cut last item in images array then user get index out of bounds exception after app update installation, so inside onCreate check that this value is in range of array (just for safety)

ViewHolder views flash/blink OnBind

Issue
Every time I call the OnBind() method inside my holders, views within them will flash or blink or maybe even fade.
I'm just pretty lost as to why, I've tried a number of things.
Changing them to have null as a background or have them all be a solid color.
Making sure nothing is gone at any point.
Removed any animations.
Asked Google a thousand times, a thousand ways.
Searched on here.
Thoughts
I've always thought that I would have to eventually try and hide it with animations and styling. Seeing it as just a side effect of the binding.
This is part of a larger project, obviously. So I still have to do all the animations, that's why I haven't done it for this yet. Figured I'd just ask and see if anyone could help find the solution another way in the meantime.
Any help, tips or advice would be great. Hopefully the code links work and are build able for everyone.
Thanks,
Jon.
Code
I'm not sure how much code I need to add in here, so I'll go small at first. If more should be added please let me know and I will. However I put it all on Github and Dropbox(Example Apk & Zip).
Links are at the bottom.
HeaderHolder.java
public class HeaderHolder extends BaseHolder {
#Bind(R.id.header_title_text)
TextView _titleTextView;
#Bind(R.id.header_status_image)
ImageView _statusImageView;
#BindDrawable(R.drawable.ic_selected)
Drawable _statusSelected;
#BindDrawable(R.drawable.ic_non_selected)
Drawable _statusNonselected;
private Header _header;
public HeaderHolder(View root, HolderCallBacks callbacks) {
super(null, root, callbacks);
}
#Override
public void OnBind(Base model) {
this._header = (Header) model;
String n = model._name();
this._titleTextView.setText(n);
this._statusImageView.setImageDrawable(this._header._iconset()._selected()
? this._statusSelected : this._statusNonselected);
}
#OnClick(R.id.header_item_wrapper)
public void _headerClick(View view) {
this._callbacks.OnHolderClick(view, this._header);
}
}
IconsetHolder.java
public class IconsetHolder extends BaseHolder {
#Bind(R.id.iconset_icon_recycler)
RecyclerView _iconsRecycler;
private AdapterCallBacks _adapterCallbacks;
public IconsetHolder(Context context, View root, AdapterCallBacks callbacks) {
super(context, root, null);
this._adapterCallbacks = callbacks;
}
#Override
public void OnBind(Base model) {
Iconset i = (Iconset) model;
this._iconsRecycler.setLayoutManager(new GridLayoutManager(
this._context, i._span(), GridLayoutManager.HORIZONTAL, false));
this._iconsRecycler.setAdapter(new ModelsAdapter(i._icons(), this._adapterCallbacks));
}
}
item_header.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/header_item_wrapper"
android:layout_width="wrap_content"
android:layout_height="56dip"
android:background="#595959"
tools:context=".views.adapters.holders.HeaderHolder">
<TextView
android:id="#+id/header_title_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="16dp"
android:textColor="#fff8f8f8"
android:gravity="center_vertical"
android:text="ICONSET"
android:textSize="24sp"
android:layout_centerVertical="true" />
<ImageView
android:id="#+id/header_status_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="12dp"
android:gravity="center_vertical"
android:layout_alignParentRight="true"
android:layout_centerVertical="true" />
</RelativeLayout>
item_iconset.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/iconset_item_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#null"
tools:context=".views.adapters.holders.IconsetHolder">
<android.support.v7.widget.RecyclerView
android:id="#+id/iconset_icon_recycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:background="#595959"
android:layout_marginBottom="16dp"
/>
</RelativeLayout>
Example Links Removed
RecyclerView has some built in animations to it, using the DefaultItemAnimator. Specifically when you call notifiyItemChanged() it does a fade animation for the changing of the data in the ViewHolder. If you would like to disable this you can use the following:
RecyclerView.ItemAnimator animator = recyclerView.getItemAnimator(); // your recycler view here
if (animator instanceof DefaultItemAnimator) {
((DefaultItemAnimator) animator).setSupportsChangeAnimations(false);
}
This will disable the item changed animation (the fade you are seeing).

Dynamic list of checkboxes with onclick functions

I have a page that returns a list of items backs from a database. I want to add each item to my android fragment as a checkbox dynamically with an onClick, that can tell if an item is being checked or un-checked.
How can I add checkboxes dynamically with on-clicks and different titles for each?
Below is the xml I am inserting the checkboxes into:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="#e5e5e5"
android:layout_height="match_parent" >
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="6dp"
android:layout_marginRight="6dp"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:orientation="vertical"
android:background="#drawable/bg_card">
<!-- Card Contents go here -->
<TextView
android:id="#+id/styleDescription"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:ems="10"
android:textSize="15sp"
android:padding="5dip"
></TextView>
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New CheckBox"
android:id="#+id/checkBox" />
</LinearLayout >
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="6dp"
android:layout_marginRight="6dp"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:orientation="horizontal"
android:background="#drawable/bg_card">
<!-- Card Contents go here -->
<Button
android:id="#+id/buttonAddList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Create List"
style="?android:attr/borderlessButtonStyle"
android:textColor="#color/orange"
android:textStyle="bold"
/>
</LinearLayout >
</FrameLayout>
</LinearLayout>
</ScrollView>
I currently have one checkbox in the above code. I plan on removing this. That checkbox is just to show where I want my check boxes to show up.
What you need to do first is add an id to your LinearLayout (in that XML file), the one which is going to hold the CheckBoxes. Then, in the code you need to get that LinearLayout by its id and use addView() to add CheckBoxes that you create dynamically. I imagine in pseudocode it'd look like this:
for (int i = 0; i < numberOfCheckBoxes; i++) {
CheckBox checkBox = new CheckBox();
checkBox.setTitle("Your title");
checkBox.setOnClickListener(new OnClickListener() {
// Your code to be executed on click
});
linearLayout.addView(checkBox);
}
Does this help?
PS: It'd be nice if you kept your code clean - ADT (and I believe Eclipse too) gives you the Shift+Ctrl+F shortcut to indent your code automatically - use it as often as possible ;)
Since you are processing database items, I suggest using a CursorAdapter to do the heavy work for you. A CursorAdapter, like any of the Adapter classes can process the database items and custom-fit them into a layout of your choice, to use in a ListView.
You have to make adjustments to your code:
Create a layout file that contains whatever you want to put in the dynamic list. This is an example, say it's named list_contents.xml:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="6dp"
android:layout_marginRight="6dp"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:orientation="vertical"
android:background="#drawable/bg_card">
<!-- Card Contents go here -->
<TextView
android:id="#+id/styleDescription"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:ems="10"
android:textSize="15sp"
android:padding="5dip"
></TextView>
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New CheckBox"
android:id="#+id/checkBox" />
</LinearLayout >
</FrameLayout>
Then, instead of returning a List from your AsyncTask, return the Cursor itself
from your database. This Cursor will be processed by CursorAdapter. I recommend this guide:
http://www.gustekdev.com/2013/05/custom-cursoradapter-and-why-not-use.html
Implement the CursorAdapter methods:
In your implementation of newView(), inflate list_contents.xml (Note that if you use ResourceCursorAdapter you wouldn't need to do this)
In your implementation of CursorAdapter.bindView() do this:
CheckBox checkbox = (CheckBox) view.findViewById(R.id.checkbox);
checkbox.setText(cursor.getString(cursor.getColumnIndex(YOUR_DATABASE_COLUMN_NAME_FOR_CHECKBOX_VALUES)));
checkbox.setOnCheckedChangedListener(listenerInitializedSomewhereFromFragmentCode);
Change your ScrollView to a ListView (it can be inside any Layout), and give it an id, say R.id.listview.
Finally, in the part where you process the List from the database, where we now have a Cursor instead, just do this:
CustomCursorAdapter cca = new CustomCursorAdapter(getActivity(), resultFromDatabase, 0);
listView.setAdapter(cca);
Note: getActivity() is for when you are working inside a Fragment. It should be a context, so inside an Activity it can just be "this".
Note2: listView should have been initialized at this point via findViewById.
Note3: If listView already has an Adapter and Cursor set, you should consider calling listView.getAdapter().changeCursor() instead.
Simple Code In Kotlin
fun createCheckbox() {
var arr_cb = arrayOfNulls<CheckBox>(checkbox_size)
val layout = findViewById<View>(R.id.layout_checkbox) as ViewGroup
val ll = LinearLayout(this)
ll.orientation = LinearLayout.VERTICAL
for (i in 0 until arr_cb.size) {
arr_cb[i] = CheckBox(this)
arr_cb[i]?.text = health_status.get(i).toString()
arr_cb[i]?.setPadding(25, 0, 0, 0)
arr_cb[i]?.id = i
arr_cb[i]?.tag = health_status[i]
arr_cb[i]?.setTextColor(resources.getColor(R.color.title_color))
arr_cb[i]?.setOnCheckedChangeListener(
arr_cb[i]?.let {
handleCheck(it)
})
arr_cb[i]?.buttonTintList =
ColorStateList.valueOf(resources.getColor(R.color.theme_color))
ll.addView(arr_cb[i])
}
layout.addView(ll)
}
handleCheck method
private fun handleCheck(chk: CheckBox): CompoundButton.OnCheckedChangeListener? {
return object : CompoundButton.OnCheckedChangeListener {
override fun onCheckedChanged(buttonView: CompoundButton?, isChecked: Boolean) {
if (!isChecked) {
//uncheck
} else {
//check
}
}
}
}
and you want to do something use direct checkboxList object like as
val layout = findViewById<View>(R.id.layout_checkbox) as ViewGroup
val ll = LinearLayout(this#MedicalHistoryActivity)
ll.orientation = LinearLayout.VERTICAL
for (i in 0 until health_status.size) {
arr_cb[i]?.isEnabled = true
// do something like change color or more
}
layout.addView(ll)
for enable checkbox or more.
Thank you

How to transfer data between views?

I am just starting writing Android apps. I have done some beginner's tutorials, but I'm having trouble with the next step for which I could not find any helpful answer.
I want to write an app that computes the value of a complex function which depends on a three parameters. This works if I put everything on a single view:
For each parameter one TextField (with the parameter name) plus one EditText field to enter the value. At the bottom there is one Button, and when this is clicked, the result is displayed in another TextField.
But now I want improve the layout (plus I want to learn how to deal with more complex structures):
Two of the parameters are usually just set once and then kept at their values. So I decided to move these two parameters to a different view.
No I'm looking for recommendations (and hopefully links example code):
Which structure should I use? It seems that I do not need to use different activities, but one activity with different views should do the job.
ViewSwitcher sounds reasonable, since I only require two different views in this case. On the other hand ViewFlipper may be preferable, since I can reuse this later for other projects with multiple views. I also read that ViewPager allows to swipe between different views.
How can I read an EditField if this is on a different view?
I tried to use ViewSwitcher, and it worked when I added an additional button to switch to a second view. But when I moved the TextField and EditField for parameters one and two
to the second view, the app does not run on the emulator, just stating "error in app" (while Eclipse shows no errors). From this, I guess that I have to do some additional work to pass data in EditText between different views.
I have not found any examples for this - can anybody give me some advice/examples?
Any help is appreciated
I figured that my initial description was maybe not too helpful without any code.
Here is my layout
<?xml version="1.0" encoding="utf-8"?>
<ViewSwitcher xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/viewSwitcher1"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView android:id="#+id/pg1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1st view" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView android:id="#+id/v1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="value1" />
<EditText android:id="#+id/val1"
android:text="2.0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="numberDecimal" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView android:id="#+id/v2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="value2" />
<EditText android:id="#+id/val2"
android:text="3.0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="numberDecimal" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<Button android:layout_width="wrap_content"
android:id="#+id/calc"
android:layout_height="wrap_content"
android:text="2*Val1 + Val2 =" />
<TextView android:id="#+id/res"
android:text=""
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<Button android:id="#+id/b1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="switch view 1" />
</LinearLayout>
</LinearLayout>
<!-- next view -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView android:id="#+id/pg2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="View 2" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<Button android:id="#+id/b2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="switch view 2" />
</LinearLayout>
</LinearLayout>
</ViewSwitcher>
and here is my main activity:
package com.example.testas2;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.ViewSwitcher;
public class MainActivity extends Activity {
ViewSwitcher switcher;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
switcher = (ViewSwitcher)findViewById(R.id.viewSwitcher1);
initControls();
}
private void initControls()
{
Button calculate=(Button)findViewById(R.id.calc);
calculate.setOnClickListener(new Button.OnClickListener()
{public void onClick (View v) { calculate(); }});
Button b1=(Button)findViewById(R.id.b1);
b1.setOnClickListener(new Button.OnClickListener()
{public void onClick (View v) { switcher.showNext(); }});
Button b2=(Button)findViewById(R.id.b2);
b2.setOnClickListener(new Button.OnClickListener()
{public void onClick (View v) { switcher.showPrevious(); }});
calculate();
}
private void calculate()
{
EditText val1=(EditText)findViewById(R.id.val1);
EditText val2=(EditText)findViewById(R.id.val2);
TextView res=(TextView)findViewById(R.id.res);
Double Val1=Double.parseDouble(val1.getText().toString());
Double Val2=Double.parseDouble(val2.getText().toString());
Double result = 2*Val1+Val2;
res.setText( String.format( "%.3f", result ) );
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
This version is working:
- when pushing the first button, it computes: result = 2 * value1 + value2)
- when pushing the button "switch view 1", it goes to the second view
- on the second view, when pushing the button "switch view 2", it goes back to view 1
But I can't get the following two pieces to work:
1) I would like to move the "switch view 1" button to the top of the first view, but this gives an error in the emulator ("Unfortunately testas2 has stopped").
2) I would like to move the input of the second value to the second view, but this gives the same error in the emulator.
What am I doing wrong?
Why does the order of the elements in the layout matter, and how can I modify my code to make it work?
Example code -
TextView tField= (add cast here)findViewById(R.id.editText)
tfield.getText();
The above answer can be improved if you post some code of yours because findViewById at times depends on the container view and the above code will not work then as it will look for the textfield in the default view.
I just did "Project > Clean", restarted the app in the emulator, and now it works!
In other words, the solution for the original question is trivial (in fact there was no real problem). One can simply move elements in the layout file (TextView, EditText, Button) within a view or between views. The posted activity works always and the data (from the different TextView and EditView fields) is accessible everywhere in the code. Therefore, no explicit "transfer" of data between views is required.
Only after moving elements in the layout file one should do "Project > Clean".
In your current Activity, create a new Intent:
Intent i = new Intent(getApplicationContext(), NewActivity.class);
i.putExtra("new_variable_name","value");
startActivity(i);
Then in the new Activity, retrieve those values:
Bundle extras = getIntent().getExtras();
if (extras != null) {
String value = extras.getString("new_variable_name");
}
For more info follow this link

Categories