Duplicated text in all EditTexts after OnRetainCustomConfigurationInstance - java

When I use onRetainCustomNonConfigurationInstance to save the text contained inside my custom EditTexts, after I rotate the device the text contained in the last EditText gets duplicated to all the others in the target layout.
While debugging with breakpoints, I found that all the text values are correct all the way. But after the changes are done, all the EditTexts get the same text showing (the text from the last one) and the focus is given to the first one in the layout.
I replicated this behavior in the simplest project I could. I tried with both android API levels 24 and 28.
Where does this behavior come from and how can I fix it ?
MainActivity.java :
public class MainActivity extends AppCompatActivity {
private ArrayList<CustomEdit> editList=new ArrayList<CustomEdit>();
private LinearLayout layout;
private Button addButton;
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
addButton=findViewById(R.id.add_button);
layout = findViewById(R.id.layout);
addButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
addEdit();
}
});
CustomSave data = (CustomSave)getLastCustomNonConfigurationInstance();
if(data==null) return;
for(int i = 0; i<data.texts.size();i++){
addEdit(data.texts.get(i));
}
}
#Override
public Object onRetainCustomNonConfigurationInstance() {
CustomSave data = save();
return data;}
private CustomSave save(){
ArrayList<String> texts = new ArrayList<String>();
for(int i =0; i<editList.size(); i++)
texts.add(editList.get(i).getText());
return new CustomSave(texts);}
/**
* Create a new custom EditText with hint
*/
private void addEdit(){
CustomEdit newEdit = new CustomEdit(this,editList.size());
layout.addView(newEdit,editList.size());
editList.add(newEdit);}
/**
* Create a new custom editText with text
* #param text
*/
private void addEdit(String text){
CustomEdit newEdit;
if(text==null) newEdit = new CustomEdit(this, editList.size());
else newEdit = new CustomEdit(this, editList.size(),text);
layout.addView(newEdit,editList.size());
editList.add(newEdit);}
}
activity_main.xml :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="#+id/title"
android:layout_width="match_parent"
android:layout_height="20dp"
android:text="Title"
android:gravity ="center"/>
<HorizontalScrollView
android:id="#+id/scroll1"
android:layout_below="#id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="10dp"
android:paddingLeft="10dp">
<LinearLayout
android:id="#+id/layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="#+id/add_button"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="+"/>
</LinearLayout>
</HorizontalScrollView>
</RelativeLayout>
CustomEdit.java :
public class CustomEdit extends RelativeLayout {
private EditText editText;
private Button closeButton;
private int indexNumber;
public CustomEdit(Context context, int indexNumber) {
super(context);
this.indexNumber =indexNumber;
init();
}
public CustomEdit(Context context, int indexNumber, String text){
super(context);
this.indexNumber=indexNumber;
init();
editText.setText(text);
}
public CustomEdit(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomEdit(Context context, AttributeSet attrs, int defStyleAttr){
super(context, attrs, defStyleAttr);
init();
}
private void init(){
inflate(getContext(),R.layout.custom_edit_text,this);
editText = (EditText)findViewById(R.id.edit);
editText.setHint("EditText "+(indexNumber+1));
closeButton = (Button)findViewById(R.id.close_button);
closeButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
((MainActivity)getContext()).closeEdit(indexNumber);
}
});
}
public String getText(){
return editText.getText().toString();
}
}
custom_edit_text.xml :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="100dp"
android:layout_height="40dp">
<EditText
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/edit"
android:inputType="text"
android:hint="Element"
android:maxLength="30"/>
<Button
android:id="#+id/close_button"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignRight="#id/edit"
android:layout_alignEnd="#id/edit"
android:layout_alignTop="#id/edit"
android:text="X"/>
</RelativeLayout>
CustomSave.java :
public class CustomSave {
public ArrayList<String> texts;
CustomSave(ArrayList<String> texts){
this.texts = texts;
}
}
Thank you.

