How to dynamically reference resources in the R.drawable folder in Android? - java

I have the following code for my Adapter:
#Override
public void onBindViewHolder(GameViewHolder holder, int position) {
final Games game = gameList.get(position);
holder.awayTeamImageView.setBackgroundResource(R.drawable.fortyers);
}
The above works perfectly but I am hard coding the image that will be displayed. What I really need is to get the background image from the game list and I am looking to do something like this:
holder.awayTeamImageView.setBackgroundResource(R.drawable.game.getaBackground());
But that causes an error
How can I dynamically set the imageView's background resource?
UPDATE:
I have attached a screenshot of the desired effect.
Each week the schedule will change so the list will always be different depending on the week selected.
Game constructor:
public Games(DataSnapshot game) {
this.AwayTeam = game.child("AwayTeam").getValue().toString();
this.AwayId = Integer.parseInt(game.child("AwayId").getValue().toString());
this.HomeTeam = game.child("HomeTeam").getValue().toString();
this.HomeId = Integer.parseInt(game.child("HomeId").getValue().toString());
this.aBackground = game.child("aBackground").getValue().toString();
this.hBackground = game.child("hBackground").getValue().toString();
}

Create a list of String that will contain the id of your drawables, keep them in the order synced with the position and then get the id as per the position from the list to pass while setting the drawable.
If it's something reused in multiple places and the order is consistent, you can also go for an Enum to get the drawable id in terms of a certain key of your choice. You might need to figure the key using a when condition as per position if it's really dependant on the position.
Hope that works!

Assuming Games class should be a model/data class; so you can have an int member field that can store drawable id for each instance of this class, and create getter & setter:
public class Games {
private int myDrawable;
public int getMyDrawable() {
return myDrawable;
}
public void setMyDrawable(int myDrawable) {
this.myDrawable = myDrawable;
}
}
Whenever you construct the Games objects, you can set the drawable image id using setMyDrawable(R.drawabe.foo).. Probably you can modify the Games constructor to accept an int parameter that you can set myDrawable to.
Then in RecyclerView:
#Override
public void onBindViewHolder(GameViewHolder holder, int position) {
final Games game = gameList.get(position);
holder.awayTeamImageView.setBackgroundResource(game.getMyDrawable());
}
UPDATE:
public class Games {
private int homeTeamImage, awayTeamImage;
public int getHomeTeamImage() {
return homeTeamImage;
}
public void setHomeTeamImage(int homeTeamImage) {
this.homeTeamImage = homeTeamImage;
}
public int getAwayTeamImage() {
return awayTeamImage;
}
public void setAwayTeamImage(int awayTeamImage) {
this.awayTeamImage = awayTeamImage;
}
public Games(DataSnapshot game, int homeTeamImage, int awayTeamImage) {
//... rest of code
this.homeTeamImage = homeTeamImage;
this.awayTeamImage = awayTeamImage;
}
}
But in terms of OOP, I'd suggest that you can have a Team class that has either team properties, like image, name, .... etc. and the Games class can be the controller of the game, not building the team instances.

Another approach that might help you is using getIdentifier from the string. For this what you have make a background string name same as the one in your resource. e.g if you want to show ic_menu_camera then your aBackground should be the same string.
Example game class:
public class Game {
String aBackground;
public Game(String aBackground) {
this.aBackground = aBackground;
}
public String getaBackground() {
return aBackground;
}
public void setaBackground(String aBackground) {
this.aBackground = aBackground;
}
}
Then use it like this. Read inline comments to understand in detail.
//set the background name that you want same as name in your drawable folder
// without any extension .png or .xml. Just name should be there
Game game = new Game("ic_menu_camera");
ImageView imageView = findViewById(R.id.imageView);
//get the id by name using this
/* #param name The name of the desired resource.
* #param defType Optional default resource type to find, if "type/" is
* not included in the name. Can be null to require an
* explicit type.
* #param defPackage Optional default package to find, if "package:" is
* not included in the name. Can be null to require an
* explicit package.
*
* #return int The associated resource identifier. Returns 0 if no such
* resource was found. (0 is not a valid resource ID.)
* */
int resId = getResources().getIdentifier(game.getaBackground(), "drawable",getPackageName());
// then set that id to your image
imageView.setBackgroundResource(resId);

Do not make things too complicated. Just use a simple approch. Using HashMap should do just fine.
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("Cincinnati", R.drawable.red_striped_helmet);
map.put("Cleveland", R.drawable.red_helmet);
map.put("New York", R.drawable.blue_helmet);
map.put("Chicago", R.drawable.dark_blue_helmet);
map.put(homeTeam, homeId);
...
holder.awayTeamImageView.setBackgroundResource(map.get("New York"));
// holder.awayTeamImageView.setBackgroundResource(map.get(homeTeam));

Related

Different Textures for same Level Data

