ListView after click and back List is empty - android

I have a layout with a ListView and ImageView. Initially, ImageView is invisible. I have a list, when an Item is clicked, it shows the Image of that item by setting ImageView and making it visible and listView is invisible, so far everything is ok. From there, onBackPressed() I want to see my listview again, I override onBackPressed(), to make my image view invisible and listview visible. However, when I select an item and see the image of it then press back, a blank activity comes, not my listView. I don't want to call the activity again, what should I do? What is wrong about listView? I tried to call invalidate() and invalidateViews(), setting adapter again, but they aren't woring.
Actually I'm filing adapter in the onResume of the activity, here is the code:
public class MyViewActivity extends Activity{
ListView imageList;
CustomImageListAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_list_view);
//initialization of image array list etc
}
#Override
public void onResume(){
super.onResume();
imageList = (ListView) findViewById(R.id.listView);
adapter = new CustomImageListAdapter(this,R.layout.image_item, imageNames);
imageList.setAdapter(adapter);
imageList.setOnItemClickListener(new OnItemClickListener()
{
public void onItemClick(AdapterView<?> adapter, View view, int i,
long l) {
// TODO Auto-generated method stub
if(imageNames.get(i) != null) {
onImageSelected(i);
}
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.image_list_view, menu);
return true;
}
public void onImageSelected(int position) {
...
}
#Override
public void onBackPressed() {
if (img.getVisibility() == ImageView.VISIBLE){
// img.setVisibility(ImageView.INVISIBLE);
// imageList.invalidateViews();
// imageList.setVisibility(ListView.VISIBLE);
// Here actually I want to use the upper part that I commented, but it didn't work, I have to call the same activity again to see my listview
Intent i = new Intent(MyViewActivity.this, MyViewActivity.class);
startActivity(i);
finish();
}
else {
....
}
return;
}
private class CustomImageListAdapter extends ArrayAdapter<String>{
...
}

As long as I can guess, the problem is caused by
img.setVisibility(ImageView.INVISIBLE);
You can try to use View.GONE instead.
The difference is clearly stated in android api's doc and I quoted:
/**
* This view is invisible, but it still takes up space for layout purposes.
*/
public static final int INVISIBLE = 0x00000004;
/**
* This view is invisible, and it doesn't take any space for layout
*/
public static final int GONE = 0x00000008;
By the way, I will recommend to use fragments to do your job. Specifically, a fragment A to present the listview, and when an item is clicked, switch to fragment B which contains the content. When Back is pressed, just let the backstack do its job.

Intent i = new Intent(MyViewActivity.this, MyViewActivity.class);
i.putExtra("currentObjectID",objectID);
startActivity(i);
finish();
Why are you traversing within the same activity? You should understand the use of intents ,If you want to stay within the same activity , Just set a flag for currentObjectID instead of put Extra..

Related

Control RecyclerView inflated views from outside the adapter: keep selection state

Generally
I want to control the ViewHolder inflated Views of my RecyclerView from outside of the ViewHolder and the RecyclerView classes. In other words, I want to have control of these views from other methods/classes.
My case (en example)
In my specific case, I made a photo gallery activity which allows the user to perform selection and deselection of each inflated view, notifying which items are selected by highlighting them.
For now, the user is able to do that by clicking each generated object / View; then, actions on specific child of RecyclerView / adapter are possible thanks to "setOnClickListener" and "setOnLongClickListener" methods, which perform the corresponding actions in methods inside the ViewHolder class.
But when activity is restarted (i.e. for device rotation) the selection goes lost and the user should perform the selection again (i.e. for deleting photos).
Assuming that positions of the selected photos are kept (for example via bundle, or via an array) is possible to restore selection (i.e. highlighting the corresponding item / views) on the adapter views after that the activity is re-started? If yes, how?
Some code
The code below contains the Recyclerview class and the AdapterView class, which both are child of an activity Class.
private class ImageGalleryAdapter extends RecyclerView.Adapter<ImageGalleryAdapter.MyViewHolder> {
private ArrayList<PhotoObject.PhotoElement> photoAL;
private Context mContext;
public ImageGalleryAdapter(Context context, ArrayList<PhotoObject.PhotoElement> photosToPreviewInGallery) {
mContext = context;
photoAL = photosToPreviewInGallery;
}
#Override
public ImageGalleryAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
// Inflate the layout
View itemView = inflater.inflate(R.layout.item_photo, parent, false);
ImageGalleryAdapter.MyViewHolder viewHolder = new ImageGalleryAdapter.MyViewHolder(itemView);
// Retrieving the itemView
return viewHolder;
}
#Override
public void onBindViewHolder(ImageGalleryAdapter.MyViewHolder holder, int position) {
PhotoObject.PhotoElement previewPhotoInGallery = photoAL.get(position);
ImageView imageView = holder.mPhotoImageView;
GlideApp.with(mContext)
.load(previewPhotoInGallery.getUrl())
.placeholder(R.drawable.ic_cloud_off_red)
.into(imageView);
}
//The method which gives back the number of items to load as photo.
#Override
public int getItemCount() {
return (photoAL.size());
}
// The class that assigns a view holder for each Image and checkbox in the RecyclerView.
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
public ImageView mPhotoImageView;
public CheckBox mPhotoCheckBox;
public MyViewHolder(View item_view) {
super(item_view);
mPhotoImageView = (ImageView) item_view.findViewById(R.id.item_photo_iv);
mPhotoCheckBox = (CheckBox) item_view.findViewById(R.id.item_photo_checkbox);
item_view.setOnClickListener(this);
item_view.setOnLongClickListener(this);
// Retrieving the item_view
}
// The method for managing the click on an image.
#Override
public void onClick(View view) {
itemSelection(view);
}
// Manages the selection of the items.
private void itemSelection(View item) {
// Retrieving the item
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
if (!item.isSelected()) {
// Add clicked item to the selected ones
MultiPhotoShootingActivity.manageSelection(true, position);
// Visually highlighting the ImageView
item.setSelected(true);
mPhotoCheckBox.setChecked(true);
mPhotoCheckBox.setVisibility(View.VISIBLE);
} else {
// Remove clicked item from the selected ones
MultiPhotoShootingActivity.manageSelection(false, position);
// Removing the visual highlights on the ImageView
item.setSelected(false);
mPhotoCheckBox.setChecked(false);
mPhotoCheckBox.setVisibility(View.INVISIBLE);
}
}
}
// The method for managing the long click on an image.
#Override
public boolean onLongClick(View view) {
int position = getAdapterPosition();
if(position != RecyclerView.NO_POSITION) {
Intent intent = new Intent(mContext, PhotoDetail.class);
intent.putExtra("KEY4URL", activityPhotoObject.getPath(position));
startActivity(intent);
}
// return true to indicate that the click was handled (if you return false onClick will be triggered too)
return true;
}
}
}
Thank you for your time.
You shouldn't "control" views from outside the adapter. Instead, Override onSaveState and onRestoreState in your activity. Make same methods in your adapter with passing the bundle to the adapter in order to save state. save an integer array of positions that were selected into the bundle(that you passed into an adapter). In corresponding way, you can get the array of selected positions from the bundle of On restore state.
activity:
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState){
adapter.onRestoreInstanceState(savedInstanceState);
}
in your adapter:
public void onRestoreInstanceState(Bundle state){
selectedItemsArray = state.getIntArray("my_array_key")
}
#Alessandro
You can handle the Runtime changes by yourself.
In your manifest, you can define the changes that your activity will handle by itself and it will not be restarted.
android:configChanges="orientation|keyboardHidden"
After that, you'll have to handle the Configuration changes that you declared in your manifest using this method in your activity:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
// Do your thing
}
}
SOLVED
Find out that for solving the problem I had to accomplish two little tasks:
saving and restoring the selected item selection state (for example via an array, as helpfully suggested by #Inkognito);
retrieving the views for applying the selection, based on the position inside the RecyclerView.
So, I had to modify some code.
Before proceeding, I would like to point out that the Activity class has a sub-class, which is the Adapter class (named ImageGalleryAdapter); the Adapter subclass, in turn, has its own subclass, which is the ViewHolder class (named MyViewHolder).
So: Activity class -> Adapter class -> ViewHolder class
Code modified in the parent class (the activity class, in which the RecyclerView is)
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
adapter.onSaveInstanceState(outState);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
adapter.onRestoreInstanceState(savedInstanceState);
}
In the onSaveInstanceState and onRestoreInstanceState methods, I added the references for saving and restoring instance states of the "adapter" sub-class.
Code added in the adapter class (which is inside the RecyclerView class)
private boolean [] selectedItemsArray;
private void onSaveInstanceState(Bundle outState) {
outState.putBooleanArray("my_array_key" , selectedItemsArray = mpsaPO.getItemsSelected());
}
private void onRestoreInstanceState(Bundle state) {
if (state != null) {
selectedItemsArray = state.getBooleanArray("my_array_key");
}
}
The selectedItemsArray is a boolean array in which the information of which elements of the RecyclerView are selected (true = selected; false = not selected) is contained.
Then, adding this element in the saved instance and retrieved via the activity class, makes the app able to know which are the views selected after that the activity is re-created.
Code added inside the onBindViewHolder method, which is inside the adapter class
if (selectedItemsArray != null) {
if (selectedItemsArray[position]) {
holder.itemView.setSelected(true);
holder.mPhotoCheckBox.setChecked(true);
holder.mPhotoCheckBox.setVisibility(View.VISIBLE);
}
}
With this last part of code, we are applying the selection to the corresponding views based on which items/views were selected before that the activity was saved.
The holer object contains the itemView and mPhotoCheckBox objectsm on which we can perform the selection.

