number doesn't show in editText field when entered (Android 2.2) - android-edittext

I have two editText fields, with following TextWatchers in their own addTextChangedListeners. Input is read and handled correctly but the number I enter is simply not shown on the display in the second field (editText2) (even though I wait (sleep() in afterTextChanged()) a while before proceeding with setting the values of both fields to null end setting focus to the first field.
What happens is on entering a number in the first field: number is diplayed in the field and focus is moved to the second field. What happens on entering a number in the second field: cursor (blinking vertical line) is frozen, no number is shown, after two seconds: cursor is moved to first field and both fields all empty. All of this is meant to happen except that the number entered in the second field should show and then the system should be frozen showing that number for a while before setting to null and moving on to the first field.
What is wrong and how to solve?
public class Spel extends FragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.spel);
editText1 = (EditText) findViewById(R.id.editText1);
editText1.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
if (before==0) { // alleen doen als editText1 leeg was
String v = s.toString();
if (v.equals("0") || v.equals("1") || v.equals("2") || v.equals("3") || v.equals("4") || v.equals("5") || v.equals("6") || v.equals("7") || v.equals("8") || v.equals("9")) {
editText2.requestFocus();
int baanWorpScore = Integer.parseInt(v);
banenWorpScore[0] = baanWorpScore;
}
else {
// blijf wachten op goede invoer
editText1.setText(null);
}
}
}
});
editText2 = (EditText) findViewById(R.id.editText2);
editText2.addTextChangedListener(new TextWatcher() {
#Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
if (before==0) {
String v = s.toString();
if (v.equals("0") || v.equals("1") || v.equals("2") || v.equals("3") || v.equals("4") || v.equals("5") || v.equals("6") || v.equals("7") || v.equals("8") || v.equals("9")) {
editText1.requestFocus();
editText1.setText(null);
editText2.setText(null);
int baanWorpScore = Integer.parseInt(v);
banenWorpScore[1] = baanWorpScore;
}
else {
// blijf wachten op goede invoer
editText2.setText(null);
}
}
});
}

Found following solution, putting the delayed operations in a runnable, passed to method postDelayed of a (new) handler. This does exactly what I wished. Refer here for a post that helped me find where to look for the solution.
(I actually don't know if method removeCallbacks must actually be called)
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
Runnable mFilterTask = new Runnable() {
#Override
public void run() {
editText1.setText(null);
editText2.setText(null);
editText1.requestFocus();
}
};
Handler mHandler = new Handler();
if (before==0) {
String v = s.toString();
if (v.equals("0") || v.equals("1") || v.equals("2") || v.equals("3") || v.equals("4") || v.equals("5") || v.equals("6") || v.equals("7") || v.equals("8") || v.equals("9")) {
mHandler.removeCallbacks(mFilterTask);
mHandler.postDelayed(mFilterTask, 2000);
int baanWorpScore = Integer.parseInt(v);
banenWorpScore[1] = baanWorpScore;
}
}
}

Related

Building Splittable DoFn (SDF) to list objects in GCS