The code below shows my Assets class which allows me to load the texture once and call it when I need it globally. If you see that my pack is called house1.pack meaning that there will be more than one house with different art styles. I was wondering if I could achieve a design similar to the popular app Clash Royale with my current code and minor tweaks. I want there to load a different .pack file based on player rank when they are in game. The different houses have the same objects with the same png file names and sizes, but they are just drawn differently.
Thanks,
Denfeet
public class Assets implements Disposable, AssetErrorListener {
public static final String TAG = Assets.class.getName();
public static final Assets instance = new Assets();
private AssetManager assetManager;
public AssetFonts fonts;
public AssetDoor door;
public AssetPlatform platform;
public AssetPlayer player;
public AssetControls controls;
// singleton
private Assets() {
}
public void init(AssetManager assetManager) {
this.assetManager = assetManager;
assetManager.setErrorListener(this);
assetManager.load("TexturePacker/house1.pack", TextureAtlas.class);
assetManager.finishLoading();
TextureAtlas atlas = assetManager.get("TexturePacker/house1.pack");
//create game resource objects
fonts = new AssetFonts();
door = new AssetDoor(atlas);
platform = new AssetPlatform(atlas);
player = new AssetPlayer(atlas);
controls = new AssetControls(atlas);
}
#Override
public void error(AssetDescriptor asset, Throwable throwable) {
Gdx.app.error(TAG, "Couldn't load asset '" + asset.fileName + "'", (Exception) throwable);
}
public class AssetFonts {
...
}
public class AssetPlayer {
...
}
public class AssetControls {
...
}
public class AssetDoor {
...
}
public class AssetPlatform {
...
}
}
You can load and unload assets at any time. Provided you don't want to use house1.pack anywhere else in your game, you can:
assetManager.unload("TexturePacker/house1.pack")
to dispose of your house1.pack, then do most of what you have in your init() method to again
assetManager.load("TexturePacker/house2.pack", TextureAtlas.class);
assetManager.finishLoading();
//etc
Not sure how you'd structure your code, but the above is the idea. Depending on how many assets you're talking about (loading time), you may need a natural transition point (not necessarily a full loading screen). But if you want to change textures from one house to another on the fly, you'd probably want to load them all at once at the beginning and find a different method to swap them.

Public Variables in a Stand-Alone Program

