I have an imageview that has its imageresource set programatically. This image could have had its resource set by any of 3 drawables, which is chosen using various variables earlier in the class.
The 3 drawables are:
R.drawable.well_done
R.drawable.try_again
R.drawable.sorry_failed
When I click on this image, it could have any of these three drawables set to it, so I'm trying to run a method something along the lines of this (I know this is totally wrong, but it might help visualise what I'm trying to do)
public void game(){
//STUFF
if(result>10){
imgView.setImageResource(R.drawable.well_done);}
//MORE STUFF
}
public void results_page(){
if(imgView=R.drawable.well_done){
//DO STUFF
}
if(imgView=R.drawable.try_again){
//DO STUFF
}
//etc...
}
Here is the proper code I have. Its a little more complex than my rubbish visualisation above, but I hope you understand what I'm trying to do.
ImageView iv_i;
//...
...onCreate(Bundle savedInstanceState){
//...
result1.setOnClickListener(onClL);
result2.setOnClickListener(onClL);
}
private void game() {
//...
result1.setImageResource(R.drawable.well_done);
result1.setTag(R.drawale.well_done)
result2.setImageResource(R.drawable.try_again);
result2.setTag(R.drawable.try_again);
//...
}
private OnClickListener onClL = new OnClickListener() {
#Override
public void onClick(View v) {
switch(v.getId()){
case R.id.result1:
ic_i = result1;
iv_i.setTag(result1.getTag());
break;
case R.id.result2:
iv_i = result2;
ic_i.setTag(result2.getTag());
break;
}
gotoResource();
}
};
private void gotoResource(){
Integer integer = (Integer) iv_i.getTag();
switch(integer){
case R.drawable.well_done:
//STUFF
break;
case R.drawable.try_again:
//STUFF
break;
case R.drawable.sorry:
//STUFF
break;
}
}
When I run this, I get a nullpointerexception at the line containing iv_i.setTag(result1.getTag());
What did i go wrong? Or how do I go about doing this properly, or another way of doing it that would be easier? Maybe converting the drawable to a string, then doing an if statement for the string, like: (also know this is completely wrong, but its just for a visualisation)
String resource = imgView.getDrawable().toString();
if(resource.equals("R.drawable.well_done")){
//DO SOMETHING
}
Thanks
Instead of relying upon the exact drawable the ImageView has, I suggest setting a tag on the ImageView to indicate which state it's in. I recently used this approach on a similar issue (determining whether a button is active or not), and it works well for me.
private static enum MessageViewType { SUCCESS, TRY_AGAIN, FAILURE }
public void game(){
//STUFF
if (result > 10){
imgView.setImageResource(R.drawable.well_done);}
imgView.setTag(R.id.image_view_status, MessageViewType.SUCCESS); // define image_view_status as a resource
}
//MORE STUFF
}
...
private void gotoResource(){
MessageViewType messageType = (MessageViewType) iv_i.getTag(R.id.image_view_status);
if (messageType == MessageViewType.SUCCESS) {
//STUFF
} else if (messageType == MessageViewType.TRY_AGAIN) {
// STUFF
} else if (messageType == MessageViewType.FAILURE) {
//STUFF
}
}
You can define the image_view_status id in any resource file. I personally use a file res > values > activity_resources.xml as follows:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="image_view_status" type="id" />
</resources>
Related
I have a project that use Android to display Unity Player. So I export Untiy project as Android module which implemented by Android Application.
I create buttons in Android Activity which contains UnityPlayer, And when I click button, it send a message to Unity Player to invoke C# function, just like this:
findViewById(R.id.btnChange).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mUnityPlayer.UnitySendMessage("ScriptHolder", "ChangeSkin", "");
}
});
And the function named "ChangeSkin" is just to change some GameObjects' active. Just like this:
void ChangeSkin()
{
int prefab;
if (_currentPrefab == PREFAB_DEFAULT)
{
prefab = PREFAB_PRINCESS;
}
else
{
prefab = PREFAB_DEFAULT;
}
ShowSkin(prefab);
}
private void ShowSkin(int prefab)
{
_currentPrefab = prefab;
foreach (var item in _defaultDressList)
{
item.SetActive(prefab == PREFAB_DEFAULT);
}
foreach (var item in _princessDressList)
{
item.SetActive(prefab == PREFAB_PRINCESS);
}
}
And something weird happening: when I click button to change the person's cloth in Unity, the GameObjects which called SetActive(true) show at the position above the right position for a frame and become normal, it looks like they flash. Here is the gif of the project demo:
It looks like the position offset is equal to the height of status bar. If I create a button on Unity Scene and call "ChangeSkin" function, everything will be OK.
I tried all I can to fix this but not succeed. So I hope you will help me, thx.
You should check your Unity layout. If you have a layout group that has content size fitter component, and the child objects also have it (content size fitter), this could cause these glitches.
I fixed this problem by using a flag (or trigger). Just like this:
// set value true to trigger ChangeSkin() in Update(),
// instead of invoke ChangeSkin() directly
private bool _changingSkinTrigger = false;
void ChangeSkin()
{
if (_currentPrefab == PREFAB_DEFAULT)
{
_currentPrefab = PREFAB_PRINCESS;
}
else
{
_currentPrefab = PREFAB_DEFAULT;
}
_changingSkinTrigger = true;
}
void Update()
{
if (_changingSkinTrigger)
{
_changingSkinTrigger = false;
ShowSkin();
}
}
private void ShowSkin()
{
foreach (var item in _defaultDressList)
{
item.SetActive(_currentPrefab == PREFAB_DEFAULT);
}
foreach (var item in _princessDressList)
{
item.SetActive(_currentPrefab == PREFAB_PRINCESS);
}
}
Thank #AndriyMarshalek for enlightening me.
I am creating some buttons programatically, I am adding the buttons this way:
final Button btn = new Button(this);
btn.setText(array.get(i));
btn.setTextSize(10);
btn.setTextColor(getColor(R.color.white));
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
goToModule(texto);
}
});
btn.setHeight(height);
btn.setWidth(width);
btn.setOnTouchListener(parentListener);
btn.post(new Runnable() {
#Override
public void run() {
btn.setCompoundDrawablesWithIntrinsicBounds(null,getDrawableForText(texto),null, null);
btn.setPadding(0,35,0,0);
btn.setBackground(gd);
btn.setLayoutParams(params);
}
});
row1.addView(btn);
Up to 19 buttons can be drawn. They are inside a ViewFlippers, so the user can page between pages
The getDrawableForText method:
private Drawable getDrawableForText(String texto) {
Drawable drawable=null;
if(texto.equalsIgnoreCase("Viajes")){
Log.i("LOG", "This drawable is the problematic one");
}
if (texto.equals(textosBotones[0])) {
drawable=getResources().getDrawable(R.drawable.vuelo,getTheme());//Viajes
} else if (texto.equals(textosBotones[1])) {
drawable=getResources().getDrawable(R.drawable.hotel,getTheme());//Hotel
} else if (texto.equals(textosBotones[2])) {
drawable=getResources().getDrawable(R.drawable.agenda,getTheme());//Agenda
/*int h = btn.getHeight()-100;
int w = btn.getWidth()-100;
drawable.setBounds( 0, 0, w, h );
Bitmap icon= BitmapFactory.decodeResource(getResources(),R.drawable.agenda);
Bitmap newbitMap = Bitmap.createScaledBitmap(icon,w,h, true);
dr = new BitmapDrawable(EventActivity.this.getResources(), newbitMap);*/
} else if (texto.equals(textosBotones[3])) {
drawable=getResources().getDrawable(R.drawable.ponentes,getTheme());//Ponentes
} else if (texto.equals(textosBotones[4])) {
drawable=getResources().getDrawable(R.drawable.documentos,getTheme());//Documentos
} else if (texto.equals(textosBotones[5])) {
drawable=getResources().getDrawable(R.drawable.ubicacion,getTheme());//Ubicaciones
} else if (texto.equals(textosBotones[6])) {
drawable=getResources().getDrawable(R.drawable.contactos,getTheme());//Contactos
} else if (texto.equals(textosBotones[7])) {
//drawable=getResources().getDrawable(R.drawable.preguntas,getTheme());//Encuestas
drawable=getResources().getDrawable(R.drawable.valoracion,getTheme());//Encuestas/valoraciones
} else if (texto.equals(textosBotones[8])) {
drawable=getResources().getDrawable(R.drawable.qr,getTheme());//Distintivo/best business
} else if (texto.equals(textosBotones[9])) {
drawable=getResources().getDrawable(R.drawable.info,getTheme());//Forum
} else if (texto.equals(textosBotones[10])) {
drawable=getResources().getDrawable(R.drawable.galeria,getTheme());//GalerĂa
} else if (texto.equals(textosBotones[11])) {
drawable=getResources().getDrawable(R.drawable.chat,getTheme());//Chats
} else if (texto.equals(textosBotones[12])) {
drawable=getResources().getDrawable(R.drawable.muro,getTheme());//Muro
} else if (texto.equals(textosBotones[13])) {
drawable=getResources().getDrawable(R.drawable.asistentes,getTheme());//Asistentes
} else if (texto.equals(textosBotones[14])) {
drawable=getResources().getDrawable(R.drawable.twitter,getTheme());//Twitter
} else if (texto.equals(textosBotones[15])) {
drawable=getResources().getDrawable(R.drawable.twitter,getTheme());//Facebook
} else if (texto.equals(textosBotones[16])) {
drawable=getResources().getDrawable(R.drawable.twitter,getTheme());//Instagram
} else if (texto.equals(textosBotones[17])) {
drawable=getResources().getDrawable(R.drawable.qr,getTheme());//QR
} else if (texto.equals(textosBotones[18])) {
drawable=getResources().getDrawable(R.drawable.valoracion,getTheme());//Proveedores
} else if (texto.equals(textosBotones[19])){
/*drawable = DrawableCompat.wrap(getResources().getDrawable(R.drawable.trophy,getTheme()));
DrawableCompat.setTint(drawable, getColor(R.color.white));*/
/*drawable=getResources().getDrawable(R.drawable.trophy,getTheme());
Drawable wrappedDrawable = DrawableCompat.wrap(drawable);
DrawableCompat.setTint(wrappedDrawable, getColor(R.color.white));
drawable=wrappedDrawable;*/
drawable=getResources().getDrawable(R.drawable.actividad, getTheme());//Actividades
}else if(texto.equals(textosBotones[20])){
drawable=getResources().getDrawable(R.drawable.noticias,getTheme());
}else{
Log.i("LOG", "Something weird happened");
}
return drawable;
}
The first time I enter this Activity, the drawable is drawn correctly. BUT, if I click one of the buttons (which goes to another Activity), and inside that new Activity, I click on a Button that goes to a third Activity, if I go back to the main Activity(where the buttons are) there is one drawable that is not drawn, its always the same, the first one. Th rest of the drawable of the rest of the buttons are drawn ok.
The main Activity is not recreated again, it remains in memory. Anyway, if I draw it again, the same weird behaviour happens.
I am pretty lost, since the third Activity is not affectin the first one in any way.
Someone could guide me about what is happening?
Thank you.
PD: If you need further details, please let me know.
EDIT:
In third Activity, I am doing something like this:
private void getArrivalsFromJSON(String resp) {
arrivals=new ArrayList<>();
ArrivalModel all=new ArrivalModel();
all.setDestination("");
all.setTerminal("ALTTODO");
all.setType("");
arrivals.add(all);
try {
JSONObject json=new JSONObject(resp);
JSONArray data=json.getJSONArray("data");
for(int i=0;i<data.length();i++){
JSONObject obj=data.getJSONObject(i);
ArrivalModel arrival=new ArrivalModel();
arrival.setDestination(obj.getString("destination"));
arrival.setTerminal(obj.getString("terminal"));
arrival.setType(obj.getString("type"));
arrivals.add(arrival);
}
generateLayout();
} catch (JSONException e) {
e.printStackTrace();
}
}
In thath for, if I modify the line:
for(int i=0;i<data.length();i++)
and change it like this:
for(int i=0;i<data.length()-7;i++)
The button drawable it is drawn normally! I have checked in the Android Studio profiler, and it is never using more than 90Mb of RAM. It is too much?
I found the error. Was not related with memory, or other performance issues.
What was happening is, in the third Activity I was using the same .png I was using in the button, but I was changing its color:
d.setColorFilter(new PorterDuffColorFilter(Color.parseColor(color), PorterDuff.Mode.MULTIPLY));
So, when I was going back to the first Activity, and tried to draw the Drawable, it was drawing, but with its color changed. Given that the button color, and the color I was changing the drawable with was the same, it appeared that the drawable was not being drawn; it fact it was being drawn, but was not visible.
I am trying to set Imageview using a function
that if we send Image drawable to a function that function set that drawable to the respective Imageview.
This is function code in which it gets "id" and after that respective id function will call
public void showpeg(int id) {
switch (id) {
case 1:
showSeagreen(R.drawable.seagreen);
break;
}
}
This is my ShowSeagreen() function
public void showSeagreen(Drawable draw) {
if (iRow == 1) {
if (iPlace == 1) {
seagreen = 1;
one_first.setBackgroundResource(R.drawable.draw);
iPlace++;
} else if (iPlace == 2) {
seagreen = 2;
one_two.setBackgroundResource(R.drawable.draw);
iPlace++;
}
}
I know i am doing it wrong but i can't find a way to do this Please any help
Thanks in advance
instead of
showSeagreen(R.drawable.seagreen);
use:
showSeagreen(getResources().getDrawable(R.drawable.seagreen));
Any Resources is a int.
Do like this to "showSeagreen":
public void showSeagreen(int draw) {
if (iRow == 1) {
if (iPlace == 1) {
seagreen = 1;
one_first.setBackgroundResource(draw);
iPlace++;
} else if (iPlace == 2) {
seagreen = 2;
one_two.setBackgroundResource(draw);
iPlace++;
}
}
If what i understand from your question is true then i think your aim is to add drawable image as a parameter if thats what you want
then you should add the
#DrawableRes int draw
like
public void showSeagreen(#DrawableRes int draw) {
}
as your parameter then you can add drawable files in here
I have an application about pmt function. However there are so many conditions that need to be handled. Somehow the app will not work with having more than 12 if-else. I want to use switch case, but i still not really understand how to use switch case(been 1 and half month since my 1st try using eclipse).Any example will be highly appreciated.
here is my example code:
if(String1.toString().equals("condition1")){
//do something
if(String2.toString().equals("condition1.1")&& String3.toString().equals("condition1.2")){
//do something else
}
.
.
.
.
.
if(String2.toString().equals("condition1.##")&& String3.toString().equals("condition1.##")){
//do something else
}
}
else if(String1.toString().equals("condition2")){
//do something
if(String2.toString().equals("condition2.1")&& String3.toString().equals("condition2.2")){
//do something else
}
.
.
.
.
.
if(String2.toString().equals("condition2.##")&& String3.toString().equals("condition2.##")){
//do something else
}
}
if(String1.toString().equals("condition3")){
//do something
if(String2.toString().equals("condition3.1")&& String3.toString().equals("condition3.2")){
//do something else
}
.
.
.
.
.
if(String2.toString().equals("condition3.##")&& String3.toString().equals("condition3.##")){
//do something else
}
}
and still keep going....to handle all possibilities .I am wondering, How to do this in switch case . Or a better implementation if we have 3 times 3 conditions. For example a,b,c(suppose these three conditions can only be used once) and d,e,f and g,h,i then condition 1 is a,d,g ; condition 2 is a,d,h condition 3 is a,d,i ; condition 4 a,e,g........on so on
Note:Suppose that the API version is 8-11 (old android)
thanks
The answer is dependent on your target version of android. From KitKat and upwards (API Level 19+), Java 7's switch (String) is available. I'd also strongly suggest trying to group the subcases (condition n.x) into different methods. It just gets very unwieldly quickly, otherwise:
switch (String1.toString) {
case "condition1":
handleCase1(String2, String3);
break;
case "condition2":
handleCase2(String2, String3);
break;
}
If that still results in too complex code, you can try a lookup table together with a command pattern:
class ConditionKey {
final String String1;
final String String2;
final String String3;
public int hashCode(); // hash strings
public boolean equals(); // compare strings
}
interface ConditionCommand {
// use whatever arguments the operation needs, you can also
// add fields and initialize in the constructor
void perform(final ConditionKey key, /* [...] */);
}
Map<ConditionKey, ConditionCommand> actionMap = new HashMap<>();
actionMap.put(
new ConditionKey("condition1", "condition1.1", "condition1.2"),
new ConditionCommand() {
void perform(final ConditionKey key) {
// perform actions that need to be done
}
}
);
And then instead of the if-else or switch-case:
[...]
ConditionKey key = new ConditionKey(string1, string2, string3);
// get the action from the map
ConditionCommand command = actionMap.get(key);
// perform the command
command.perform(key);
since java 1.7 switch on string is supported.
you could annidate two switch:
switch(String1) {
case "condition1": {
switch(String2) {
case "condition1.1":
break;
// ... other cases
default:
break;
}
}
break;
// ... other cases
default break;
}
I'm generating a question and answers of that randomly. And I want to generate new random arrays and answer options according to those when users chose the correct answer. But it says "unreachable code" when I add a boolean while loop... What is theproblem?
Thanks...
final boolean basadon = false;
while(basadon)
{
Random soru = new Random();
final int[] rastgele = new int[1];
for (int i=0; i<1; i++)
{
rastgele[i]= soru.nextInt(8);
}
ArrayList<Integer> cevap = new ArrayList<Integer>();
for (int k = 0; k <= 7; ++k)
{
cevap.add(k);
}
final Integer[] rastgele2 = new Integer[4];
if (rastgele[0]!=cevap.get(0))
{
rastgele2[0]=cevap.get(0);
}
else
{
rastgele2[0]=cevap.get(3);
}
if (rastgele[0]!=cevap.get(1))
{
rastgele2[1]=cevap.get(1);
}
else
{
rastgele2[1]=cevap.get(3);
}
if (rastgele[0]!=cevap.get(2))
{
rastgele2[2]=cevap.get(2);
}
else
{
rastgele2[2]=cevap.get(3);
}
rastgele2[3]=rastgele[0];
Collections.shuffle(Arrays.asList(rastgele2));
view.setText(countries.get(rastgele[0]));
cevap1.setBackgroundResource(heads[rastgele2[0]]);
cevap1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (rastgele[0]==rastgele2[0])
{
cevap1.setBackgroundResource(heads[8]);
countries.remove(rastgele[0]);
basadon=true;
}
else {
cevap1.setBackgroundResource(heads[9]);
}
}
});
cevap2.setBackgroundResource(heads[rastgele2[1]]);
cevap2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (rastgele2[1]==rastgele[0])
{
cevap2.setBackgroundResource(heads[8]);
countries.remove(rastgele[0]);
basadon=true;
}
else {
cevap2.setBackgroundResource(heads[9]);
}
}
});
cevap3.setBackgroundResource(heads[rastgele2[2]]);
cevap3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (rastgele2[2]==rastgele[0])
{
cevap3.setBackgroundResource(heads[8]);
countries.remove(rastgele[0]);
basadon=true;
}
else {
cevap3.setBackgroundResource(heads[9]);
}
}
});
cevap4.setBackgroundResource(heads[rastgele2[3]]);
cevap4.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (rastgele2[3]==rastgele[0])
{
cevap4.setBackgroundResource(heads[8]);
countries.remove(rastgele[0]);
basadon=true;
}
else {
cevap4.setBackgroundResource(heads[9]);
}
}
});
}
} }
Looks like you start with basedon value as false and later set it to true inside the loop.
So, Change
final boolean basedon = false
while (basedon) {
....
}
to
boolean basedon = false;
do {
....
} while (basedon);
while(basadon) is always false, so you never enter the loop. What you really mean is probably while(basadon==false). Also, don't declare basalon as final boolean because you want to modify its value later, and that will give error.
Why are you declaring all of those variables as final?
If bsadon for example needs to change from false to true, it can't be final. A final value is exactly that, a constant, it won't change.
Don't declare something as final unless you want it to keep the same value for the entire runtime of your program.
You are saying basadon is always "false", that's what final means, so the compiler is telling you you will never enter the while, since you need it to evaluate "true" to enter.
The expression between () in you while clause, needs to evaluate to true for the code to enter.
To your specific question which you have asked:
Why does the compiler give unreachable code warning
The answer is that since the condition in while loop is always false, there is no chance that the code in while loop will get executed. The warning is given to indicate that (given the current code situation) you have wasted your effort in typing that portion of code and it is guaranteed never to be executed. To rectify this, you can remove the final modifier from basedon and put a programming logic to set the value of basedon which will decide whether to enter the loop or not. If you want the loop to always run put while(true).
But I believe that what you wanted to ask was how to make the random question and answer generator. For that you'll have to post a bigger chunk of your code (It looks like you are trying to put a loop over a listener callback ?) and phrase your question to ask specific problems (possibly post a separate question).
It's probably complaining because basadon is known to be false and the body of the while loop cannot be reached. You can suppress the complaint by adding this annotation to the method:
#SuppressWarnings("unused")
You might also try removing the final modifier from the declaration of basadon. That might resolve the issue (but I'm not sure about that).
EDIT I finally noticed that you are trying to modify basadon directly from within your click listeners. That obviously won't work if basadon is final, yet you cannot access local variable unless it is final. I suggest you change basadon to be a (non-final) field of the enclosing class. Then all the warnings and errors should go away.