You have two choices for how to solve this: move your code to a different point in the activity lifecycle or change the xml definition for CustomEdit.
Android lifecycle
Move this code out of onCreate():
CustomSave data = (CustomSave)getLastCustomNonConfigurationInstance();
if(data==null) return;
for(int i = 0; i<data.texts.size();i++){
addEdit(data.texts.get(i));
}
And put it in onRestoreInstanceState() instead:
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
CustomSave data = (CustomSave)getLastCustomNonConfigurationInstance();
if(data==null) return;
for(int i = 0; i<data.texts.size();i++){
addEdit(data.texts.get(i));
}
}
or
XML definition
Add this attribute to the <EditText> tag in your custom_edit_text.xml file:
android:saveEnabled="false"
There's nothing wrong with the code you've written to save/restore your text values. However, after onCreate(), Android is automatically performing its own save/restore logic, and that's overwriting what you've done.
If you move your code from onCreate() to onRestoreInstanceState(), then your code will run after Android's automatic save/restore, so you'll "win". Or, you can disable the automatic save/restore by adding the saveEnabled=false attribute.
The reason that Android's automatic save/restore doesn't work is that it is based on each view's android:id attribute, and your EditText tags all have the same id. That means that all four values get saved with the same key, so the last value overwrites all previous values.

