findViewById with reverse search does not work - android

I'm confused right now. I expect, that something, which works one way, also works reversed as well. But apparently not... I'm creating a view programmatically in my the class PlayerView. In the method player_table I'm assigning an onclick listener. And that works perfectly fine. However in the class PlayerLifePoints_Functions I have created the onclick method. The method itself works fine. The problem is the following: I'm assigning id's manually (to make my work in future process steps easier). Now I can read the id from an element, which was clicked. However if I want to find exactly this element by the ID (e.g. 400) it does return an error:
Error: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.Window$Callback android.view.Window.getCallback()' on a null object reference at ...PlayerLifePoints_Functions.onClick(PlayerLifePoints_Functions.java:21) -> The line with the log command
I have no idea why. I have also tried using getParent(), but that does not work either. Any ideas, where the problem could be?
Class PlayerView
public class PlayerView extends View {
private RelativeLayout relativeLayout;
private TableLayout tableLayout;
private int player_loop;
private int player_count;
public PlayerView(Context context, int player_count){
super(context);
setPlayer_count(player_count);
}
public ScrollView create_scrollView(){
ScrollView scrollView = new ScrollView(getContext());
ScrollView.LayoutParams scroll_params = new ScrollView.LayoutParams(
ScrollView.LayoutParams.MATCH_PARENT,
ScrollView.LayoutParams.MATCH_PARENT
);
scrollView.setLayoutParams(scroll_params);
scrollView.addView(create_relativeLayout());
return scrollView;
}
public HorizontalScrollView create_relativeLayout(){
HorizontalScrollView horizontalScrollView = new HorizontalScrollView(getContext());
relativeLayout = new RelativeLayout(getContext());
RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT,
RelativeLayout.LayoutParams.MATCH_PARENT
);
relativeLayout.setLayoutParams(relativeParams);
create_Player_Table_Layout();
horizontalScrollView.addView(relativeLayout);
return horizontalScrollView;
}
public void create_Player_Table_Layout(){
for(player_loop = 1; player_loop <= player_count; player_loop++){
relativeLayout.addView(player_table(getResources().getString(R.string.dummy_player_name) + player_loop, player_loop));
}
}
public TableLayout player_table(String playername, int playernumber){
tableLayout = new TableLayout(getContext());
tableLayout.setId(playernumber * 1000);
if (playernumber > 1) {
//TABLE PLACEMENT
RelativeLayout.LayoutParams tbl_params_New = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
tbl_params_New.addRule(RelativeLayout.RIGHT_OF, (playernumber - 1) * 1000);
tableLayout.setLayoutParams(tbl_params_New);
}
//Add Playername
TableRow row_playername = new TableRow(getContext());
TextView view_name = new TextView(getContext());
TableRow.LayoutParams view_name_params = new TableRow.LayoutParams();
view_name_params.setMargins(20,20,20,20);
view_name.setLayoutParams(view_name_params);
view_name.setGravity(Gravity.CENTER);
view_name.setText(playername);
view_name.setTextSize(20);
view_name.setId(playernumber * 100);
//OnClickListener
PlayerName_Functions listener_name = new PlayerName_Functions();
view_name.setOnClickListener(listener_name);
row_playername.addView(view_name);
tableLayout.addView(row_playername);
//Add Lifepoints
TableRow row_lifepoints = new TableRow(getContext());
TextView view_lifepoints = new TextView(getContext());
TableRow.LayoutParams view_lifepoints_params = new TableRow.LayoutParams();
view_lifepoints_params.setMargins(20, 0, 20, 20);
view_lifepoints.setText("40");
view_lifepoints.setTextSize(40);
view_lifepoints.setGravity(Gravity.CENTER);
view_lifepoints.setId(playernumber * 100 + 10);
view_lifepoints.setLayoutParams(view_lifepoints_params);
//OnClickListener
PlayerLifePoints_Functions listener_lifepoints = new PlayerLifePoints_Functions();
view_lifepoints.setOnClickListener(listener_lifepoints);
row_lifepoints.addView(view_lifepoints);
tableLayout.addView(row_lifepoints);
for(int opponent_loop = 1; opponent_loop <= player_count; opponent_loop++){
tableLayout.addView(commander_damage_from_player(player_loop, opponent_loop));
}
return tableLayout;
}
Class PlayerLifePoints (Containing the OnClick Function implemented in the class above)
public class PlayerLifePoints_Functions extends AppCompatActivity implements View.OnClickListener {
#Override
public void onClick(View v) {
TextView textView = (TextView) v;
String lp = textView.getText().toString();
int id = textView.getId();
int playernumber = Character.getNumericValue(String.valueOf(id).charAt(0));
Log.d("Test", "ID: " + findViewById(v.getId()).getId());
// Intent intent = new Intent(v.getContext(), Update_LifePoints.class);
// intent.putExtra( "Update Reason", "Test");
//// intent.putExtra("Player Name", playername);
// intent.putExtra("Lifepoints", lp);
//
// v.getContext().startActivity(intent);
}

Your class PlayerLifePoints_Functions cannot use findViewById because it does not have content. Usually activities are started with Intents and they inflate a layout by overriding the onCreate method.
If you just want to make it work, you can use:
v.getRootView().findViewById(v.getId()).getId());
In that case you do not need to extend from AppCompatActivity
Or better just get rid of the class:
view_lifepoints.setOnClickListener( View.OnClickListener {
#Override
public void onClick(View v) {
TextView textView = (TextView) v;
String lp = textView.getText().toString();
int id = textView.getId();
int playernumber = Character.getNumericValue(String.valueOf(id).charAt(0));
Log.d("Test", "ID: " + findViewById(v.getId()).getId());
}
);
In general:
I would recommend not putting your whole logic into a view, but more down into a lower layer. Having it in the activity would already be an improvement for prototyping. If your code grows, it may make sense to switch to MVP or MVVM.
Google has some great resources to get you started:
https://developer.android.com/guide/components/activities/intro-activities
https://developer.android.com/topic/libraries/architecture/

Related

Android issue with programatically created buttons

Well im trying to get the text on each button, it displays the text correctly on each but when i try to print it, it shows the same text. The text of optionD
private void displayQuestion() {
final ArrayList<String> options = new ArrayList<>();
for (int i = 0; i < questions.size(); i++){
Questions diaplayQuestion = questions.get(i);
question.setText(diaplayQuestion.getQuestion());
options.add(0, diaplayQuestion.getOptionA());
options.add(1, diaplayQuestion.getOptionB());
options.add(2, diaplayQuestion.getOptionC());
options.add(3, diaplayQuestion.getOptionD());
correctOption = diaplayQuestion.getCorrectOption();
}
for (int i = 0; i < options.size(); i++) {
btn = new Button(GameplayActivity.this);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(10, 10, 10, 0);
btn.setLayoutParams(params);
btn.setText(options.get(i));
btn.setId(i);
linearLayout.addView(btn);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
System.out.println(view.getId());
}
});
}
}
If you want to store some information inside View use tags. From official docs:
Unlike IDs, tags are not used to identify views. Tags are essentially an extra piece of information that can be associated with a view. They are most often used as a convenience to store data related to views in the views themselves rather than by putting them in a separate structure.
So in your case it'll be like this:
btn = new Button(GameplayActivity.this);
...
btn.setTag(options.get(i)); // I assume that value is String
...
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
System.out.println((String) view.getTag());
}
});

