I have GridLayout with a CardView inside. I want to create an Intent to 4 different activities. I only can execute one Intent. I do not know if I should use Else If or case. Thanks for your help. Here is my code.
GridLayout mainGrid;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dashboard);
mainGrid = (GridLayout)findViewById(R.id.grid);
setSingleEvent(mainGrid);
}
private void setSingleEvent(GridLayout mainGrid) {
for (int i=0;i<mainGrid.getChildCount();1++)
{
CardView cardView = (CardView)mainGrid.getChildAt(i);
final int final1= i;
cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent i=new Intent(DashboardActivity.this,MapsActivity.class);
startActivity(i);
}
});
}
}
I think your problem comes from a lack of understanding how the order of execution of the program works. If you insert a cycle for and then you put inside an anonymous class as it is the case of View.onViewClickListener is normal that you will have only one result, because you break the for cycle.
The way to go should be to not use a for cycle, but assigning different Explicit Intents depending by what you want to obtain.
EDIT. On the base of your use case you need to trigger the Intent from the Adapter. Please see here and mainly here, basically you need to use the Android SDK functionality that tells you which card has been clicked mRecyclerView.getChildLayoutPosition(view); then depending from your needs you may (or not) pass a switch case for educational purposes, although possibly is not the most elegant and efficient way to solve.
If you want a different Activity to be started depending on what CardView is clicked try something like the following:
private void setSingleEvent(GridLayout mainGrid) {
mainGrid.getChildAt(0).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startActivity(i);
}
});
mainGrid.getChildAt(1).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startActivity(i);
}
});
//do this for all 4 cardViews.
}
In short: set all Intents separately.
Related
There is a scenario in which i need to pass activity and its button to a java class.
I did following and its working fine, I am only concerned if its the right way of integrating this.
MainActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button= findViewById(R.id.btn);
UIComponents uiComponents= new UIComponents();
uiComponents.setActivity(this, button);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d("result", String.valueOf(requestCode));
}
UIComponents.class
public class UIComponents {
public void setActivity(final AppCompatActivity activity, Button btn){
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent= new Intent(activity, ResultActivity.class);
activity.startActivityForResult(intent, 999);
}
});
}
This works perfectly fine, It displays toast message on my activity screen, also i am able to receive onActivityResult callback on my activity. I am concerned if this can lead to any performance related issues.
you can just pass only the Button and use the getContext method available e.g
public class UIComponents {
public void setActivity(Button btn){
Context activity = btn.getContext();
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent= new Intent(activity, ResultActivity.class);
activity.startActivityForResult(intent, 999);
}
});
}
The most important thing to consider here is the lifecycle of your components. In general you shouldn't pass a reference to an activity to any object which might outlive it. In theory (probably very rear), your activity might be killed between the time the user clicks the button and the time the OnClickListener (if it wasn't garbage collected yet) will be executed and you'll get a NullPointerException. Also, you might pass (even accidentally) UIComponents to some other object with a different lifecycle.
Best practice in such a case is usually using MVP architecture. The specific case of handling button clicks is described here among other places.
In addition, following the "Guide to App Architecture" by Google is probably a good idea.
this is my first question being asked on stackoverflow. My question is regarding variable use across different recyclable intents.
e is declared like this.
final Bundle e=getIntent().getExtras();
Here i am creating new intents for different setOnClickListener() and passing a different variable for each intent.
Intent info = new Intent(EItemListView.this, ItemInfo.class);
Bundle extras = new Bundle();
int[] a=new int[listview.getAdapter().getCount()];
if (i == 0) {
extras.putIntArray("img", n5x_images);
extras.putString("info", n5x_info);
extras.putInt("pc",a[0]);
} else if (i == 1) {
extras.putIntArray("img", op3_images);
extras.putString("info", op3_info);
extras.putInt("pc",a[1]);
}
info.putExtras(extras);
startActivity(info);
Now this is the OnClickListener() where i am trying to update the variables which i passed through the intent extras, but am unable to update those variables.
addtc.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int c=e.getInt("pc");
c=c+1;
Log.i("Log","value "+c);
}
The log message which i get from the above method is always 1, i think the variable in c is always set to 0 and then increments by 1 and hence the log message shows 1.
I need the variables a[0],a[1],a[2], etc to pertain its increment operation.
To make it more clear, this is the java file i am using. The error is in the OnClickListener of addtc button at the bottom of this code.
public class ItemInfo extends AppCompatActivity {
private ViewAnimator viewanimator;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item_info);
Button next=(Button)findViewById(R.id.bnext);
Button prev=(Button)findViewById(R.id.bprev);
viewanimator=(ViewAnimator)findViewById(R.id.viewAnimator);
TextView info=(TextView)findViewById(R.id.item_info);
Button addtc=(Button)findViewById(R.id.badd);
Button test=(Button)findViewById(R.id.button);
Bundle e=getIntent().getExtras();
int img[]=e.getIntArray("img");
for(int i=0;i<img.length;i++)
{
ImageView imgview = new ImageView(getApplicationContext());
imgview.setImageResource(img[i]);
viewanimator.addView(imgview);
}
info.setText(e.getString("info"));
next.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
viewanimator.showNext();
}
});
prev.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
viewanimator.showPrevious();
}
});
addtc.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int c=e.getInt("pc");
c=c++;
Log.i("Log","value "+c);
}
});
}
}
Thanks in advance!!!
Your approach is wrong. You cannot do this in this way. Your understanding of what an "extra" in an Intent is incorrect.
When you do this:
extras.putInt("pc",a[1]);
This adds an "extra" to the extras Bundle. The Bundle is simply a key/value pair map and you have added an entry that contains the key "pc" and the value is whatever a[1] is. It puts a copy of the value of a[1] into the Bundle, it does not put a reference to a[1] in the Bundle.
Therefore, if a[1] is 5 when you add it to the extras Bundle, a[1] will always be 5 and will never be changed to anything else.
You can't do this in this way.
Alternative: Depending on your application architecture and what you are trying to do, you can use one of the following methods:
1) Use startActivityForResult(), pass the data from one Activity to another, have the second Activity update the data and put it back into the Intent which is then returned to the "calling" Activity by using setResult().
2) Use a static variable (basically a "global" variable) to contain the data. Both activities can then access the data directly (you don't need to put the data in the Intent.
3) Put the data in a database. Both activities can then read/write from/to the database.
First advice I can give you is debugging and posting debug result. for example, are you sure that a[0] and a[1] aren't 0?
Assuming they are not, why are you declaring the bundle as final? referring to this probably final is not what you were looking for. Try removing it or replacing with private
Another suggestion is more for readable purpose, replace c = c+1; with c++; but this doesn't change the result, it just make it more linear and easier for reading.
Now after this fix (the final keyword one) tell me if something changed please :)
Is this generally a good practice to adopt?
I am working through the tutorials and got to the part where button listeners are being implemented:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_quiz);
mTrueButton = (Button) findViewById(R.id.true_button);
//and here is the anonymous inner class
mTrueButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
}
Am I better off learning this style or is there another way I should be learning this for the sake of good practice? It seems a little counter to my basic understanding of OOP where things seem to be... separated and modularized, if that makes sense.
Yes, there is another way that I often prefer (especially in big projects), your class can implement listeners
So your Activity/Fragment can be declared this way
public class MyActivity implements View.OnClickListener{
and your view object, button in this case, would set it's listener this way
mTrueButton.setOnClickListener(this)
and then you would have another class called onClick() where ALL of your clickable view elements can now have their code
#Override
public void onClick(View v){
switch(v.getId()){
case R.id.true_button:
break;
}
}
the question is as above.
scenario : i programmatically created table rows with text view in it. i wanted to allow text-to-speech when i clicked on the textview. there is some reason for not using listview. i tried to use button for easier usage, however the button that i created is always out of the dimension that gave. so, i wanted to use textview to activate the TTS.
how do i do that ?
i tried using
tv.setOnClickListener(new OnClickListener()
{
public void OnClick(View v)
{
String speech = list.get(i).toString();
tts.speak(speech,TextToSpeech.QUEUE_FLUSH,null);
}
});
i uses for-loop for it, so that it will create a table row for every data collected. the problem is, it requested the "i" to be final. and when i made it final, i cant use i++.
please help. thanks alot =)
Try to declare your int i; in your class. I believe this will help you to avoid of using final modifier.
public class MyActivity extends Activity {
int i;
public void onCreate(Bundle savedInstanceState) {
...
tv.setOnClickListener(new OnClickListener()
{
public void OnClick(View v){
String speech = list.get(i).toString();
tts.speak(speech,TextToSpeech.QUEUE_FLUSH,null);
}
});
...
}
}
or put this code String speech = list.get(i).toString();
tts.speak(speech,TextToSpeech.QUEUE_FLUSH,null); to another method. for example:
tv.setOnClickListener(new OnClickListener()
{
public void OnClick(View v){
speak();
}
});
__
public void speak(){
String speech = list.get(i).toString();
tts.speak(speech,TextToSpeech.QUEUE_FLUSH,null);
}
Alright, so i've been making great progress on the app i'm trying to create, but most of the tutorials that i've been learning from only showcase the wondrous feature of having only one active widget inside the application at a time...
The thing is, my application requires 2 or more buttons and that's the part i'm partially stuck at. My code implements a "SetWordsBtn" shown below (everything else is declared),
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
SetWordsBtn=(Button)findViewById(R.id.SetWordsBtn);
SetWordsBtn.setOnClickListener(this);
}
which implements a onClick() like this:
public void onClick(View view) {
startWords();
}
but what if i have another button that deletes the words such as "DelWordsBtn"? I was thinking i could declare both buttons simultaneously like this:
SetWordsBtn=(Button)findViewById(R.id.SetWordsBtn);
DelWordsBtn=(Button)findViewById(R.id.DelWordsBtn);
SetWordsBtn.setOnClickListener(this);
DelWordsBtn.setOnClickListener(this);
but what about the onClick() method? Does it automatically apply itself to both the buttons when i do this?
How am i able to declare a seperate onClick from each other so it both does different stuff when i click on either one of them?
I was thinking the answer could be something like this, but i dunno :
//Declarations
SetWordsBtn=(Button)findViewById(R.id.SetWordsBtn);
DelWordsBtn=(Button)findViewById(R.id.DelWordsBtn);
SetWordsBtn.setOnClickListener(setWordsView);
DelWordsBtn.setOnClickListener(delWordsView);
//onClick Functions
public void onClick(View setWordsView) {
startWords();
}
public void onClick(View delWordsView) {
deleteWords();
}
So it would actually link the startWords() function to the SetWordsBtn, and deleteWords() to DelWordsBtn...
Any clear cut explanation/form of help would be appreciated. Thanks in advance guys. :)
The typical convention is to just switch off of the ID of the View that is clicked. For example:
View.OnClickListener listener = new View.OnClickListener() {
#Override
public void onClick(View v) {
switch(v.getId()) {
case R.id.SetWordsBtn:
startWords();
break;
case R.id.DelWordsBtn:
deleteWords();
break;
}
}
};
int[] ids = { R.id.SetWordsBtn, R.id.DelWordsBtn };
for(int i : ids) ((Button)findViewById(i)).setOnClickListener(listener);
You can alternatively set up anonymous inner class(es) that listen, instead of having your Activity itself be the listener that implements OnClickListener. Example from the Android Button javadoc:
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Perform action on click
}
});
http://developer.android.com/reference/android/widget/Button.html
P.S. start your local variable names, and method names, with lower case letters -- upper case is for class names.
Where you suggested:
public void onClick(View setWordsView) {
startWords();
}
public void onClick(View delWordsView) {
deleteWords();
}
If you think about it, there is no difference in the two method declarations and you would get a build error (method signatures are the same, even though the method parameter, View, has a different name).
If I understand your question correctly then the answer given by kcoppock is correct. You also could define an Anonymous Class
Drag and drop button on graghiclayout.xml
...>right click the button -->choose other properties....>choose inherited from view ---->click on click ....name it callme.
That will be shows like this:
xml file
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_x="76dp"
android:layout_y="58dp"
android:onClick="callme"
android:text="Button" />
Run once your project:
Open src --->activity .java
----->, do the coding like this:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
but=(Button)findViewById(R.id.button1);
}
public void callme(View v)
{
//Do somthing
}