So what's happening here is that Android is also handling state saving for your custom EditText implementation, which is overwriting yours. Since your list of CustomEdit instances is generated dynamically, you likely do not want to rely on Android to save the state for your views, since they do not have unique IDs.
Since your CustomEdit inflates custom_edit_text.xml (which declares the EditText ID as #+id/edit) that means that each CustomEdit you add to the layout has the same ID for the inner EditText -- R.id.edit. Since they all have the same ID, each view will save its state to that ID, so the last one to save its state will end up being the text applied to all of the views when restoring state.
There are two things you can do to avoid this:
In your custom_edit_text.xml, add android:saveEnabled="false" to the EditText. This will prevent that View's state from being saved. This would be preferred as it avoids doing unnecessary work.
Perform your state restoration in onRestoreInstanceState() where the view state is being restored currently.

Related

Displaying ListView on Android

How do I create a working ListView in Android?
I am not looking for you to just fix my code, but am looking for a simple working example of a ListView in Android so I can understand the process of creating one and working with it. But I have included my code so you can see where I am coming from and what I have been trying.
I have done the following and had no success:
--
Made a xml layout with only a TextView item in it:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/dir_text_view"
/>
Created the following class as per the instructions at the following tutorial:
http://www.vogella.com/tutorials/AndroidListView/article.html
public class DataTempleArrayAdapter extends ArrayAdapter<String> {
HashMap<String, Integer> mIdMap = new HashMap<String, Integer>();
public DataTempleArrayAdapter(Context context, int textViewResourceId,
List<String> objects) {
super(context, textViewResourceId, objects);
for (int i = 0; i < objects.size(); ++i) {
mIdMap.put(objects.get(i), i);
}
}
#Override
public long getItemId(int position) {
String item = getItem(position);
return mIdMap.get(item);
}
#Override
public boolean hasStableIds() {
return true;
}
}
And in the main activity I have a snippet of code where I attempt to add a list of strings to the ArrayList associated with the DataTempleArrayAdapter here:
int i;
for (i=0;i<dirContents.length;i++) {
dirList.add(dirContents[i]);
//Toast.makeText(this, dirList.get(i), Toast.LENGTH_SHORT).show();
}
adapter.notifyDataSetChanged();
dirList is successfully populated, while the adapter doesn't update the ListView at all.
--
Before you ask for it, here I am including the rest of the relevant code:
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="org.hacktivity.datatemple.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="text"
android:hint="#string/directory"
android:ems="10"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:id="#+id/dirEditText" />
<Button
android:text="→"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:id="#+id/dirButton"
android:onClick="populateDirList" />
</LinearLayout>
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:id="#+id/dirListView" />
</LinearLayout>
</RelativeLayout>
And alas the MainActivity class:
public class MainActivity extends AppCompatActivity {
ListView dirListView;
EditText et;
DataTempleArrayAdapter adapter;
ArrayList<String> dirList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dirListView = (ListView) findViewById(R.id.dirListView);
et = (EditText) findViewById(R.id.dirEditText);
dirList = new ArrayList<String>();
dirListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Toast.makeText(getApplicationContext(),
"Click ListItem Number " + position, Toast.LENGTH_LONG)
.show();
populateDirList(view);
}
});
ArrayList<String> dirList = new ArrayList<String>();
adapter = new DataTempleArrayAdapter(this,
R.id.dir_text_view, dirList);
dirListView.setAdapter(adapter);
}
public void populateDirList (View view) {
File f;
// NO INPUT.
if (et.getText().toString().equals("")) {
Toast.makeText(this, "empty string", Toast.LENGTH_SHORT).show();
return;
}
f = new File(et.getText().toString());
if (f == null) { return; }
String dirContents[] = f.list();
if (dirContents == null) { return; }
dirList = new ArrayList<String>(Arrays.asList(f.list()));
adapter.clear();
int i;
for (i=0;i<dirContents.length;i++) {
dirList.add(dirContents[i]);
//Toast.makeText(this, dirList.get(i), Toast.LENGTH_SHORT).show();
}
adapter.notifyDataSetChanged();
}
}
One of the best resources for understanding ListView is indeed the
one you mentioned from Vogella
Another cool resource to understand how the the
notifyDataSetChanged() method works in ListView this post from StackOverflow
For a short, simple explanation of how to use CustomLayouts in
ListView (without the ViewHolder pattern) check another of the best
references available: Mkyong
Discussing the benefits of the ViewHolder pattern in ListView:
check this StackOverflow post
Concise example and explanation of the ViewHolder pattern in
ListView: check this example from JavaCodeGeeks
And to fix your code I think the answer given before is only part of the problem:
You must indeed comment the line
//ArrayList<String> dirList = new ArrayList<String>();
because, like #F43nd1r mentioned this would also be a different instance of a list passed into the adapter
but there is more, when you do this:
dirList = new ArrayList<String>(Arrays.asList(f.list()));
you are instantiating a new, different, list, the old reference held by the adapter will NOT be changed... it will still hold the OLD object list
you should perhaps substitute it for something like:
dirList.clear();
dirList.addAll(Arrays.asList(f.list()));
Hope this helps!
Excerpt from your code:
#Override
protected void onCreate(Bundle savedInstanceState) {
//...
dirList = new ArrayList<String>();
//...
ArrayList<String> dirList = new ArrayList<String>();
adapter = new DataTempleArrayAdapter(this,
R.id.dir_text_view, dirList);
//...
}
I bet you already see what the problem is, but in case you don't: You have a field and a local variable with the same name. You pass the local variable to the adapter. It is only naturally that the adapter does not react to changes on the field, as it has no knowledge of its existence.
I think what you have done wrong is to supply a UI Component to the Array Adapter with:
adapter = new DataTempleArrayAdapter(this, R.id.dir_text_view, dirList);
The second item should not be an ID, but a layout file. Android have already implemented a List item layout with a textview that you can use: android.R.layout.simple_list_item_1.
so replace your row with
adapter = new DataTempleArrayAdapter(this, android.R.layout.simple_list_item_1, dirList);
and you are one step closer.
(This way you don't need your "xml layout with only a TextView item in it")

Android numberpicker getting stuck

I have a numberpicker dialog to select hours and minutes (15 minutes interval). It works fine on large screens but on small screens and older devices it gets stuck if I try to scroll using touch.
I am extending the android.widget.NumberPicker and reducing the font size which helps on some devices.
public class TimerNumberPicker extends android.widget.NumberPicker {
public TimerNumberPicker(Context context) {
super(context);
}
public TimerNumberPicker(Context context, AttributeSet attrs){
super(context,attrs);
}
#Override
public void addView(View child) {
super.addView(child);
updateView(child);
}
#Override
public void addView(View child, ViewGroup.LayoutParams params) {
super.addView(child, params);
updateView(child);
}
#Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
super.addView(child, index, params);
updateView(child);
}
private void updateView(View view) {
if(view instanceof EditText){
((EditText) view).setTextSize(TypedValue.COMPLEX_UNIT_SP,16);
view.setTag(FontUtil.TAG_CONDENSED_LIGHT);
FontUtil.getInstence(getContext()).setFontByTag(view);
}
}
}
What makes it more complicated is that the minutes have only values (0, 15, 30, 45) and I have to setWrapSelectorWheel to false?
I am thinking if it will be possible to always show the up and down arrows and then disabling scroll.
Change it to an Edittext with the type of number, and use a Toast if the client put a number upper or below of your range. It's more elegant visually, and that will not give you any problem at all
you can use Fantastic PickView library
See PickView
This is a helper lib for us to pick date or province like IOS system WheelView widget.
Maybe you could solve it using a TimePicker.
This could be the layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:padding="8dp"
android:layout_height="wrap_content">
<ScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TimePicker
android:id="#+id/time_picker"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<Button
android:id="#+id/date_time_set"
android:layout_width="match_parent"
android:text="Set"
android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView>
While the dialog could be included in a normal alert:
private void showTimePicker(){
final View dialogView = View.inflate(getActivity(), <time_picker_container_layout_id>, null);
final AlertDialog alertDialog = new AlertDialog.Builder(getActivity()).create();
dialogView.findViewById(R.id.date_time_set).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
TimePicker timePicker = (TimePicker) dialogView.findViewById(R.id.time_picker);
String time = timePicker.getCurrentHour()+":"+timePicker.getCurrentMinute());
dateTime.setText(time);
alertDialog.dismiss();
}});
TimePicker timePicker = (TimePicker) dialogView.findViewById(R.id.time_picker);
timePicker.setCurrentHour(<default_hour>);
timePicker.setCurrentMinute(<default_minute>);
alertDialog.setView(dialogView);
alertDialog.show();
}
If you need to show just the 15', you can round the picked minutes to the closest valid value.
The scrollView in the layout will reduce problems related the picker size.
I hope it helped.