How to update linearlayout child view programmatically in android?

I have created linearylayout programatically. where it has multiple rows created having white background. Now if I click on any row then only that row's imageview icon should be changed(should be green) and other row's imageview background should be changed to white. Is there any substitude of notifyDataSetChanged for linearlayout in android. below is my code.
for (int i = 0; i <= obj_tribe_info.al_ethnicity_secondary.size(); i++) {
final int position = i;
al_eth_bool.add(false);
final LinearLayout ll_values = new LinearLayout(_activity);
ll_values.setOrientation(LinearLayout.HORIZONTAL);
ll_values.setGravity(Gravity.CENTER_VERTICAL);
LayoutParams LLParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
ll_values.setLayoutParams(LLParams);
ll_values.setBackgroundResource(R.drawable.my_tribe_box_top);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
layoutParams.setMargins(50, 0, 0, 0);
final ImageView iv_icon = new ImageView(_activity);
if (al_eth_bool.get(position)) {
iv_icon.setBackgroundResource(R.drawable.notify_onn);
} else {
iv_icon.setBackgroundResource(R.drawable.notify_off);
}
iv_icon.setLayoutParams(layoutParams);
ll_values.addView(iv_icon);
TextView tv_value = new TextView(_activity);
tv_value.setTextColor(_activity.getResources().getColor(
R.color.black));
tv_value.setLayoutParams(layoutParams);
if (i == 0) {
tv_value.setText(obj_tribe_info.str_ethnicity_primary);
} else {
tv_value.setText(obj_tribe_info.al_ethnicity_secondary
.get(i - 1).str_ethnicity_secondary);
}
ll_values.addView(tv_value);
ll_ethnicity.post(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
ll_ethnicity.addView(ll_values);
}
});
ll_values.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (al_eth_bool.get(position)) {
iv_icon.setBackgroundResource(R.drawable.notify_off);
al_eth_bool.set(position, false);
} else {
iv_icon.setBackgroundResource(R.drawable.notify_onn);
al_eth_bool.set(position, true);
}
}
});
}
No, there is no substitute for notifyDataSetChanged(), you have to manually inform your ImageViews of that change.
You could iterate like this, as soon as you have a change:
for(int i= 0; i < ll_ethnicity.getChildCount(); i++){
ImageView iv = (ImageView) ((ViewGroup)ll_ethnicity.getChildAt(i)).getChildAt(0);
// new background because something has changed
// check if it's not the imageView you just clicked because you don't want to change its background
iv.setBackground(...);
}
For better performance you may also create an HashMap with your ImageViews and later access it to change some of them as you see fit.
I believe what you're looking for is View.invalidate() method. It tells the application that this view is no longer correct, and it will be redrawn when possible. Call this at the end of the onClick method.

