Contents of textView change when contents are selectable - android

I am currently working on a project which requires me to dynamically add textView objects to a LinearLayout based on the contents of an array.
chapter = Home.chapters.get(index);
layout.removeAllViews();
String dataText = chapter.content;
String[] dataArray = dataText.split("~");
for (int i = 0; i < dataArray.length; i++) {
String paragraph = dataArray[i];
String outputParagraph = paragraph.replace("`", "\n");
View view = getLayoutInflater().inflate(R.layout.ttc_text, null);
final TextView tv = (TextView) view.findViewById(R.id.textView);
tv.setText(outputParagraph);
//tv.setTextIsSelectable(true);
layout.addView(view);
}
TextView titleView = (TextView) findViewById(R.id.title);
titleView.setText("Chapter " + chapter.title);
layout.setOnTouchListener(new OnSwipeTouchListener(getBaseContext()) {
public void onSwipeRight() {
retreatBackward();
}
public void onSwipeLeft() {
advanceForward();
}
});
I have configured saveOnItemStateChanged in order to restore the correct contents of the textViews when the screen is rotated.
if (savedInstanceState != null) {
index = savedInstanceState.getInt("Chapter");
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putInt("Chapter", index);
super.onSaveInstanceState(savedInstanceState);
}
However, whenever the screen is rotated, the textViews present within the parent layout do not display their original contents. Instead, the same number of textViews in the original layout all display identical contents, that is, the contents of the final textView added to the layout.
This issue only presents when the text within the TextViews is designated as selectable, either through the setTextIsSelectable() function or through the XML markup. As such, the selectability of the text must be somewhat impacting the way in which the contents of the TextViews are repopulated after a rotation, although I cannot seem to establish exactly why. Any assistance would be much appreciated.

I think the problem is due to your device's configuration change. When you rotate your device a configuration change event occur. Add the following code to your Manifest.xml and your activity class. Hope, that will solve your problem.
Changes to Manifest.xml file ---> (Suppose XYZ is your activity class)
<activity android:name=".activities.XYZ"
android:configChanges="orientation|screenSize"/>
Add this to your XYZ activity class --->
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}

1st
super.onSavedInstanceState(...) should be the first thing called. Your 'save' stuff should come after.
2nd
You will most likely need to save all of the textviews, so you can repopulate them, or save the array and repopulate based on that.
I found this site to be very good for explaining the ins and out of save-instance-state handling.
http://www.intertech.com/Blog/saving-and-retrieving-android-instance-state-part-1/

Related

Radio Buttons in ListView recycling and causing issues