Issues when relative layout implement swipe-to-refresh layout

I'm currently attempting to implement swipe-to-refresh layout into relative layout, but it is extremely insensitive and unstable. When I pull down the screen, it usually either doesn't refresh or it refreshes without progress bar.
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.example.miaor.tutorialweather.MainActivity"
android:id="#+id/refreshLayout"
android:background="#fe970b">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
</RelativeLayout>
public class MainActivity extends AppCompatActivity{
public static final String TAG = MainActivity.class.getSimpleName();
#BindView(R.id.TimeString) TextView mTimeLabel;
#BindView(R.id.TemperatureLabel) TextView mTemperatureLabel;
#BindView(R.id.HumidityValue) TextView mHumidityValue;
#BindView(R.id.rainingChanceValue) TextView mChance;
#BindView(R.id.weatherIcon) ImageView mWeatherIcon;
#BindView(R.id.SummaryText) TextView mSummaryText;
#BindView(R.id.refreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
///why do we make a new variable of CurrentWeather
private CurrentWeather mCurrentWeather;
private String apiKey = "6b9448b8e21c2abe2fb623b25554a77c";
private double latitude = 31.230708;
private double longitude = 121.472916;
private String forecastUrl = "https://api.forecast.io/forecast/" + apiKey +
"/" + latitude + "," + longitude;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
///implement swipe-to-refresh feature
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
Log.i(TAG, "onRefresh is working");
getForecast();
}
});
getForecast();
Log.d(TAG, "Main UI code is running!");
}
You can't implement SwipeToRefreshLayout with RelativeLayout as its child. You need to have a scrollable view as its only child. e.g. Listview, RecyclerView, ScrollView. That is the reason why it is not working as expected for you.
That is not the right position.
You need type like this:
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/your_id"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
YOUR RELATIVE LAYOUT HERE
</ScrollView>
</android.support.v4.widget.SwipeRefreshLayout>
Your code looks fine, it's weird that it's not working correctly... Maybe it's because of the ButterKnife library? I don't think that's the problem, but it will be worth the shot to get views manually to see if that's the problem
Then, if you need the loading animation to appear/hide you can use mSwipeRefreshLayout.setRefreshing(boolean);
For example in my app I attach the listener first (as you did in your example) and then I use the following code to show the loading animation while I fetch the data.
// Show loading while fetching the first set of data
mainSwipeRefreshLayout.post(new Runnable() {
#Override
public void run() {
mainSwipeRefreshLayout.setRefreshing(true);
}
});
In my fetchData() method I use the following line to hide the animation again when it finishes fetching the data.
// On load complete stop refresh animation
mainSwipeRefreshLayout.setRefreshing(false);
Hope this helps!
Andres.