How do I Pass an Intent to a Tab Activitiy in a onClickListener

I have a Tabbed Activity that I want to pass an intent to. I am trying to pass some parameters and this is not passing the intent. I am setting the current Tab in the onClickListener. My Code is below how do I do that?
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#SuppressLint("InlinedApi")
private void displayEvacRouteTable(){
AsyncClass ac = new AsyncClass(EvacRouteTableActivity.this);
ac.execute();
List<String> evacRouteList = new ArrayList<String>(DALController.sharedInstance().getAllRouteNames());
// get a reference for the TableLayout
TableLayout ll = (TableLayout) findViewById(R.id.TableLayout01);
for (String routeName : evacRouteList){
// create a new TableRow
TableRow row = new TableRow(this);
// create a new TextView
TextView destNameTextView = new TextView(this);
String evacRouteName = " " + routeName;
SpannableString evacRouteSpanString = new SpannableString(evacRouteName);
evacRouteSpanString.setSpan(new UnderlineSpan(), 0, evacRouteName.length(), 0);
destNameTextView.setText(evacRouteSpanString);
destNameTextView.setTextColor(Color.BLUE);
destNameTextView.setTextSize(20);
destNameTextView.setHeight(55);
Linkify.addLinks(evacRouteSpanString, Linkify.ALL);
final Intent i = new Intent(EvacRouteTableActivity.this, MapViewActivity.class);
Bundle b = new Bundle();
b.putString("evacObject", routeName);
i.putExtras(b);
destNameTextView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
AsyncClass ac = new AsyncClass(EvacRouteTableActivity.this);
ac.execute();
#SuppressWarnings("deprecation")
TabActivity ta = (TabActivity) EvacRouteTableActivity.this.getParent();
ta.getTabHost().setCurrentTab(4);
}
});
destNameTextView.setBackgroundResource(R.drawable.cell_shape);
destNameTextView.setLayoutParams(new TableRow.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
row.addView(destNameTextView);
ll.addView(row,new TableLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
}
}
Here is the code that I am trying to use to receive the intent :
String fuelStopBundle = getIntent().getExtras();
if (fuelStopBundle != null){
evacName = fuelStopBundle.getString("evacObject");
this might help you,Instead of passing the string through intent use static variable as,
your passing class
class EvacRouteTableActivity extends TabActivity{
public static String routeName="";
/**** write your code here****/
/****change the value of routeName string as per your desire****/
}
your receiving class,
class MapViewActivity extends Activity{
/**** write your code here****/
//access routeName string as below
String recieved_string= EvacRouteTableActivity.routeName;
}
please let me know if you have any trouble regarding this.

Bring to front part of layout in android

I have a problem with parts of layout. I am adding buttons programmatically, because I want do something like breadcrump. I my solution work good. If I am in first activity I show one button. If I go to second I show two buttons.
This is code:
public class TabsGenerator extends LinearLayout{
public TabsGenerator(Context context) {
super(context);
}
public View addNewLinearLayout(Context context, ArrayList<String> descriptions) {
final HorizontalScrollView horizontalView = new HorizontalScrollView(context);
LinearLayout linearLayout = new LinearLayout(context);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
params.height = 60;
linearLayout.setLayoutParams(params);
horizontalView.setLayoutParams(params);
postDelayed(new Runnable() {
public void run() {
horizontalView.fullScroll(HorizontalScrollView.FOCUS_RIGHT);
}
}, 100L);
linearLayout.setGravity(Gravity.TOP);
List<View> components = getButtons(context, descriptions);
for(View component : components) {
linearLayout.addView(component);
}
horizontalView.addView(linearLayout);
return horizontalView;
}
public List<View> getButtons(Context context, ArrayList<String> descriptions) {
List<View> buttons = new ArrayList<View>();
for(int i = 0; i < descriptions.size(); i++) {
buttons.add(createButton(context,i, descriptions));
}
return buttons;
}
public View createButton(final Context context, final int i, final ArrayList<String> descriptions){
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
params.leftMargin = -20;
final Button button = new Button(context);
button.setText(SecondActivity.descriptions.get(i));
button.setBackgroundDrawable(getResources().getDrawable(R.drawable.paseknawigacji));
button.setHorizontallyScrolling(true);
button.setEllipsize(TruncateAt.END);
button.setSingleLine();
button.setWidth(20);
if(i==1)
button.bringToFront();
button.setLayoutParams(params);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ActivityManager am = (ActivityManager) context.
getSystemService(Activity.ACTIVITY_SERVICE);
String packageName = am.getRunningTasks(1).get(0).topActivity.getPackageName();
String className = am.getRunningTasks(1).get(0).topActivity.getClassName();
final String StringClassname = packageName+"."+descriptions.get(i);
Class<?> c = null;
if(StringClassname != null) {
try {
c = Class.forName(StringClassname );
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Intent intent = new Intent();
intent.setClassName(context,StringClassname);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
if(!(StringClassname.contains(className))){
for(int j = 0; j<descriptions.size()-1;j++)
if(i<descriptions.size()-1)
descriptions.remove(i+1);
context.startActivity(intent);
}
}
});
return button;
}
}
I have a problem because buttons was added to layout but every buttons has ending by triangular shape. When I add second button he cover this shape.
This is how it is looks:
I want to bring to front ending every button. How I can do that?
Edit: Maybe is other way to create breadcrup in android?
Try to add buttons in the reverse order
Your code
List<View> components = getButtons(context, descriptions);
for(View component : components) {
linearLayout.addView(component);
}
now in reverse order
List<View> components = getButtons(context, descriptions);
for(int i = components.size() - 1; i >= 0; i --) {
View component = components.get (i);
linearLayout.addView(component);
}
(code not compiled, may have errors)
try this
thirdButton.bringtoFront();
SecondButton.bringToFront();
Your will see the triangular shape of third and second button.
Hope so this will work
I dont think yours will work with a linear layout as I have noticed that when using bring to front in a linear layout you automatically set it at the total end (eg its not longer button 1 button 2 button 3 but button 1 button 3 button 2). You would need to use a Relative layout or something similar. This might add a little logic to your code but it should be ok otherwise.
Maybe you can try setting elevation in your buttons
But I think the leftMargin= -20 is the reason why you cant see the ending triangle shape