I'm writing a small Java program that randomly deals out playing cards, then displays them on screen in a window.
Since I'm using NetBeans, the GUI was started for me, and I've been writing my methods for randomly choosing cards, setting up an array to store whether or not a card has already been dealt, etc., all in the same class NetBeans set up for me when it built the JFrame.
I'd like to move all my non-GUI code into its own Class, and then just pass data back to the GUI class as needed to display the cards, but I'm not sure of the best way to share data between the two classes.
I know about set/get methods and I know I could make public class-level variables, but everything I've been reading tells me to avoid both as much as possible.
Right now I have a method that generates an int between 1 and 52 for each card dealt. 1 = Ace of spades, 2= 2 of spades, etc. Once the GUI has that number, it can display the appropriate card in the appropriate place on the screen (or at least it will be able to once I've coded the GUI side of things). If I'm looking to pass that integer value to the GUI class, then display a specific card on the screen based on that value, how should I do it?
Seems to me a public variable would make this easy, as would a simple get method...but in the interest of avoiding those options is there another way?
I can provide code snippets if that helps.
Here's one way you could start to implement this idea using OO concepts.
Make a Card class to represent a card.
public class Card {
// FIELDS
// card name
private final String name;
// card value (number)
private final int value;
// another arbitrary value to demonstrate setter
private Object arbitraryValue;
public Card(String name, String value) {
this.name = name;
this.value = value;
}
public String getName() {
return this.name;
}
public int getValue() {
return this.value;
}
public Object getArbitraryValue() {
return this.arbitraryValue;
}
public void setArbitraryValue(Object arbitraryValue) {
this.arbitraryValue = arbitraryValue;
}
}
Create a CardManager class to hold methods that pertain to handling cards (e.g. utility methods and card data storage)
public class CardManager() {
private List<Card> cards = new ArrayList<Card>();
public void addCard(Card card) {
this.cards.add(card);
}
// and so on...your methods here.
}
Finally, create a class for your GUI (CardGUI) management and make use of the other classes to manage it.
You can do so like this:
public class CardGUI() {
public static void main(String[] args) {
// create your GUI and put your logic here...
// also use your other classes, perhaps like so.
Card card = new Card("One", 1);
CardManager cardManager = new CardManager();
cardManager.addCard(card);
// From there you can manage your cards through other classes.
}
Hope this helps / demonstrates how to share data between classes following standards.
Edit:
To answer your question on exactly how you would get the value, then see the above Card class. You would simple create a new card (Card card = new Card("name", intval);), then you would use the method Card#getValue() to get that value and display it in the GUI.

Usage of Proxy design pattern

I tried to understand proxy design pattern. But i could not understand the usage of the proxy design pattern. i got this code example from wikipedia
interface Image {
public void displayImage();
}
//on System A
class RealImage implements Image {
private String filename = null;
/**
* Constructor
* #param filename
*/
public RealImage(final String filename) {
this.filename = filename;
loadImageFromDisk();
}
/**
* Loads the image from the disk
*/
private void loadImageFromDisk() {
System.out.println("Loading " + filename);
}
/**
* Displays the image
*/
public void displayImage() {
System.out.println("Displaying " + filename);
}
}
//on System B
class ProxyImage implements Image {
private RealImage image = null;
private String filename = null;
/**
* Constructor
* #param filename
*/
public ProxyImage(final String filename) {
this.filename = filename;
}
/**
* Displays the image
*/
public void displayImage() {
if (image == null) {
image = new RealImage(filename);
}
image.displayImage();
}
}
class ProxyExample {
/**
* Test method
*/
public static void main(String[] args) {
final Image IMAGE1 = new ProxyImage("HiRes_10MB_Photo1");
final Image IMAGE2 = new ProxyImage("HiRes_10MB_Photo2");
IMAGE1.displayImage(); // loading necessary
IMAGE1.displayImage(); // loading unnecessary
IMAGE2.displayImage(); // loading necessary
IMAGE2.displayImage(); // loading unnecessary
IMAGE1.displayImage(); // loading unnecessary
}
}
In this example they said loading is unnecessary for second time of dispalyImage. Even it is possible in directly accessing the RealImage object too.
final Image IMAGE1 = new RealImage("HiRes_10MB_Photo1");
final Image IMAGE2 = new RealImage("HiRes_10MB_Photo2");
IMAGE1.displayImage(); // loading necessary
IMAGE1.displayImage(); // loading unnecessary
IMAGE2.displayImage(); // loading necessary
IMAGE2.displayImage(); // loading unnecessary
IMAGE1.displayImage(); // loading unnecessary
I need to understand the usage of the ProxyImage class in this pattern.
You know, I agree with you. I feel like there's a much better example they could have used for the proxy pattern. This seems to use the same example but it's explained much better. You should look at that instead.
Basically, it all comes down to this comment:
// create the Image Object only when the image is required to be shown
That is the benefit the proxy gives you in this example. If you don't display the image, you don't pay the penalty of loading it:
package proxy;
/**
* Image Viewer program
*/
public class ImageViewer {
public static void main(String[] args) {
// assuming that the user selects a folder that has 3 images
//create the 3 images
Image highResolutionImage1 = new ImageProxy("sample/veryHighResPhoto1.jpeg");
Image highResolutionImage2 = new ImageProxy("sample/veryHighResPhoto2.jpeg");
Image highResolutionImage3 = new ImageProxy("sample/veryHighResPhoto3.jpeg");
// assume that the user clicks on Image one item in a list
// this would cause the program to call showImage() for that image only
// note that in this case only image one was loaded into memory
highResolutionImage1.showImage();
// consider using the high resolution image object directly
Image highResolutionImageNoProxy1 = new HighResolutionImage("sample/veryHighResPhoto1.jpeg");
Image highResolutionImageNoProxy2 = new HighResolutionImage("sample/veryHighResPhoto2.jpeg");
Image highResolutionImageBoProxy3 = new HighResolutionImage("sample/veryHighResPhoto3.jpeg");
// assume that the user selects image two item from images list
highResolutionImageNoProxy2.showImage();
// note that in this case all images have been loaded into memory
// and not all have been actually displayed
// this is a waste of memory resources
}
}
Proxy means ‘in place of’, representing’ or the authority to represent someone else, or a figure that can be used to represent the value of something.
Proxy design pattern is also called surrogate, handle, and wrapper.
It is used when we want to create a wrapper to cover the main object's complexity from the client.
Some real world examples of Proxy Design Pattern:
A bank's cheque or credit card is a proxy for what is in our bank account. It can be used in place of cash, and provides a means of accessing that cash when required. And that’s exactly what the Proxy pattern does – “Controls and manage access to the object they are protecting“.
A company or corporate used to have a proxy which restricts few site access. The proxy first checks the host you are connecting to, if it is not a part of restricted site list, then it connects to the real internet.

How to: Make addition to class property within list

I have a List<Presenter> presenterList;
With
public class Presenter(){
String name;
String imageRef; // Filename to be downloaded
Bitmap image;
(etc...)
}
I'm working with AsyncTask & once the image has downloaded, I wish to go through the list and set Image value to the newly download image.
so far i have
Presenter pres = PresenterList.get(Position);
pres.Image = new (Bitmap) downloadedImageFromImageRef;
however i fear that this will not relate to the Image value of the presenter within the list.
How do i refer, or even assign to the specific Presenter attribute within the list?
From working with C (many years ago), i belive somthing like a pointer to the value in which to assign .Image would work
Thank you in advace
Well, if you have C experience, then the thing to know about Java is that it doesn't use pointers, but it does use references. So if I'm understanding your problem correctly, you are already using the Image attribute of a Presenter instance elsewhere and then you want to fill it in later. Assigning pres.Image = new (Bitmap) DownloadedImageFromImageRef; would not work in this case because other objects are looking at a different Bitmap object reference.
What you might need to do is use an observer pattern -- it depends on the details of your problem. Here's an example:
Somewhere in the code I have a class Foo that wants to use the Image property from a Presenter instance. But, since that property isn't set until later, this class wants to be notified when it is ready (it is an observer).
public class Presenter {
String Name;
String ImageRef; // Filename to be downloaded
private Bitmap Image;
private PresenterImageObserver observer;
public void setImageObeserver(PresenterImageObserver pio) {
this.observer = pio;
}
public void setImage(Bitmap b) {
this.Image = b;
this.observer.imageLoaded(b);
}
}
public interface PresenterImageObserver {
public void imageLoaded(Bitmap b);
}
public class Foo implements PresenterImageObserver {
//Foo's constructor. It wants the image from presenter p, when it is ready
public Foo(Presenter p) {
p.setImageObserver(this);
}
public void imageLoaded(Bitmap b) {
//b contains the loaded image and this Foo instance can use it now!
}
}
You'd need to set the image using pres.setImage(new (Bitmap) downloadedImageFromImageRef);.
So you have to find in your list the Presenter for which the correct imageref. You have basically two options.
First, you simply iterate through your list
for (Presenter presenter: presenterList) {
if (presenter.imageref.equals(imageName) {
Presenter.image = new Bitmap(downloadedImage);
break; // found : stop iterations
}
}
Secondly, you can create a HashMap for your presenters, with the imageref as the key :
HashMap<String, Presenter> map = new HashMap<>();
for (Presenter presenter: presenterList) {
map.put(presenter.imageref, presenter);
}
Then, you can directly find the right presenter through map.get(imageName)

How to pass a custom class between Activities

I found many simple solutions to this (such as Intent.putExtra(String, String) and Bundle.putString(String, String)), but this is not helpful for my situation.
I have a class called MyMP3 which contains non-primitive types. I need to pass the following for MyMP3...
private AudioFile audioFile;
private Tag tag;
private int index;
private boolean saved, startedWithLyrics;
private String id3lyrics;
AudioFile and Tag are both classes that I imported from a .jar file. How can I go about passing these to another Activity via Intents? I tried messing with implementing Parcelable for my "MyMP3" class, but I am not sure how to correctly use these methods when not passing primitive types.
Could you help me out and look at my code below and try to tell me how to correctly use Parcelable with a custom class like mine? How do I set the Parcel in the writeToParcel function and how do I correctly retrieve the class in another Activity?
Below is my code (the part that is important, at least). I've been trying different things for a couple of days now, but I cannot get it to work. Please help me out!
public class MyMP3 extends AudioFile implements Parcelable
{
private AudioFile audioFile;
private Tag tag;
private int index;
private boolean saved, startedWithLyrics;
private String id3lyrics;
public MyMP3(File f, int index)
{
this.audioFile = AudioFileIO.read(f);
this.tag = this.audioFile.getTag();
this.index = index;
this.saved = false;
this.id3lyrics = getLyrics();
}
#Override
public int describeContents()
{
return 0;
}
#Override
public void writeToParcel(Parcel out, int flats)
{
/* This method does not work, but I do not know how else to implement it */
Object objects[] = {this.audioFile, this.tag, this.index, this.saved, this.startedWithLyrics, this.id3lyrics};
out.writeArray(objects);
}
public static final Parcelable.Creator<MyMP3> CREATOR = new Parcelable.Creator<MyMP3>()
{
public MyMP3 createFromParcel(Parcel in)
{
/* Taken from the Android Developer website */
return new MyMP3(in);
}
public MyMP3[] newArray(int size)
{
/* Taken from the Android Developer website */
return new MyMP3[size];
}
};
private MyMP3(Parcel in)
{
/* This method probable needs changed as well */
Object objects[] = in.readArray(MyMP3.class.getClassLoader());
}
}
You can make your MyMP3 class Parcelable like that. Make sure you get the read/write order correct. The non-primitives must also be Parcelable, so you might not have control over that unfortunately. Alternatively, you could come up with your own serialization/deserialization. You could use a text format, like JSON or XML. Another alternative is to use subclass Application (make sure you declare it in your manifest) and use it is as a place to hang objects that span Activities. This keeps the object in memory for the lifecycle of your app, so be careful with doing this.

Categories