I am trying to develop custom source for parallel GCS content scanning. The naive approach would be to loop through listObjects function calls:
while (...) {
Objects objects = gcsUtil.listObjects(bucket, prefix, pageToken);
pageToken = objects.getNextPageToken();
...
}
The problem is performance for the tens of millions objects.
Instead of the single thread code we can add delimiter / and submit parallel processed for each prefix found:
...
Objects objects = gcsUtil.listObjects(bucket, prefix, pageToken, "/");
for (String subPrefix : object.getPrefixes()) {
scanAsync(bucket, subPrefix);
}
...
Next idea was to try to wrap this logic in Splittable DoFn.
Choice of RestrictionTracker: I don't see how can be used any of exiting RestrictionTracker. So decided to write own. Restriction itself is basically list of prefixes to scan. tryClaim checks if there is more prefixes left and receive newly scanned to append them to current restriction. trySplit splits list of prefixes.
The problem that I faced that trySplit can be called before all subPrefixes are found. In this case current restriction may receive more work to do after it was splitted. And it seems that trySplit is being called until it returns a not null value for a given RestrictionTracker: after certain number of elements goes to the output or after 1 second via scheduler or when ProcessContext.resume() returned. This doesn't work in my case as new prefixes can be found at any time. And I can't checkpoint via return ProcessContext.resume() because if split was already done, possible work that left in current restriction will cause checkDone() function to fail.
Another problem that I suspect that I couldn't achieve parallel execution in DirectRunner. As trySplit was always called with fractionOfRemainder=0 and new RestrictionTracker was started only after current one completed its piece of work.
It would be also great to read more detailed explanation about Splittable DoFn components lifecycle. How parallel execution per element is achieved. And how and when state of RestrictionTracker can be modified.
UPD: Adding simplified code that should show intended implementation
#DoFn.BoundedPerElement
private static class ScannerDoFn extends DoFn<String, String> {
private transient GcsUtil gcsUtil;
#GetInitialRestriction
public ScannerRestriction getInitialRestriction(#Element String bucket) {
return ScannerRestriction.init(bucket);
}
#ProcessElement
public ProcessContinuation processElement(
ProcessContext c,
#Element String bucket,
RestrictionTracker<ScannerRestriction, ScannerPosition> tracker,
OutputReceiver<String> outputReceiver) {
if (gcsUtil == null) {
gcsUtil = c.getPipelineOptions().as(GcsOptions.class).getGcsUtil();
}
ScannerRestriction currentRestriction = tracker.currentRestriction();
ScannerPosition position = new ScannerPosition();
while (true) {
if (tracker.tryClaim(position)) {
if (position.completedCurrent) {
// position.clear();
// ideally I would to get checkpoint here before starting new work
return ProcessContinuation.resume();
}
try {
Objects objects = gcsUtil.listObjects(
currentRestriction.bucket,
position.currentPrefix,
position.currentPageToken,
"/");
if (objects.getItems() != null) {
for (StorageObject o : objects.getItems()) {
outputReceiver.output(o.getName());
}
}
if (objects.getPrefixes() != null) {
position.newPrefixes.addAll(objects.getPrefixes());
}
position.currentPageToken = objects.getNextPageToken();
if (position.currentPageToken == null) {
position.completedCurrent = true;
}
} catch (Throwable throwable) {
logger.error("Error during scan", throwable);
}
} else {
return ProcessContinuation.stop();
}
}
}
#NewTracker
public RestrictionTracker<ScannerRestriction, ScannerPosition> restrictionTracker(#Restriction ScannerRestriction restriction) {
return new ScannerRestrictionTracker(restriction);
}
#GetRestrictionCoder
public Coder<ScannerRestriction> getRestrictionCoder() {
return ScannerRestriction.getCoder();
}
}
public static class ScannerPosition {
private String currentPrefix;
private String currentPageToken;
private final List<String> newPrefixes;
private boolean completedCurrent;
public ScannerPosition() {
this.currentPrefix = null;
this.currentPageToken = null;
this.newPrefixes = Lists.newArrayList();
this.completedCurrent = false;
}
public void clear() {
this.currentPageToken = null;
this.currentPrefix = null;
this.completedCurrent = false;
}
}
private static class ScannerRestriction {
private final String bucket;
private final LinkedList<String> prefixes;
private ScannerRestriction(String bucket) {
this.bucket = bucket;
this.prefixes = Lists.newLinkedList();
}
public static ScannerRestriction init(String bucket) {
ScannerRestriction res = new ScannerRestriction(bucket);
res.prefixes.add("");
return res;
}
public ScannerRestriction empty() {
return new ScannerRestriction(bucket);
}
public boolean isEmpty() {
return prefixes.isEmpty();
}
public static Coder<ScannerRestriction> getCoder() {
return ScannerRestrictionCoder.INSTANCE;
}
private static class ScannerRestrictionCoder extends AtomicCoder<ScannerRestriction> {
private static final ScannerRestrictionCoder INSTANCE = new ScannerRestrictionCoder();
private final static Coder<List<String>> listCoder = ListCoder.of(StringUtf8Coder.of());
#Override
public void encode(ScannerRestriction value, OutputStream outStream) throws IOException {
NullableCoder.of(StringUtf8Coder.of()).encode(value.bucket, outStream);
listCoder.encode(value.prefixes, outStream);
}
#Override
public ScannerRestriction decode(InputStream inStream) throws IOException {
String bucket = NullableCoder.of(StringUtf8Coder.of()).decode(inStream);
List<String> prefixes = listCoder.decode(inStream);
ScannerRestriction res = new ScannerRestriction(bucket);
res.prefixes.addAll(prefixes);
return res;
}
}
}
private static class ScannerRestrictionTracker extends RestrictionTracker<ScannerRestriction, ScannerPosition> {
private ScannerRestriction restriction;
private ScannerPosition lastPosition = null;
ScannerRestrictionTracker(ScannerRestriction restriction) {
this.restriction = restriction;
}
#Override
public boolean tryClaim(ScannerPosition position) {
restriction.prefixes.addAll(position.newPrefixes);
position.newPrefixes.clear();
if (position.completedCurrent) {
// completed work for current prefix
assert lastPosition != null && lastPosition.currentPrefix.equals(position.currentPrefix);
lastPosition = null;
return true; // return true but we would need to claim again if we need to get next prefix
} else if (lastPosition != null && lastPosition.currentPrefix.equals(position.currentPrefix)) {
// proceed work for current prefix
lastPosition = position;
return true;
}
// looking for next prefix
assert position.currentPrefix == null;
assert lastPosition == null;
if (restriction.isEmpty()) {
// no work to do
return false;
}
position.currentPrefix = restriction.prefixes.poll();
lastPosition = position;
return true;
}
#Override
public ScannerRestriction currentRestriction() {
return restriction;
}
#Override
public SplitResult<ScannerRestriction> trySplit(double fractionOfRemainder) {
if (lastPosition == null && restriction.isEmpty()) {
// no work at all
return null;
}
if (lastPosition != null && restriction.isEmpty()) {
// work at the moment only at currently scanned prefix
return SplitResult.of(restriction, restriction.empty());
}
int size = restriction.prefixes.size();
int newSize = new Double(Math.round(fractionOfRemainder * size)).intValue();
if (newSize == 0) {
ScannerRestriction residual = restriction;
restriction = restriction.empty();
return SplitResult.of(restriction, residual);
}
ScannerRestriction residual = restriction.empty();
for (int i=newSize; i<=size; i++) {
residual.prefixes.add(restriction.prefixes.removeLast());
}
return SplitResult.of(restriction, residual);
}
#Override
public void checkDone() throws IllegalStateException {
if (lastPosition != null) {
throw new IllegalStateException("Called checkDone on not completed job");
}
}
#Override
public IsBounded isBounded() {
return IsBounded.UNBOUNDED;
}
}