Dynamic TextViews OnCLickListener not triggering first time the Activity loads

I have a LinearLayout that gets populated with TextViews. Each of those TextViews gets set with the same OnClickListener. The Listener DOES get triggered, but only on the SECOND time the Activity loads.
How can I get it to trigger the first time through / why is it not triggering the first time?
public static void loadArticlesIntoSimilarList(Context mContext, String myid)
{
//POPULATES THE LIST OF ARTICLES
//associatedArticles = articlesDataSource.getAssociatedArticlesData(articleId);
for(final Article similarArticle : articlesDataSource.getAssociatedArticlesList(myid))
{
TextView similarArticleTextView = new TextView(mContext);
similarArticleTextView.setTextColor(mContext.getResources().getColor(R.color.meddark_gray));
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
similarArticleTextView.setLayoutParams(new LayoutParams(
LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
layoutParams.setMargins(ConversionHelper.dpToPx(5), 0, ConversionHelper.dpToPx(5), ConversionHelper.dpToPx(20));
similarArticleTextView.setText(similarArticle.title);
similarArticleTextView.setId((int) similarArticle.id);
similarArticlesLinearLayout.addView(similarArticleTextView);
similarArticleTextView.setClickable(true);
similarArticleTextView.setOnClickListener(relatedArticleClickListener);
similarArticleTextView.setLayoutParams(layoutParams);
}
}
I'm first setting the listener at the top:
private static OnClickListener relatedArticleClickListener;
And the function is:
//RELATED ARTICLE CLICK
relatedArticleClickListener = new OnClickListener()
{
public void onClick(View v) {
Log.d("MYLOG", "RL Article clicked " + v.getId());
Intent myIntent = new Intent(v.getContext(),MainActivity.class);
myIntent.putExtra("id", v.getId());
startActivity(myIntent);
finish();
}
};

Categories

Resources