1QuickQuestion 1QuickQuestion - 5 months ago 35
Java Question

XML TypedArray only Displaying first image

This is my first attempt with TypedArrays and I believe I've written my code correctly, but for some reason I am only able to see the first image in my array. I have a loop that should be displaying the images repeatedly.

My activity.xml:

<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:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".HomeScreen"
android:background="@android:drawable/screen_background_dark_transparent"
android:clickable="true"
android:id="@+id/homescreen_view">

<Button
android:layout_width="100.0dp"
android:layout_height="25.0dp"
android:text="Help"
android:id="@+id/instructionsButton"
android:layout_alignParentTop="false"
android:layout_alignParentStart="true"
android:textColor="#05ffda"
android:background="@android:color/holo_purple"
android:longClickable="true" />

<ImageButton
android:layout_width="50dp"
android:layout_height="50dp"
android:scaleType="centerCrop"
android:id="@+id/soundEnable_button"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:longClickable="true"
android:nestedScrollingEnabled="true"/>

<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="100dp"
android:layout_height="25dp"
android:text="Highscores"
android:id="@+id/highscores_button"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:background="@android:color/holo_purple"
android:textColor="#05ffda" />

<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="100dp"
android:layout_height="30dp"
android:text="Play Game"
android:id="@+id/startGame_button"
android:background="@android:color/holo_purple"
android:textColor="#05ffda"
android:layout_marginTop="175dp"
android:singleLine="true"
android:layout_alignParentTop="false"
android:layout_centerHorizontal="true" />

</RelativeLayout>


Arrays.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<array name="musicIcon">
<item>@drawable/musicoff</item>
<item>@drawable/musicon1</item>
<item>@drawable/musicon2</item>
<item>@drawable/musicon3</item>
<item>@drawable/musicon4</item>
<item>@drawable/musicon5</item>
</array>
</resources>


and my activity.java

import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageButton;

public class HomeScreen extends AppCompatActivity {

ImageButton musicEnable_ImageButton;
Handler musicIcon_animate = new Handler();
int ArrayPos = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home_screen);


final TypedArray musicIcons = getResources().obtainTypedArray(R.array.musicIcon);
for(ArrayPos =0;ArrayPos<5;ArrayPos++) {
musicIcons.getResourceId(ArrayPos, -1);
}
ArrayPos = 0;
musicEnable_ImageButton = (ImageButton) findViewById(R.id.soundEnable_button);
musicEnable_ImageButton.setImageResource(musicIcons.getResourceId(ArrayPos,-1));
musicIcons.recycle();
musicEnable_ImageButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
ArrayPos = 1;
Runnable runnable = new Runnable() {
@Override
public void run() {
musicEnable_ImageButton.setImageResource(musicIcons.getResourceId(ArrayPos,-1));
musicIcons.recycle();
if(ArrayPos < 5) {
ArrayPos++;
}
else{
ArrayPos = 1;
}
Log.d("test", "timer fired");
musicIcon_animate.postDelayed(this, 1);
}
};

musicIcon_animate.postDelayed(runnable, 1);

}
});
}

Answer

You can only see the first image because you are recycling your musicIcons TypedArray after you set the first image. TypedArray.recycle() removes all of the references to the resources in the array, making it an empty array. You want to do this, but only after you've gotten what you need from the array.

In your case, since you are using the resources over a period of time, I would suggest doing something like this:

List<Integer> musicIcons = new ArrayList<>();

final TypedArray typedArray = getResources().obtainTypedArray(R.array.musicIcon);

for(int i = 0; i < typedArray.length(); i++) {
    musicIcons.add(typedArray.getResourceId(i, -1);
}

typedArray.recycle();

Then set the ImageView resource like this:

musicEnable_ImageButton.setBackgroundResource(musicIcons.get(ArrayPos));

But, I also noticed that it looks like you are just trying to animate the icon, in which case, you should look into using an AnimationDrawable. In this way you can just create a drawable XML file:

<animation-list android:id="@+id/selected" android:oneshot="true">
    <item android:drawable="@drawable/musicoff" android:duration="50" />
    <item android:drawable="@drawable/musicon1" android:duration="50" />
    <item android:drawable="@drawable/musicon2" android:duration="50" />
    <item android:drawable="@drawable/musicon3" android:duration="50" />
    <item android:drawable="@drawable/musicon4" android:duration="50" />
    <item android:drawable="@drawable/musicon5" android:duration="50" />
 </animation-list>

Then set the image resource to this animation-list, and animate it:

musicEnable_ImageButton.setImageResource(R.id.sound_button);

AnimationDrawable frameAnimation = (AnimationDrawable) musicEnable_ImageButton.getBackground();

frameAnimation.start();

On API 21+ it is even easier, you can create an AnimatedStateListDrawable to wrap your animation-list (or lists). Then set android:button attribute of a RadioButton to the AnimatedStateListDrawable and watch it animate as you call setChecked().

Comments