OnClick doesn't work with LinearLayout

OnClick doesn't work. Nothing happens after clicking on layout. It seems like it is clickable, because layout changes its color, but new layout doesn't open.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/window"
android:layout_width="295dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#drawable/editborder"
android:clickable="true"
android:onClick="openBigImage">
Here is more code for Main Activity:
public class MyMapActivity extends FragmentActivity implements LocationListener
{
private Marker marker;
private Hashtable<String, String> markers;
private ImageLoader imageLoader;
private DisplayImageOptions options;
private GoogleMap map;
private ListView mainListView ;
private ArrayAdapter<String> listAdapter ;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_map);
// Look up the AdView as a resource and load a request.
//AdView adView = (AdView)this.findViewById(R.id.adView);
//adView.loadAd(new AdRequest());
// Getting Google Play availability status
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getBaseContext());
// Showing status
if(status!=ConnectionResult.SUCCESS)
{ // Google Play Services are not available
int requestCode = 10;
Dialog dialog = GooglePlayServicesUtil.getErrorDialog(status, this, requestCode);
dialog.show();
}
else
{// Google Play Services are available
// Getting reference to the SupportMapFragment of activity_main.xml
SupportMapFragment mapFragment = (SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map);
if (savedInstanceState == null) {
// First incarnation of this activity.
mapFragment.setRetainInstance(true);
}
else
{
// Reincarnated activity. The obtained map is the same map instance in the previous
// activity life cycle. There is no need to reinitialize it.
map = mapFragment.getMap();
}
setUpMapIfNeeded();
}
}
#Override
protected void onResume()
{
super.onResume();
setUpMapIfNeeded();
}
public void openBigImage(View v)
{
setContentView(R.layout.bigpicture);
}
bigpicture.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/bigpicture"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000"
android:orientation="vertical">
<fragment
android:id="#+id/minimap"
android:layout_width="200px"
android:layout_height="200px"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
class="com.google.android.gms.maps.SupportMapFragment" />
<ImageView
android:id="#+id/badge"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:adjustViewBounds="true" />
</RelativeLayout>
Calling setContentView() multiple times worked in other cases, like menu items "about", "settings" etc.
Tried to make without setContentView. I've put new Layout to the main.xml and made visibility GONE. OnClick method should change visibility to visible, but again nothing happens.
Logcat says "11-25 13:47:28.638: D/GestureDetector(3156): [Surface Touch Event] mSweepDown False, mLRSDCnt : -1 mTouchCnt : 2 mFalseSizeCnt:0" when i'm clicking on linear layout.
Paul,
One thing is close the linear layout with /> .I am assuming that you have followed the map tutorials link and passed all the manifest permissions and other requirements. You might have some reasons to use px. Check if map is being created. Also give some height and background color to your badge image and see if something happens.
I tested your code without map fragment and it worked fine.
Can you post the error log ?
Found. It is a click on InfoWindow, so we should implement onInfoWindowClick.
But first we must add map.setOnInfoWindowClickListener(this); in main activity. Main activity must implement OnInfoWindowClickListener.
I've added new LinearLayout to the main.xml, made it invisible.
Here's code for onInfoWindowClick:
#Override
public void onInfoWindowClick(Marker marker) {
LinearLayout secondLL = (LinearLayout) findViewById(R.id.bigpicture);
int visibility = secondLL.getVisibility();
if(visibility == View.GONE)
{
secondLL.setVisibility(View.VISIBLE);
}
}
I think you can't use onClick attribute.
You have to use setOnClickListener() like that :
LinearLayout layout = (LinearLayout )findViewById(R.id.window);
layout .setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
YourActivity.this.setContentView(R.layout.bigpicture);
}
});

Menu view for several layouts