So I have a listview that is built to have each view in the list to have 2 radio buttons. The problem is when the list gets longer than the page the list starts to recycle the views and it also takes along the checked radio buttons. I understand what is causing the problem but I don't really know how to solve this issue and the answers I've looked up online aren't really helping. My problem is a bit unique because I'm using Parse with my adapter so looking up solutions specifically for parse is pretty hard.
Here is my code for my adapter:
// Set up a customized query
ParseQueryAdapter.QueryFactory<AnywallPost> factory =
new ParseQueryAdapter.QueryFactory<AnywallPost>() {
public ParseQuery<AnywallPost> create() {
Location myLoc = (currentLocation == null) ? lastLocation : currentLocation;
ParseQuery<AnywallPost> query = AnywallPost.getQuery();
query.include("user");
query.orderByDescending("PostScore");
query.whereWithinKilometers("location", geoPointFromLocation(myLoc), radius
* METERS_PER_FEET / METERS_PER_KILOMETER);
query.setLimit(MAX_POST_SEARCH_RESULTS);
return query;
}
};
// Set up the query adapter
postsQueryAdapter = new ParseQueryAdapter<AnywallPost>(this, factory) {
#Override
public View getItemView(AnywallPost post, View view, ViewGroup parent) {
if (view == null) {
view = View.inflate(getContext(), R.layout.anywall_post_item, null);
}
//TextView DetailsView = (TextView) view.findViewById(R.id.content_view);
TextView contentView = (TextView) view.findViewById(R.id.content_view);
TextView usernameView = (TextView) view.findViewById(R.id.username_view);
TextView postscoreView = (TextView) view.findViewById(R.id.PostScore);
RadioButton upvote = (RadioButton) view.findViewById(R.id.Upvote);
RadioButton downvote = (RadioButton) view.findViewById(R.id.DownVote);
//DetailsView.setText(post.getDetails());
contentView.setText(post.getText());
usernameView.setText(post.getUser().getUsername());
postscoreView.setText(post.getInt().toString());
upvote.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
post.increment("PostScore", 1);
post.saveInBackground();
}
});
downvote.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//post.decrement();
}
});
return view;
}
};
postsQueryAdapter.setAutoload(false);
postsQueryAdapter.setPaginationEnabled(false);
// Attach the query adapter to the view
ListView postsListView = (ListView) findViewById(R.id.posts_listview);
postsListView.setAdapter(postsQueryAdapter);
So I need these two radio buttons to stay with the post made the entire time but I am still a beginner so I'm not entirely sure how I would go about that. Could anyone provide a solution and explain how it worked? If you need anymore code just let me know. Thank you for you time.
Essentially when you get a new cell, be sure to clear both the radio buttons, then re-check them only if it meets your condition for it to be checked (likely checking the count on the post object). Hard to tell exactly how this will look without knowing more about how you are storing data, but I'd guess something like this:
upvote.setChecked(post.getInt() > 0);
downvote.setChecked(post.getInt() < 0);
Along with the list items I'd carry a list with the state of radio buttons.
So even when the views get recycled you use your own state to check the correct radio button.
A good choice would be a list of Boolean (the boolean wrapper). Where you could keep true for upvote, false for downvote and null for neither.

Auto-scrolling textview in Android

I've tried a lot of different ways, most of the suggestions found here, but none of them seems to work. What I'm trying to achieve is at chat area below my game area, a SurfaceView. It is supposed to scroll upwards as new lines are added to the textview.
At first, it looks like a really simple task, but having tried all kinds of suggestions, like a TextView in a ScrollView, like a TextView in a TableRow in a TableLayout in a ScrollView, and so on...I've still not made it happen. Of course this must be something easily achieved in Android, right??
The task is to display like 6 lines of text in the bottom of the screen, and as a new message is added last it should scroll the rest upwards, like a terminal window. The important thing is that it should add the latest message after the other and, when reached the bottom line, scroll the text upwards and add the new line(s) at the end.
Any kind of help or suggestions would be highly appreciated!!
I needed the same behavior in one of my apps and I achieved in just with one command:
view.setGravity(Gravity.BOTTOM);
Or, analogously, setting this attribute in your layout:
android:gravity="bottom"
Then simply add your lines using:
your_text_view.append(newLine);
Suppose, you declared your ScrollView as follows...
private ScrollView mScrollView;
you initialized it as...
mScrollView = (ScrollView) findViewById(R.id.scroll_view_chat_window);
Now, create a method to perform scroll down when you call the method. Inside the method implement a thread which will do the scroll down independently. And call the method after every chat message update thats will do the auto-srcoll functionality.
private void scrollDown() {
mScrollView.post(new Runnable() {
#Override
public void run() {
mScrollView.smoothScrollTo(mScrollView.getScrollY(), mScrollView.getScrollY()
+ mScrollView.getHeight());
}
});
}
I've achieved this (crudely!) by maintaining my own list, deleting the lowest element then adding at the end each time. Here i've just got a 3 line window:
public class MessageWindow {
private ArrayList <String> msgs;
private Activity parentActivity;
public MessageWindow(Activity act, int allMsgsMax) {
this.parentActivity = act;
msgs = new ArrayList <String> ();
// create empty list elements for initial display
for (int i = 0; i < allMsgsMax; i++){
msgs.add("");
}
}
//
public void put (String msg){
msgs.remove(0);
msgs.add(msg);
// get a handle to the textview 'messages', a 3-line box
TextView t2v = (TextView) parentActivity.findViewById(R.id.messages);
// crappy but you get the idea:
t2v.setText(msgs.get(0) + "\n" + msgs.get(1) + "\n" + msgs.get(2) );
}
then in the activity:
protected MessageWindow messageWindow;
// setup splash screen
messageWindow = new MessageWindow(this, 3);
// write some stuff - row1 will disappear off the top of the box
messageWindow.put ("row1")
messageWindow.put ("row2")
messageWindow.put ("row3")
messageWindow.put ("row4")

Android check boxes change text when switched to landscape

I have a view in android that shows a number of check boxes. They are all added dynamically and I set a text for each one in part.
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LinearLayout layout = (LinearLayout) findViewById(R.id.layout);
LayoutInflater inflater = getLayoutInflater();
for (String string : getResources().getStringArray(R.array.string_array)) {
LinearLayout searchField = (LinearLayout) inflater.inflate(R.layout.cb, null);
CheckBox checkBox = (CheckBox) searchField.findViewById(R.id.checkBox1);
checkBox.setText(string);
layout.addView(searchField, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
}
}
}
AS you can see from the code, I have an array of strings and for each of the strings in the array I add an check box. When the view is first shown, all the check boxes have the correct text, but after I rotate the device to landscape or portrait mode, all the check boxes have the same text (from the last check box). Any rotations (to redraw the screen) do not affect the text anymore. All of them remain with the text of the last check box.
I have looked in the debugger, the check box object is a new one for each string, so I am not working with the same instance of an object. I am currently out of ideas.
Do you have any idea why this is happening?
When you rotate the screen, runtime Resource is changed, and Activity is relaunched. Two ways to fix your problem:
Hold the value of all your checkbox in OnCheckedChangeListener and reset them back in onResume.
Handle onConfigurationChanged by yourself, according to https://developer.android.com/guide/topics/resources/runtime-changes.html#HandlingTheChange