ListView not displaying anything in new activity using array adapter

I've got a class that should, theoretically, display RSS headlines, from a SINGLE RSS feed site, in a ListView called searchListView. If the ListView is empty a TextView appears informing the user that the ListView is empty, which is what happens every time I navigate to this activity. The button and EditText is for filtering the headlines.
I've got the exact same class in another project (this class is the main activity in said project) which works perfectly fine.
RssItem is a class that parses the RSS feed information into a headline title and URL to the headline.
Note: SearchActivity is not the main activity.
Edit: I'm using a CallBack and LoaderManager in the main activity to display items in a list view as well. I'm not too knowledgeable about these and I really don't know if they might be causing the issue due to the main activity. I do not pass any information from the main activity, though.
FIXED: I wasn't getting any errors or anything but, for some reason, nothing would get displayed. Then I went into the android manifest and realised that the app doesn't have permissions to connect to the internet. Silly mistake, easy to miss.
<uses-permission android:name="android.permission.INTERNET"/>
SearchActivity.java
public class SearchActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<List<RssItem>> {
private EditText mEditText;
private Button mButton;
private ArrayAdapter<RssItem> mAdapter;
private ListView mListView ;
// hard wire Rss feed source for the time being
private String mDataSource = "http://feeds.bbci.co.uk/news/uk/rss.xml";
// no search string at the moment
private String mSearchString = "";
private static final int LOADER_ID = 1;
// The callbacks through which we will interact with the LoaderManager.
private LoaderManager.LoaderCallbacks<List<RssItem>> mCallbacks;
private LoaderManager mLoaderManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mButton = (Button) findViewById(R.id.button);
mEditText = (EditText)findViewById(R.id.editTextSearch);
mAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1);
mListView = (ListView)findViewById(R.id.searchListView);
mListView.setAdapter(mAdapter);
TextView emptyText = (TextView)findViewById(R.id.textViewEmpty);
mListView.setEmptyView(emptyText);
// Set list view item click listener
mListView.setOnItemClickListener(new ListListener(this));
// The Activity (which implements the LoaderCallbacks<Cursor>
// interface) is the callbacks object through which we will interact
// with the LoaderManager. The LoaderManager uses this object to
// instantiate the Loader and to notify the client when data is made
// available/unavailable.
mCallbacks = this;
// Initialize the Loader with id '1' and callbacks 'mCallbacks'.
// If the loader doesn't already exist, one is created. Otherwise,
// the already created Loader is reused. In either case, the
// LoaderManager will manage the Loader across the Activity/Fragment
// lifecycle, will receive any new loads once they have completed,
// and will report this new data back to the 'mCallbacks' object.
mLoaderManager = getLoaderManager();
mLoaderManager.initLoader(LOADER_ID, null, mCallbacks);
}
// handler for search button click
public void onClick(View v){
mSearchString = mEditText.getText().toString();
mLoaderManager.restartLoader(LOADER_ID, null, mCallbacks);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public Loader<List<RssItem>> onCreateLoader(int id, Bundle args) {
RssLoader loader = new RssLoader(
this, // context
mDataSource, // URL of Rss feed
mSearchString // search loaded RssItem for match in title
);
return loader;
}
#Override
public void onLoadFinished(Loader<List<RssItem>> loader, List<RssItem> data) {
mAdapter.clear();
mAdapter.addAll(data);
}
#Override
public void onLoaderReset(Loader<List<RssItem>> loader) {
mAdapter.clear();
}
}
ListListener.java
public class ListListener implements OnItemClickListener {
// And a reference to a calling activity
// Calling activity reference
Activity mParent;
/** We will set those references in our constructor.*/
public ListListener(Activity parent) {
mParent = parent;
}
/** Start a browser with url from the rss item.*/
public void onItemClick(AdapterView<?> parent, View view, int pos, long id) {
// We create an Intent which is going to display data
Intent i = new Intent(Intent.ACTION_VIEW);
// We have to set data for our new Intent;
i.setData(Uri.parse(((RssItem)(parent.getItemAtPosition(pos))).getLink()));
// And start activity with our Intent
mParent.startActivity(i);
}
}
I wasn't getting any errors or anything but, for some reason, nothing would get displayed. Then I went into the android manifest and realised that the app doesn't have permissions to connect to the internet. Silly mistake, easy to miss.
<uses-permission android:name="android.permission.INTERNET"/> was missing.