Linked List search method

I am practicing build a doubly linked list contains string value.
In find method, I have a NullPointer Exception
here is my code.
package LinkedList;
package LinkedList;
public class LinkedList {
// 노드 클래스
class Node {
String value;
Node prev;
Node next;
Node(String v, Node p, Node s) {
value = v;
prev = p;
next = s;
}
public String getValue() {
return value;
}
public Node getPrev() {
return prev;
}
public Node getNext() {
return next;
}
public void setPrev(Node p) {
prev = p;
}
public void setNext(Node n) {
next = n;
}
}
Node head;
Node tail;
int size = 0;
public LinkedList() {
head = new Node(null, null, null);
tail = new Node(null, head, null);
head.setNext(tail);
}
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
public String first() {
if (isEmpty()) {
return null;
}
return head.getNext().getValue();
}
public String last() {
if (isEmpty()) {
return null;
}
return tail.getPrev().getValue();
}
public void addFirst(String value) {
addBetween(value, head, head.getNext());
}
public void addLast(String value) {
addBetween(value, tail.getPrev(), tail);
}
public void addBetween(String v, Node p, Node s) {
Node newNode = new Node(v, p, s);
p.setNext(newNode);
s.setPrev(newNode);
size++;
}
public String remove(Node node) {
Node p = node.getPrev();
Node s = node.getNext();
p.setNext(s);
s.setPrev(p);
size--;
return node.getValue();
}
public String removeFirst() {
if (isEmpty()) {
return null;
}
return remove(head.getNext());
}
public String removeLast() {
if (isEmpty()) {
return null;
}
return remove(tail.getPrev());
}
public void insert(String value) {
Node current = head;
// first
if (isEmpty()) {
addFirst(value);
} else {
// check
while (current.getNext() != tail || current.getValue().compareTo(value) > 0) {
current = current.getNext();
}
// last
if (current.getNext() == tail) {
addLast(value);
} else // between
{
addBetween(value, current.getNext(), current);
}
}
}
/* !!!!!!!!!!!!!! ERORR !!!!!!!!!!!! */
public void find(String value) {
Node current = head.getNext();
while ((current != null) || !(current.getValue().equals(value)))
current = current.getNext();
if (current.getValue().equals(value)) {
System.out.println("found " + value);
} else {
System.out.println("Not found " + value);
}
}
// • Traverse the list forwards and print
// 순회
public void fowardTraverse() {
Node current = head.getNext();
System.out.print(current.getValue());
while (current.getNext() != tail) {
current = current.getNext();
System.out.print(" -> " + current.getValue());
}
}
// • Traverse the list backwards and print
// 뒤로 순회
public void backwardTraverse() {
Node current = tail.getPrev();
System.out.print(current.getValue());
while (current.getPrev() != head) {
current = current.getPrev();
System.out.print(" -> " + current.getValue());
}
}
// • Delete a node from the list
// 지우기
public String delete(String value) {
return value;
}
// • Delete/destroy the list
// 파괴하기
public void destroy() {
}
public static void main(String[] args) {
// TODO Auto-generated method stubs
LinkedList a = new LinkedList();
a.insert("a");
a.insert("b");
a.insert("c");
a.insert("d");
a.insert("e");
a.insert("f");
a.insert("g");
a.insert("h");
a.insert("i");
// a.fowardTraverse();
a.find("a");
}
I don't understand why I get a nullpointException at the line,
It suppose to put a node contains a.
Make sure you check for Non-NULL before dereferencing:
Node current = head.getNext();
and
if (current.getValue().equals(value)) {
to be replaced by
Node current;
if(head != NULL) current = head.getNext();
and
if (current != NULL && current.getValue().equals(value)) {
Because your Head is empty...(No pun intended)
before Addfirst calling..your structure:
head=[null,null,tail],tail=[null,head,null];
you are sending ("a",head,tail)
and your storing it in new node making it a structure like:
head=[null,null,newNode]==>newNode["a",head,tail]==>tail[null,newNode,null]
So search will compare null to a (in find) giving you the error .....
---Edit 1:
#JanghyupLee, My Bad, Didn't do a closer look on find method...however , I found that in condition of "if" you are using condition
current != null || ......
After first line that is ( current=head.next)..current becomes not null..
which is causing the condition in while to ignore the right part of '||' (short circuit) until current has a value of null...
Once the current becomes null then it goes for the next statement to check for value..causing null pointer exception

Wait for view pager animations with espresso?

Trying to do some tests with a ViewPager.
I want to swipe between tabs, and I don't want to continue until the swipe is complete. But there doesn't appear to be a way to turn off the animation for the view pager (all animations under the developer options are disabled).
So this always results in a test failure, because the view pager hasn't completed it's animation, and so the view is not completely displayed yet:
// swipe left
onView(withId(R.id.viewpager)).check(matches(isDisplayed())).perform(swipeLeft());
// check to ensure that the next tab is completely visible.
onView(withId(R.id.next_tab)).check(matches(isCompletelyDisplayed()));
Is there an elegant or maybe even recommended way to do this, or am I stuck putting some kind of timed wait in there?
The IdlingResource #Simas suggests is actually pretty simple to implement:
public class ViewPagerIdlingResource implements IdlingResource {
private final String mName;
private boolean mIdle = true; // Default to idle since we can't query the scroll state.
private ResourceCallback mResourceCallback;
public ViewPagerIdlingResource(ViewPager viewPager, String name) {
viewPager.addOnPageChangeListener(new ViewPagerListener());
mName = name;
}
#Override
public String getName() {
return mName;
}
#Override
public boolean isIdleNow() {
return mIdle;
}
#Override
public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
mResourceCallback = resourceCallback;
}
private class ViewPagerListener extends ViewPager.SimpleOnPageChangeListener {
#Override
public void onPageScrollStateChanged(int state) {
mIdle = (state == ViewPager.SCROLL_STATE_IDLE
// Treat dragging as idle, or Espresso will block itself when swiping.
|| state == ViewPager.SCROLL_STATE_DRAGGING);
if (mIdle && mResourceCallback != null) {
mResourceCallback.onTransitionToIdle();
}
}
}
}
Since I've done this at least twice now, here is the accepted answer in Kotlin and with androidx ViewPager2:
class ViewPager2IdlingResource(viewPager: ViewPager2, name: String) : IdlingResource {
private val name: String
private var isIdle = true // Default to idle since we can't query the scroll state.
private var resourceCallback: IdlingResource.ResourceCallback? = null
init {
viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageScrollStateChanged(state: Int) {
isIdle = (state == ViewPager.SCROLL_STATE_IDLE // Treat dragging as idle, or Espresso will block itself when swiping.
|| state == ViewPager.SCROLL_STATE_DRAGGING)
if (isIdle && resourceCallback != null) {
resourceCallback!!.onTransitionToIdle()
}
}
})
this.name = name
}
override fun getName(): String {
return name
}
override fun isIdleNow(): Boolean {
return isIdle
}
override fun registerIdleTransitionCallback(resourceCallback: IdlingResource.ResourceCallback) {
this.resourceCallback = resourceCallback
}
}
And here is how you use it from a UI test using ActivityScenarioRule:
#get:Rule
val testRule = ActivityScenarioRule(OnboardingActivity::class.java)
private lateinit var viewPager2IdlingResource: ViewPager2IdlingResource
....
#Before
fun setUp() {
testRule.scenario.onActivity {
viewPager2IdlingResource =
ViewPager2IdlingResource(it.findViewById(R.id.onboarding_view_pager), "viewPagerIdlingResource")
IdlingRegistry.getInstance().register(viewPager2IdlingResource)
}
}
#After
fun tearDown() {
IdlingRegistry.getInstance().unregister(viewPager2IdlingResource)
}
The androidx.test.espresso:espresso-core library offers a ViewPagerActions class which contains a number of methods for scrolling between the pages of a ViewPager. It takes care of waiting until the scroll is complete so you don't need to add any explicit waits or sleeps in your test methods.
If you need to perform similar scrolling on a ViewPager2 instance, you can take the source code of the ViewPagerActions class and make some minor tweaks to it to get it to work for ViewPager2. Here is an example which you are welcome to take and use.
Try this,
onView(withId(R.id.pager)).perform(pagerSwipeRight()).perform(pagerSwipeLeft());
private GeneralSwipeAction pagerSwipeRight(){
return new GeneralSwipeAction(Swipe.SLOW, GeneralLocation.CENTER_LEFT,
GeneralLocation.CENTER_RIGHT, Press.FINGER);
}
private GeneralSwipeAction pagerSwipeLeft(){
return new GeneralSwipeAction(Swipe.SLOW, GeneralLocation.CENTER_RIGHT,
GeneralLocation.CENTER_LEFT, Press.FINGER);
}
I was having issues with #vaughandroid approach, so I did some changes to his approach. This approach will set idle to false as soon as it detects a scrolling is happening and "force" the ViewPager to finish scrolling by using setCurrentItem().
public class ViewPagerIdlingResource implements IdlingResource {
private volatile boolean mIdle = true; // Default to idle since we can't query the scroll state.
private ResourceCallback mResourceCallback;
private ViewPager mViewPager;
public static ViewPagerIdlingResource waitViewPagerSwipe(ViewPager viewPager) {
return new ViewPagerIdlingResource(viewPager);
}
private ViewPagerIdlingResource(ViewPager viewPager) {
mViewPager = viewPager;
mViewPager.addOnPageChangeListener(new ViewPagerListener());
}
#Override
public String getName() {
return ViewPagerIdlingResource.class.getSimpleName();
}
#Override
public boolean isIdleNow() {
return mIdle;
}
#Override
public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
mResourceCallback = resourceCallback;
}
private class ViewPagerListener extends ViewPager.SimpleOnPageChangeListener {
float mPositionOffset = 0.0f;
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (isSwipingToRight(positionOffset)) {
mIdle = false;
mViewPager.setCurrentItem(position + 1);
} else if (isSwipingToLeft(positionOffset)) {
mIdle = false;
mViewPager.setCurrentItem(position - 1);
}
mPositionOffset = positionOffset;
if (positionOffset == 0 && !mIdle && mResourceCallback != null) {
mResourceCallback.onTransitionToIdle();
mIdle = true;
mPositionOffset = 0.0f;
}
}
private boolean isSwipingToRight(float positionOffset) {
return mPositionOffset != 0.0f && positionOffset > mPositionOffset && mIdle;
}
private boolean isSwipingToLeft(float positionOffset) {
return mPositionOffset != 0.0f && positionOffset < mPositionOffset && mIdle;
}
}
}
My goal was to make a screenshot of the screen with ViewPager2 using Facebook screenshot test library. The easiest approach for me was to check almost every frame whether animation completed, if yes then it's time to make a screenshot:
fun waitForViewPagerAnimation(parentView: View) {
if (parentView is ViewGroup) {
parentView.childrenViews<ViewPager2>().forEach {
while (it.scrollState != ViewPager2.SCROLL_STATE_IDLE) {
Thread.sleep(16)
}
}
}
}
childrenViews function can be found here
You can either do a lot of work and use an IdlingResource to implement an OnPageChangeListener
or simply:
SystemClock.sleep(500);