CheckBoxes in ListView disappear when the screen rotates

What my application first does is it loads ListView whose items have invisible CheckBoxes by setting its visibility View.Gone. When the user tabs a menu button then it will turn on and off the CheckBox visibility and some other layouts. Below is the code, I removed some unnecessary parts:
private void editmodeSwitch(boolean flag){
// get topbar, bottombar, and bottombar2
LinearLayout topbar = (LinearLayout) findViewById(R.id.task_topbar_linearLayout);
LinearLayout bottombar = (LinearLayout) findViewById(R.id.task_bottombar1_linearlayout);
LinearLayout bottombar2 = (LinearLayout) findViewById(R.id.task_bottombar2_linearlayout);
if(flag){
isEditmodeOn = true;
// make topbar and bottombar2 visilble, but bottombar gone
topbar.setVisibility(View.VISIBLE);
bottombar.setVisibility(View.GONE);
bottombar2.setVisibility(View.VISIBLE);
// make checkboxes visible in listview visible as well
for(int i=0; i<listView.getChildCount(); i++){
LinearLayout ll = (LinearLayout) listView.getChildAt(i);
CheckBox cb = (CheckBox) ll.findViewById(R.id.task_row_checkBox1);
cb.setVisibility(View.VISIBLE);
}
}
else{
isEditmodeOn = false;
topbar.setVisibility(View.GONE);
bottombar.setVisibility(View.VISIBLE);
bottombar2.setVisibility(View.GONE);
// set each checkbox false and its visibility gone
for(int i=0; i<listView.getChildCount(); i++){
LinearLayout ll = (LinearLayout) listView.getChildAt(i);
CheckBox cb = (CheckBox) ll.findViewById(R.id.task_row_checkBox1);
cb.setVisibility(View.GONE);
cb.setChecked(false);
}
}
}
It works fine but the problem is the application doesn't work when the screen rotates(changes the screen orientation). Everything worked fine as it displayed some layouts but only CheckBoxes in list items. Below is the code inonCreate()`:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.task_layout);
initialize();
loadDB();
updateListAdapter(list_title, list_date);
// in case of screen rotation
if(savedInstanceState != null){
isEditmodeOn = savedInstanceState.getBoolean(EDITMODE_CHECK);
isItemChecked = savedInstanceState.getBoolean(ITEM_CHECK);
if(isEditmodeOn){
if(!isItemChecked){
Log.i(tag, "item NOT checked");
editmodeSwitch(true);
} else{
//this is something different so please don't mind
deditmodeSwitch(savedInstanceState.getBooleanArray(LIST_CB_CHECK));
}
}
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// save values for rotation
outState.putBoolean(EDITMODE_CHECK, isEditmodeOn);
outState.putBoolean(ITEM_CHECK, isItemChecked);
outState.putBooleanArray(LIST_CB_CHECK, list_cb_check);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.i(tag, "you're in onRestoreInstanceState()");
// in case of screen rotation
if(savedInstanceState != null){
isEditmodeOn = savedInstanceState.getBoolean(EDITMODE_CHECK);
isItemChecked = savedInstanceState.getBoolean(ITEM_CHECK);
if(isEditmodeOn){
if(!isItemChecked){
Log.i(tag, "item NOT checked");
editmodeSwitch(true);
} else{
// this is for something else so please ignore this part
editmodeSwitch(savedInstanceState.getBooleanArray(LIST_CB_CHECK));
}
}
}
What I guessed is the ListView is being loaded at the end. Therefore, even if the code in onCreate() makes CheckBoxes visible, the CheckBoxes will become invisible again as its initialization in xml will do so. However, I'm stuck here and need your advice to solve this problem. Can anyone help me?
Just in case, below is the checkbox code of layout xml file for getview.
<CheckBox android:id="#+id/task_row_checkBox1" android:gravity="right"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:visibility="gone"
/>
Override onSaveInstanceState for saving value on screen rotation and onRestoreInstanceState as:
protected void onCreate(Bundle savedInstanceState) {
if(null != savedInstanceState)
{
Boolean IntTest = savedInstanceState.getBoolean("ITEM_CHECK");
Boolean StrTest = savedInstanceState.getBoolean("ITEM_CHECK");
Log.e(TAG, "onCreate get the savedInstanceState+IntTest="+IntTest+"+StrTest="+StrTest);
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save away the CheckBoxes states, so we still have it if the activity
// needs to be killed while paused.
savedInstanceState.putBoolean(EDITMODE_CHECK, 0);
savedInstanceState.putBoolean(ITEM_CHECK, 0);
super.onSaveInstanceState(savedInstanceState);
Log.e(TAG, "onSaveInstanceState");
}
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Boolean IntTest = savedInstanceState.getBoolean(EDITMODE_CHECK);
Boolean StrTest = savedInstanceState.getBoolean(ITEM_CHECK);
Log.e(TAG, "onRestoreInstanceState+IntTest="+IntTest+"+StrTest="+StrTest);
}
Similar to how you override onCreate, you can override onConfigurationChanged(...) which you can setup to run when the screen changes orientation.
In order for OnConfigurationChanged(...) to be trigger when the screen rotates, you need to to edit your manifest and put that relationship/rule in.
It's easy to do but takes a bit of explaining and it was answered before in this question:
Activity restart on rotation Android
Edit: Here is the dev guide on how to handle configuration changes
http://developer.android.com/guide/topics/resources/runtime-changes.html
Edit #2: First, let me suggest using Imran's solution. It follows the Developer Guide better and the end results will be the same.
Now, for the onConfigurationChanged solution.
Look at what you are doing with your onCreate:
1) Set the view. (Checkboxes are hidden at this point. Right?)
2) Call your DB and determine if you should display checkboxes (edit mode)
3) Make all the checkboxes visible.
Now, onConfigurationChanged also calls setContentView, at which point all your checkboxes are hidden again. So you need to repeat the process of making your checkboxes visible (#3 above). You probably don't need to repeat step #2 because the value should be retained, but I'm not sure how the logic of your app works, so you may need to re-do step #2.
Does that make sense?
Based on my experience, getview seems to be triggered at the end and it was why 'onRestoreInstanceState()' and 'onConfigurationChanged()' could not make it as getview will reset my checkboxes invisible as initialization in the layout xml file.
Therefore, the only solution I could find out was I must control them in getview for the answer.

Wrong value in EditText when changing screen orientation

Im confused.
I have a layout (LinearLayout) holding a TextView and EditText.
Somewhere in my code i create (programatically) a RelativeLayout and push in it several of this LinearLayouts. To each one of them i set an ID and values for TextView and EditText.
The problem is when i change screen orientation. All EditText controls gets the same value (from the last EditText). If i set a breakpoint all seems fine. I even inspected all elemets before setContentView is called and all values seem fine.
Any idea?
Here is the relevant part of code:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
csWgs84 = getCoordinateSystem();
wgs84C = getCoordinates();
sView = new ScrollView(this);
layout = getLayoutInflater().inflate(R.layout.location_calculator, null);
View control1 = getLayoutInflater().inflate(R.layout.text_edit, null);
control1.setId(1);
TextView title1 = (TextView) control1.findViewById(R.id.title);
title1.setText(csWgs84.axisInfo.yAxisAbbreaviation + " [°] :");
EditText value1 = (EditText) control1.findViewById(R.id.input);
value1.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
value1.setText(cutValue(RSimpleFormatter.formatNumber(wgs84C.y, 1, 7, '.'), 12));
RelativeLayout.LayoutParams viewLayoutParams1 = new RelativeLayout.LayoutParams
(RelativeLayout.LayoutParams.FILL_PARENT,RelativeLayout.LayoutParams.WRAP_CONTENT );
viewLayoutParams1.addRule(RelativeLayout.BELOW, group.getId());
((RelativeLayout) layout).addView(control1, viewLayoutParams1);
View control2 = getLayoutInflater().inflate(R.layout.text_edit, null);
control2.setId(2);
TextView title2 = (TextView) control2.findViewById(R.id.title);
title2.setText(csWgs84.axisInfo.xAxisAbbreaviation + " [°] :");
EditText value2 = (EditText) control2.findViewById(R.id.input);
value2.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
value2.setText(cutValue(RSimpleFormatter.formatNumber(wgs84C.x, 1, 7, '.'), 12));
RelativeLayout.LayoutParams viewLayoutParams2 = new RelativeLayout.LayoutParams
(RelativeLayout.LayoutParams.FILL_PARENT,RelativeLayout.LayoutParams.WRAP_CONTENT );
viewLayoutParams2.addRule(RelativeLayout.BELOW, control1.getId());
((RelativeLayout) layout).addView(control2, viewLayoutParams2);
sView.addView(layout, scrollViewLayoutParams);
setContentView(sView);
}
I had the same problem. I don't know why it happens; it happens in one of my activities but not in another one that I think is almost identical. I haven't investigated it extensively though.
However, I came up with a workaround: Populate the EditTexts in onResume() instead of in onCreate(). (I also tried to populate them in onStart, but then I got the same fault.) I hope that may work for you or anyone else reading this thread.
If the (admittedly usually very clever) default onPause() method isn't dealing well your activity being pushed to memory and being reloaded from it then you need to override it.
Use onPause to save the value's of your programatically created fields in a bundle. In your onCreate method check for the presence of a Bundle and create you're view's from this.
Activity Lifecycle
Be careful with the references. Maybe you are creating all the EditText "programatically", and then just modifying the last one several times.
Posting the code will be helpful.
Check this or this. I think you are not saving EditText content during orientation change.
The underlying problem is that the views in your custom layout, which is inflated and added multiple times, all have the same IDs (R.id.title and R.id.input). When Android saves their state, each one overwrites the previous one because of the same ID.
What you could do is to define some unique IDs which are generated by Android and assign those to the fields programmatically.
Not sure if this is the case, but I was able to fix this issue by removing
android:textIsSelectable="true"
from my XML layout.

Categories

Resources