Is there a way to hide specific listview items from the main activity?

Just wondering if what I'm trying to do is possible. So i have a custom adapter for a listview. It contains a textview and two buttons. I would like one of the listview buttons to remain hidden unless a specific button is pressed on the main activity.
So far I have the listview buttons performing their intended function but I have no idea how I would even begin to get what I'm wanting.
Sorry, for clarification, I have one button completely separate from the listview that is just always there. When I press this button I would like to toggle the visibility of a button that is on each listview item all together. The best example of this that I can think of is having a list of items and a button that can toggle off the 1. 2. 3. 4. that comes in front of each item.
Create a method in your adapter for knowing you have clicked the button from your main activity like this
public void buttonIsClicked(){ //in your adapter
buttonhide.setVisibility(visibility?View.VISIBLE:View.GONE);
}
And call this method from your activity on btnclick.
like
yourAdapter.buttonIsClicked();
and call this method for notifying the adapter about the change.
yourAdapter.notifyDatasetChanged().
or
You can use an interface for listening to the clicks in main activity and implement that listener in your adapter
Set visibility gone to the button you want to hide by calling code
buttonhide.setVisibilty(VIEW.GONE);
hide it in oncreate() of your activity and make it shown on the button click event by calling code buttonhide.setVisibilty(VIEW.VISIBLE);
Below is the code
btnView.setVisibility(View.GONE);
yes it is possible to do that.
First have a Model class to back the listview data and keep a flag in that model which indicates whether to show the button in that row's data model. On certain condition change that model's flag and call notifyDataSetChanged() on adapter.
Ex:
class Model{
String label;
boolean showBtn;
}
in adapter's getView()
Model model = list.get(position)
if(model.showBtn){
btn.setVisibility(View.VISIBLE);
}else{
btn.setVisibility(View.GONE);
}
in Activity
disableButton(){
modelList.get(0).setShowBtn(false);
adapter.notifyDataSetChanged();
}
This code will hide button in first row
Add a Boolean value in your dataset which represent the Visibility state of the button.
public class Dataset {
private boolean visible;
public boolean isVisible() {
return this.visible;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
//..more items
}
Then in your getView method of the Adapter check this Boolean value to show/hide the button.
boolean visibility = yourDataset.get(position).isVisible();
yourButton.setVisibility(visibility?View.VISIBLE:View.GONE);
And when the Button outside of your listview is clicked Update your dataset. And call yourAdapter.notifyDatasetChanged().
What you are attempting is: manipulating the visibility of the button declared in the Adapter from the containing activity. Simple, put a controlling variable in the activity and pass it a parameter to adapter.
Boolean mShowButton; //a controlling variable
void onCreate(Bundle savedInstanceState) {
...
mAdapter=new MyAdapter(...,mShowButton);
mButton.setOnClickListener(actionShow );
}
OnClickListener actionShow = new OnClickListener() {
#Override
public void onClick(View button) {
mShowButton=true;
mAdapter.notifyDataSetChanged();
mListView.invalidateViews();
}
};
And do this in your adapter,
Boolean showButton;
public MyAdapter(Context context, List<String> myList, Boolean showButton) {
...
this.showButton=showButton;
}
public View getView(int position, View rowView, ViewGroup parent) {
...
if(showButton){
mButtonTwo.setVisibility(View.GONE);
}else{
mButtonTwo.setVisibility(View.VISIBLE);
}
}

Android to display a text on Text View from String-array items and changing it on left and right swipe

I am just days old to android.In my application I have a List View displaying planets name, and when user clicks on the list view item i.e any of the planet name, another activity will gets opened in respect of which planet is clicked on list view, like suppose if user choose "earth", an activity gets opened having Text View display and on that text view, I am displaying some facts(say 10 facts) about planet Earth that I have stored in string-array items(displaying only 1 fact at a time). Now, when user swipes left or right,the text gets changed depending on whether it is swiped left or right.
Tasks that I've managed to perform
I am able to set the list view items i.e lists of planet and I've implemented the onItemSelectListener() to it.
I've created the 9 activities also for each planet and I am able to call the particular activity for which the item is clicked using Intent().
I have declared the facts for each planet in string-array items.But don't know how to set them on Text View.
Tasks that I'm trying to achieve
Like when click on Earth, I am starting another activity that is displaying the first fact from the string-array items. I want when user swipes left or right, the second fact will gets displayed.
P.S.. Though I am able to change the facts from string-array items, but for that I was using next and previous buttons in which I using a counter, but I want to use the swipe.
I tried several tuts about swipes but did understand much. Please help and suggest.
One more thing, I am having a Samsung Galaxy Y S5360, how to install plug-ins in it, so that I can test my application directly because my emulator sucks.(i've heard using Kies slows down the system-any other alternative you can offer)
Thanks a lot
MainActivity.java
public class MainActivity extends Activity {
ListView lv;
String[] list = new String[] { "Mercury","Venus","Earth","Mars","Jupiter",
"Saturn","Uranus","Neptune","Pluto" };
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv = (ListView) findViewById(R.id.lv);
ArrayAdapter<String> adps = new ArrayAdapter<String>(
getApplicationContext(), android.R.layout.simple_list_item_1,
list);
lv.setAdapter(adps);
lv.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int pos,
long arg3) {
// TODO Auto-generated method stub
switch (pos) {
case 0:
Intent intent = new Intent(MainActivity.this,
Mercury.class);
startActivity(intent);
break;
// similarly for all other 8 cases
default:
break;
}
}
});
// final String[] quo = getResources().getStringArray(R.array.quotes);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
Mercury.java
public class motivatinal extends Activity {
int counter = 0;
TextView mercury;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.motivational);
String[] mer = getResources().getStringArray(R.array.motivational);
mercury.setText(mer);
// do not know how to display string array items on text view.
// mercury.settext is showing error.
}
}