SAX getting only the end of a content string

I need to catch data from < itunes:sumary > tag but my handler is getting only the end of tag's content (last three words for example). I don't know what to do because other tags are being handled as expected, getting all content.*
I've seen that some tags are ignored by parser, but I don't think it's happening with because as I said it gets the content but only the end of that.
The source XML is hosted in -> http://djpaulonla.podomatic.com/archive/rss2.xml
Please, could someone help me???
The code is the following:
public class PodOMaticCustomHandler extends CustomHandler {
public PodOMaticCustomHandler(int quantityToFetch, String startTagValue,
String endTagValue) {
super(quantityToFetch, startTagValue, endTagValue);
}
#Override
public void characters(char[] ch, int start, int length)
throws SAXException {
super.characters(ch, start, length);
this.value = new String(ch, start, length);
}
#Override
public void endDocument() throws SAXException {
super.endDocument();
this.endDoc = true;
}
#Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
super.endElement(uri, localName, qName);
if (this.podcast != null) {
if (qName.equalsIgnoreCase("title")) {
podcast.setTitle(this.value);
} else if (qName.equalsIgnoreCase("pubDate")) {
podcast.setPubDate(this.value);
} else if (qName.equalsIgnoreCase("description")) {
podcast.setContent(this.value);
} else if (qName.equalsIgnoreCase("guid")) {
this.podcast.setLink(value);
}
}
}
#Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
if (this.startTagValue == null) {
this.startTagValueFound = true;
} else if (qName.equalsIgnoreCase("guid")
&& this.value.equalsIgnoreCase(this.startTagValue)) {
this.startTagValueFound = true;
}
if (this.endTagValue != null) {
if (qName.equalsIgnoreCase("guid")
&& this.value.equalsIgnoreCase(this.endTagValue)) {
this.endDoc = true;
}
}
if (!this.endDoc) {
if (this.quantityToFetch != this.podcasts.size()) {
if (this.startTagValueFound == true) {
if (qName.equalsIgnoreCase("item")) {
this.podcast = new Podcast();
} else if (qName.equalsIgnoreCase("enclosure")) {
this.podcast.setMedia(attributes.getValue("url"));
this.podcasts.add(podcast);
}
}
} else {
this.podcast = null;
}
}else{
this.podcast = null;
}
}
}
You can't rely on the characters method being called once with the entire element text, it may be called multiple times, each time with only part of the text.
Add a debug log statement to the characters method showing what you're setting value to and you will see that values is getting set with the first part of the string and then getting overwritten with the last part.
The answer is to buffer the text passed in from the characters calls in a CharArrayWriter or StringBuilder. Then you have to clear the buffer when the end of the element is found.
Here's what the Java tutorial on SAX has to say about the characters method:
Parsers are not required to return any particular number of characters at one time. A parser can return anything from a single character at a time up to several thousand and still be a standard-conforming implementation. So if your application needs to process the characters it sees, it is wise to have the characters() method accumulate the characters in a java.lang.StringBuffer and operate on them only when you are sure that all of them have been found.