I've created a layout with a menu view that will be in other layouts showing some buttons. To define these buttons and their actions, I'm creating an independet class to define all of them and this way I avoid to have to define all of them again and again in all the activities.
To do this, first I've created the menu_view layout:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<!-- Button columns -->
<RelativeLayout
android:id="#+id/border_left"
android:layout_width="100dip"
android:layout_height="fill_parent"
android:orientation="vertical"
android:layout_alignParentLeft="true"
android:background="#000000" >
<ImageView
android:id="#+id/radioButton"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_weight="1"
android:layout_marginTop="60dp"
android:layout_marginLeft="10dp"
android:onClick="launch_radio"
android:src="#drawable/radio_button" />
<ImageView
android:id="#+id/musicButton"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_weight="1"
android:layout_marginTop="200dp"
android:layout_marginLeft="10dp"
android:onClick="launch_media"
android:src="#drawable/music_button" />
</RelativeLayout>
</RelativeLayout>
NOTE: Here aren't all the buttons, I only put 2 to have an idea.
After this, I created the MenuView class where I define all these buttons and what they do:
public class MenuView extends RelativeLayout {
private final LayoutInflater inflater;
public MenuView(Context context, AttributeSet attrs) {
super(context, attrs);
inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.menu_view, this, true);
((ImageView)this.findViewById(R.id.navButton)).setOnClickListener(launch_nav);
((ImageView)this.findViewById(R.id.phoneButton)).setOnClickListener(launch_phone);
((ImageView)this.findViewById(R.id.webButton)).setOnClickListener(launch_web);
((ImageView)this.findViewById(R.id.backButton)).setOnClickListener(goBack);
}
private final OnClickListener launch_nav = new OnClickListener() {
#Override
public void onClick(View v) {
getContext().startActivity(new Intent(getContext(), Navigation.class));
}
};
**¡¡¡THROUBLE!!!**
private final OnClickListener launch_phone = new OnClickListener() {
#Override
public void onClick(View v) {
public void launch_phone (String number) {
String numberToDial = "tel:"+number;
}
getContext().startActivity(new Intent(Intent.ACTION_DIAL, Uri.parse(numberToDial)));
}
};
private final OnClickListener launch_web = new OnClickListener() {
#Override
public void onClick(View v) {
getContext().startActivity(new Intent(android.content.Intent.ACTION_VIEW, Uri.parse("http://www.google.es")));
}
};
**¡¡¡THROUBLE!!!**
private final OnClickListener goBack = new OnClickListener() {
#Override
public void onClick(View v) {
getContext().startActivity(new Intent(getContext(), NO.class));
}
};
}
Here is where I'm a little bit lost. I have to define 2 actions:
1- The phone dialer
2- The goBack key
The phone dialer I don't know how to define it right here. I had defined in other way when I was first creating this app, and it worked fine.. But now, with lot of activities, I have to do this way, and here it shows an error because this isn't the way to do it.
With the back button, what I need is just to define that when this button is pressed, it must go back on activity, but again, in this type of class I don't know how to define it.
It sounds as though with a quick overview of your application that you are segregating code outside of an Activity where it originally existed and now what these to be structured so that they are in a separate class object to be referenced. You are already passing in a context when you construct the class, so you should be able to just save that context that is being passed in and use that as your launch for the goBack call. Otherwise you are calling a goBack on a view context, and the back button is associated with an Activity (which is ideally what you have passed into this class when you created it) so you want the context passed in to your view.
private activityContext;
public MenuView(Context context, AttributeSet attrs) {
super(context, attrs);
activityContext = context;
inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.menu_view, this, true);
((ImageView)this.findViewById(R.id.navButton)).setOnClickListener(launch_nav);
((ImageView)this.findViewById(R.id.phoneButton)).setOnClickListener(launch_phone);
((ImageView)this.findViewById(R.id.webButton)).setOnClickListener(launch_web);
((ImageView)this.findViewById(R.id.backButton)).setOnClickListener(goBack);
}
**¡¡¡THROUBLE!!!**
private final OnClickListener goBack = new OnClickListener() {
#Override
public void onClick(View v) {
activityContext.startActivity(new Intent(activityContext, NO.class));
}
};
}

Categories