ListView.getChildAt(validPosition) returns null

When user clicks on item of ListView I show Edit button at this item of list. lastSelectedPosition has the position of the list item that was clicked last.
code:
public class MainActivity extends Activity {
private ListView listView;
private MyAdapter adapter;
// static - If the activity is re-created, the data
// about list items remain.
private static List<String> items = loadItems();
private MyItemClickListener listener = new MyItemClickListener();
private int lastSelectedPosition = ListView.INVALID_POSITION;
#Override
protected void onCreate(Bundle savedInstanceState) {
listView = (ListView) findViewById(R.id.myListView);
adapter = new MyAdapter(R.layout.my_item, items);
listView.setAdapter(adapter);
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
listView.setOnItemClickListener(listener);
if (savedInstanceState != null) {
// Is recreating the activity because
// of the change screen orientation.
lastSelectedPosition = savedInstanceState.getInt("lastSelectedPos");
if (lastSelectedPosition != ListView.INVALID_POSITION) {
// !!! getChildAt() always returns null !!!
View listItem = listView.getChildAt(lastSelectedPosition);
View editButton = listItem.findViewById(R.id.editButton);
// Only selected list item has visible EditButton,
// other list items have not
editButton.setVisibility(View.VISIBLE);
}
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
// Is destroying the activity because
// of the change screen orientation.
outState.putInt("lastSelectedPos", lastSelectedPosition);
}
// Other methods
}
I think that getChildAt() always returns null in Activity.onCreate(), because at that moment the list is not yet fully developed. How I can get View of list item to show Edit button on it?
And sorry for my English.
Thanks
Your adapter needs to know about this selected position so it can be rendered properly in getView(). Just modify the constructor for your adapter to take the int, and update that int value whenever the onclick is called. In general, you should always have all the information you need to recreate the state of your list items within your adapter.
I think it is because you didn't change your lastSelectedPosition's value when user click on item in your listview. Just implement your onItemClickListener like the following code snippet. And change your lastSelectedPosition's value on this. And remove your
private MyItemClickListener listener = new MyItemClickListener();
line.
I think the value of lastSelectedPosition is couldn't changed until you define your listener variable. And also I didn't know where you define your listener variable.
lv1.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
lastSelectedPosition = arg2
}
});
I hope this will help you.

Categories

Resources