Blackberry - Clickable BitmapField With Different ID's

i'm creating one application in which i get gift images with id's from web server through JSON. When i click on any gift image, it goes on next page where it shows all information of that image (get image information with its id from web server through JSON).
Problem is: When i click on any gift image on page to see its relevant information, it gets the last gift image id every time, i want when i click on any image, it gets the specific image id which i click. How it is possible??
Screenshot of the page is : http://ugo.offroadstudios.com/gifts.png
Here is sample code:
public class Gifts extends MainScreen {
String giftsid;
BitmapField giftimg;
public Gifts(){
setTitle("Gift Store");
creategifts();
}
public void creategifts()
{
//Link URL
String strURL = "http://ugo.offroadstudios.com/api/frndgift/?loginusername=adil;deviceside=true";
webConnection wb = new webConnection();
String res = wb.getJson(strURL);
try {
JSONObject object = new JSONObject(res);
if(object.getString("status") == "error")
{
Dialog.alert("Invalid "+object.getString("status"));
}
else
{
int totalgifts;
totalgifts = object.getInt("totalgifts");
Bitmap listThumb;
JSONArray imagearr;
JSONArray giftsidarr;
String imgname;
Bitmap bmpResized;
for(int i=0; i < totalgifts; i++){
imagearr = object.getJSONArray("gifts_image");
imgname = imagearr.getString(i);
giftsidarr = object.getJSONArray("gifts_id");
giftsid = giftsidarr.getString(i);
listThumb = getImage.getImageFromUrl("http://ugo.offroadstudios.com/wp-content/plugins/bp-gifts-rebirth/includes/images/"+imgname+";deviceside=true");
bmpResized = GPATools.ResizeTransparentBitmap(listThumb, 80, 80,
Bitmap.FILTER_LANCZOS, Bitmap.SCALE_TO_FIT);
giftimg =new BitmapField(bmpResized,FOCUSABLE)
{
protected boolean navigationClick(int status, int time)
{
Dialog.alert("giftsid "+giftsid);
UiApplication.getUiApplication().pushScreen(new SendGift(giftsid));
return true;
}
};
add(giftimg);
}
}
}
catch (JSONException e) {
System.out.println("EX is "+e);
e.printStackTrace();
}
}
}
You are always getting the gift id of the last gift in the list because you have created your buttons with this code:
giftimg =new BitmapField(bmpResized,FOCUSABLE)
{
protected boolean navigationClick(int status, int time)
{
Dialog.alert("giftsid "+giftsid);
UiApplication.getUiApplication().pushScreen(new SendGift(giftsid));
return true;
}
};
Your navigationClick() method used the giftsid variable, which is a persistent member variable of your class. You assign this variable in your for loop, so the final value it keeps is the last value assigned in the loop (giftsidarr.getString(totalgifts)).
Although you declare the navigationClick() method in a loop where the giftsid is many different values, the navigationClick() method uses the value of giftsid when it is run. The last value.
There's many ways to fix it. You can use a separate constant value in your loop:
final String nextGiftsId = giftsid;
giftimg =new BitmapField(bmpResized,FOCUSABLE)
{
protected boolean navigationClick(int status, int time)
{
Dialog.alert("nextGiftsId= "+nextGiftsId);
UiApplication.getUiApplication().pushScreen(new SendGift(nextGiftsId));
return true;
}
};
Or, as Signare suggested, attach a cookie to each button that identifies its corresponding gift:
giftimg =new BitmapField(bmpResized,FOCUSABLE)
{
protected boolean navigationClick(int status, int time)
{
String giftId = (String)getCookie(); // read gift id from the cookie
Dialog.alert("giftId= "+giftId);
UiApplication.getUiApplication().pushScreen(new SendGift(giftId));
return true;
}
};
giftimg.setCookie(giftsid); // set the cookie after creating the field
Inside your for loop, add the following code -
giftimg[i].setChangeListener(this);
Then -
public void fieldChanged(Field field, int context) {
for(int i=0;i<totalgifts;i++) {
if(field == giftimg[i]) {
// you can trigger your event
}
}
EDIT :-
giftimg[i].setChangeListener(listener);
listener = new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
if ( field instanceof BitmapField ) {
for(int i=0;i<totalgifts;i++) {
if ( field == giftimg[i] ) {
// you can trigger your event
}
}
}
}
};

Resources