I am using a ListFragment for displaying a list from a database in my activity. I have included a search function. Unfortunately the "old" ListFragments seem to remain in the background and the ListFragments containing the result of the query are displayed on top of it. How can I avoid, that the old ListFragments are displayed?
My FragmentActivity:
private Button buttonSearch;
private TextView searchString;
public static String search = null;
static IShoppinglist shoppinglistManager;
static IAktionen aktionenManager;
private AktionenListListFragment listFragment;
#Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "ListFragmentActivity created");
super.onCreate(savedInstanceState);
setContentView(R.layout.articlelist);
shoppinglistManager = new Shoppinglist(this);
aktionenManager = new Aktionen(this);
buttonSearch = (Button) findViewById(R.id.search_Button);
buttonSearch.setOnClickListener(searchListAktionen);
//show all entries on start
listFragment = new AktionenListListFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_articlelist, listFragment).commit();
}
OnClickListener searchListAktionen = new OnClickListener() {
public void onClick(View v) {
try{
searchString = (TextView) findViewById(R.id.input_search_bezeichnung);
search = searchString.getText().toString().trim();
Log.d(TAG, "search Button clicked "+search);
if(search.trim().length()==0){
search=null;
}
//show all entries on start
listFragment = new AktionenListListFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_articlelist, listFragment).commit();
}catch(Exception ex){
ex.printStackTrace();
}
}
};
Thanks in advance,
update:
thank you for your answers. I tried to implement them, but the main problem seems to be nowthat the onCreate and onActivityCreated method in the ListFragment are called twice (as I can see in my log messages).
my new code:
#Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "ListFragmentActivity created");
super.onCreate(savedInstanceState);
//force commit
getSupportFragmentManager().executePendingTransactions();
if(getSupportFragmentManager().findFragmentByTag(tag) == null) {
setContentView(R.layout.articlelist);
shoppinglistManager = new Shoppinglist(this);
aktionenManager = new Aktionen(this);
buttonSearch = (Button) findViewById(R.id.search_Button);
buttonSearch.setOnClickListener(searchListAktionen);
listFragment = new AktionenListListFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_articlelist, listFragment,tag).commit();
}else{
Log.d(TAG, "ListFragment already exists");
}
}
I tried to set a unique tag for my ListFragment but this solution does not work.
I guess that one of the ListFragments is displayed in the background and the other is updated.
So first you need to stop making new ListFragments everytime your list is refreshed and just have a public method in your ListFragment that the Activity can call to restart the loader with the proper parameters. Then:
In your onLoadFinished(),
you should make a new adapter with the list you want to replace it with
myAdapter = new AktionenListCustomCursorAdapter(getActivity(), myCursor);
and call:
this.getListView().setAdapter(myAdapter);
So:
public void onLoadFinished(Loader<Cursor> mAdapter, Cursor myCursor) {
if(myCursor!=null){
//getting the data from the database
Log.d(TAG, "search String "+AktionenListFragmentActivity.search);
if(AktionenListFragmentActivity.search==null){
myCursor = AktionenListFragmentActivity.aktionenManager.fetchAllArticles();
}else{
myCursor = AktionenListFragmentActivity.aktionenManager.fetchItemsByBezeichnung(AktionenListFragmentActivity.search);
}
myAdapter = new AktionenListCustomCursorAdapter(getActivity(), myCursor);
this.getListView().setAdapter(myAdapter);
}
}
Hopefully this solved your question as I understood it. If you have any questions please leave it in the comment below and I will expand my answer. If it worked for you please accept answer. :D
Related
I have a RecyclerView inside a AppCompatActivity. Item insertions and changes are shown and animated correctly after rotating the device.
The problem happens when you:
Tap on an item in the RecyclerView.
A DialogFragment opens prompting if you want to the delete the item.
Rotate the device.
Confirm the deletion in the dialog.
Check the array list. The item has been deleted.
The RecyclerView still shows the item.
Tried using notifyDataSetChanged instead of notifyItemRemoved but didn't work either because the item is still being shown in the RecyclerView.
This is happening with any version of Android.
Simplified code of how the process is being handled:
public class MyAppCompatActivity extends AppCompatActivity {
int positionOfDeletedItem;
MyObjectRecyclerViewAdapter adapter;
ArrayList<MyObject> someTestData;
MyItemDeletionHandler deletionHandlerRemover;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity_layout);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
positionOfDeletedItem = 1;
deletionHandlerRemover = new MyItemDeletionHandler(this);
someTestData = new ArrayList<MyObject>(3);
someTestData.add(new MyObject("A"));
someTestData.add(new MyObject("B"));
someTestData.add(new MyObject("C"));
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new MyObjectRecyclerViewAdapter(new MyAdapterOnClickEvent.OnItemClick() {
#Override
public void onClick(int posicion, int idViaje, View view) {
String tag = "Some tag value";
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment prev = getSupportFragmentManager().findFragmentByTag(tag);
if(prev != null)
ft.remove(prev);
ft.addToBackStack(null);
DialogFragment newFragment = MyDeletionConfirmationDialog.newInstance(deletionHandlerRemover);
newFragment.show(ft, tag);
}
}, someTestData);
recyclerView.setAdapter(adapter);
}
private final static class MyItemDeletionHandler extends Handler {
private final WeakReference<MyAppCompatActivity> theActivity;
private MyItemDeletionHandler(MyAppCompatActivity act) {
theActivity = new WeakReference<MyAppCompatActivity>(act);
}
#Override
public void handleMessage(Message msg) {
MyAppCompatActivity activity = theActivity.get();
if(activity != null) {
if(msg.what == 1) {
activity.deleteTheItem();
}
}
}
}
public void deleteTheItem() {
someTestData.remove(positionOfDeletedItem);
adapter.notifyItemRemoved(positionOfDeletedItem);
}
}
public class MyDeletionConfirmationDialog extends DialogFragment {
private Message handlerMessage;
public static MyDeletionConfirmationDialog newInstance(Handler callbackHandler) {
MyDeletionConfirmationDialog myDialog = new MyDeletionConfirmationDialog();
Bundle args = new Bundle();
args.putParcelable("handlerMessage", callbackHandler.obtainMessage(1, true));
myDialog.setArguments(args);
return myDialog;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handlerMessage = getArguments().getParcelable("handlerMessage");
}
#Override
#NonNull
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
alertDialogBuilder.setMessage("Some message");
alertDialogBuilder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
final Message toSend = Message.obtain(handlerMessage);
toSend.sendToTarget();
}
});
alertDialogBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
Dialog dialog = alertDialogBuilder.create();
dialog.setCanceledOnTouchOutside(true);
return dialog;
}
}
How can I get the RecyclerView to work correctly?
Edit 1:
I have other RecyclerViews in which this works correctly. The only difference is those are inside Fragments instead of AppCompatActivity. I am suspecting that this has something to do with the events onDetachedFromWindow and onAttachedToWindow of the RecyclerView.
Edit 2:
If the dialog is closed (step 4) and opened again it works as expected.
Edit 3:
If the RecyclerView is extracted as a Fragment the problem disappears and works as intended. It is impossible to have the use case described above working correctly in conjunction with AppCompatActivity instead of a Fragment.
I was facing a similar problem with RecyclerView.
When I swiped left to delete an item and then rotate the screen, the item was removed from my dataset but the screen wasn't refreshing like it normaly does when we do the same action without rotating. It seems the adaptar.notifyItemRemoved() wasn't refreshing the screen at all.
I'm using the Nemanja Kovacevic source code as starting point, but I did some changes on it (like adding item click, edit with a dialog, database support, etc).
So I read this post which gave me a hint about what could be going wrong.
It seems the adapter.notify was still pointing to the previous adapter referece before rotation. Every time we rotate a new adapter is created at the Activity:OnCreate
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener,
AddAlertDialog.OnAlertSavedListener,
AlertListAdapter.OnItemDeletedListener {
static ListAdapter mListAdapter;
RecyclerView mRecyclerView;
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
mRecyclerView = (RecyclerView) findViewById(R.id.mainListView);
mDB = new DatabaseTable(this);
// Reading all alerts
ArrayList<Alert> alerts = mDB.getAllAlerts();
if (mListAdapter == null)
mListAdapter = new ListAdapter(this, alerts);
}
}
Maybe it is not ideal (creating static objects is not a good idea), but it solved the problem.
I hope it may help you too.
I have two activities, in the main one I have a text field and two buttons, the user can enter text in the text field.
When clicking the add button,text will be added to some ArrayList.
When clicking show in list button a new activity with its own fragment should open showing a listview that contains the names that the user has entered.
I used ArrayAdapter and this is working fine. When I am in the list activity and when I click the back button of the device everything goes fine and the data in the ArrayList is not lost.
If I click show in list again I will find the old data I entered at the first time. But, if I click the back icon provided by Android at the top left of the device screen, the ArrayListbecomes empty and when I click show in list the listview shows as empty.
Here is the main activity code,
public class MainActivity extends ActionBarActivity {
String LOG_TAG = this.getClass().getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ArrayList<String> itemList= new ArrayList<String>();
final EditText text = (EditText) findViewById(R.id.text_field);
text.setHint("Enter name here");
Button addButton = (Button) findViewById(R.id.add_button);
Button showButton = (Button) findViewById(R.id.show_button);
addButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String name= text.getText().toString();
itemList.add(name);
if (itemList.size()==1){
Toast.makeText(getApplicationContext(), "one", Toast.LENGTH_SHORT).show();
}
Toast.makeText(getApplicationContext(), "name has been added to the list", Toast.LENGTH_SHORT).show();
}
});
showButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent (getApplicationContext(), ListActivity.class);
intent.putExtra("list", itemList);
startActivity(intent);
}
});
}//end oncreate
This is the ListActivity and its fragment code,
public class ListActivity extends ActionBarActivity {
static ArrayList <String> itemList;
String LOG_TAG = this.getClass().getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
itemList= getIntent().getStringArrayListExtra("list");
setContentView(R.layout.list_activity);
if (savedInstanceState==null){
getSupportFragmentManager().beginTransaction().add(R.id.container, new list()).commit();
}
}
public static class list extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,false);
ListView listView = (ListView) rootView.findViewById(R.id.list);
ArrayAdapter <String> adapter= new ArrayAdapter<String>(getActivity(),R.layout.fragment_main, R.id.row, itemList);
listView.setAdapter(adapter);
return rootView;
}
}
}
Can anyone please tell me why this is happening? How can I solve this issue?
Any help is appreciated.
Many thanks.
create a class Constantss.java and declare
public static ArrayList <String> itemList=null;
then inside your class
use
Constantss. itemList.add(name);
instead of
itemList.add(name);
// replace itemList with Constantss. itemList in all of your classes
I believe this is a navigation issue. So you should close your ListActivity like this:
public class ListActivity extends ActionBarActivity {
//your code
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int itemID = item.getItemId();
switch (itemID ) {
case android.R.id.home:
this.finish();
return true;
}
return super.onOptionsItemSelected(item);
}
}
Anyway your data can be lost if android destroys your MainActivity. So if you navigate from ListActivity back to MainActivity, MainActivity will be recreated and you data get lost. So you should find the way how to save your
data permanent.
there are two common ways:
Save data to data base (SQLite)
Save data to Preferences How to store list of values in SharedPreferences
Fairly new to android programming and having trouble changing the string value "channel" when a button is clicked. Having issues trying to close the onCreate but it only seems to let me close it at the end of the activity. I get an error of 'token "}". please delete' if i try to close it elsewhere. I'm having a hard time trying to wrap my head around this even though it's probably very simple.
public class MainActivity extends Activity {
String channel = "bbc1";
// This method creates main application view
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set view
setContentView(R.layout.main);
final ViewSwitcher switcher = (ViewSwitcher)findViewById(R.id.ViewSwitcher1);
Button bbcButton = (Button) findViewById(R.id.bbcButton);
Button bbc2Button = (Button) findViewById(R.id.bbc2Button);
bbcButton.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
channel = "bbc1";
switcher.showNext();
}
});
bbc2Button.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
channel = "bbc2";
switcher.showNext();
}
});
try{
// This line creates RSS reader
RssReader rssReader = new RssReader("http://bleb.org/tv/data/rss.php?ch="+channel+"&day=0");
// This line gets a ListView from main view
ListView tvItems = (ListView) findViewById(R.id.listMainView);
// This line creates a list adapter
ArrayAdapter<RssItem> adapter = new ArrayAdapter<RssItem>(this,android.R.layout.simple_list_item_1, rssReader.getItems());
// This line sets list adapter for the ListView
tvItems.setAdapter(adapter);
} catch (Exception e) {
Log.e("Tv RSS Reader", e.getMessage());
}
}
}
I'm guessing that you want to change the RSS feed when you press the button. But since you are fetching the RSS info in the onCreate, you won't update the data, even though you are pressing the buttons. But you are changing the value of the string channel.
onCreate is only called once when you create the activity!
Try moving the try-statement into a seperate method and call this method in your two onClickListeners.
bbc2Button.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
channel = "bbc2";
updateRSS();
switcher.showNext();
}
});
public void updateRSS(){
try{
// This line creates RSS reader
RssReader rssReader = new RssReader("http://bleb.org/tv/data/rss.php?ch="+channel+"&day=0");
// This line gets a ListView from main view
ListView tvItems = (ListView) findViewById(R.id.listMainView);
// This line creates a list adapter
ArrayAdapter<RssItem> adapter = new ArrayAdapter<RssItem>(this,android.R.layout.simple_list_item_1, rssReader.getItems());
// This line sets list adapter for the ListView
tvItems.setAdapter(adapter);
} catch (Exception e) {
Log.e("Tv RSS Reader", e.getMessage());
}
i have two activity files in my code, and the first activity file loads the layout search, and the second file loads layout list. I have a textbox in layout search and enter some text. I want to use this text in my second activity file but i can not reach it since it is in the layout search. How can i do this? Here the first activity file, here there is an EditText item called searchedText, and i want to use it in the second activity file.
public class SearchActivity extends Activity{
public EditText searchedText;
public RadioGroup radioGroup;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.search);
}
public void onStart(){
super.onStart();
searchedText = (EditText) findViewById(R.id.searchText);
Button searchinSearchButton = (Button)findViewById(R.id.searchInSearch);
radioGroup = (RadioGroup) findViewById(R.id.radioGroup1);
searchinSearchButton.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
String searched=searchedText.getText().toString();
Intent myIntent = new Intent(v.getContext(),
SearchListActivity.class);
startActivityForResult(myIntent, 1);
}
});
}
}
And here is the second activity file:
public class SearchListActivity extends Activity{
public DatabaseAdapter db;
public ArrayList<String> myList;
public ListView listview;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list);
db = new DatabaseAdapter(this);
myList = new ArrayList<String>();
getContacts();
// Example of retrieving tweets of the user "mashable" and adding them to
myList
/*
ArrayList<Tweet> tweets= new ArrayList<Tweet>();
tweets.addAll(Twitter.getTimeline("mashable", 10));
for(Tweet t: tweets){
myList.add(t.username + ": " + t.message + " Tweet id: "+ t.id);
}
*/
printList();
}
public void printList(){
listview = (ListView)findViewById(R.id.contactcListView);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, android.R.id.text1, myList);
listview.setAdapter(adapter);
}
public void getContacts() {
db.open();
Cursor c = db.getContactbyName("y");
if (c.moveToFirst()) {
do {
DisplayContact(c);
} while (c.moveToNext());
}
db.close();
}
public void DisplayContact(Cursor c) {
String entry = "";
// if you add another attribute to your table, you need to change 3 into x
for (int i=1; i<5;i++){
entry += c.getString(i) + "\n";
}
myList.add(entry);
}
}
In this second activity file, you can see the getContacts() method. There, i search by Cursor c = db.getContactbyName("y"); but instead of "y", i want to search whatever user enters the texbox, whic is in the 1st activity file called searchedText. How can i do this?
Thanks
Send the text as an extra in your Intent when you start your second activity.
searchinSearchButton.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
String searched=searchedText.getText().toString();
Intent myIntent = new Intent(v.getContext(),
SearchListActivity.class);
myIntent.putExtra("SEARCH_STRING",searched);
startActivityForResult(myIntent, 1);
}
});
And in your onCreate get the extra. You could use Intent.getStringExtra(String name)
In other words:
mySearched = getIntent().getStringExtra("SEARCH_STRING");
Just make sure to see if anything is null before using it.
I've some database that i update with a service, and i want to update my listView on resume, or refresh it from time to time with the new data in it, but it's not working.
Here is my code (the code in comment is not working and sometimes make the app crash)
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
taskLiteApplication = ((TaskLiteApplication)getApplicationContext());
listGroupTask = taskLiteApplication.getCtrlGroupTask().getListGroupTaskToDoAndToReview(taskLiteApplication.getUser());
Log.d(TAG, "nbtask to do an to review from DB :"+listGroupTask.size());
if(listGroupTask.size() > 0) {
setContentView(R.layout.to_do_layout);
ListView lv = (ListView) findViewById(R.id.ListViewGroupTaskToDoToDo);
//set adapter
groupTaskToDoBaseAdapter = new GroupTaskToDoBaseAdapter(this, listGroupTask);
lv.setAdapter(groupTaskToDoBaseAdapter);
} else {
TextView textView = new TextView(this);
textView.setText("No tasks to do found!");
setContentView(textView);
}
}
public void onResume() {
super.onResume();
//listGroupTask = taskLiteApplication.getCtrlGroupTask().getListGroupTaskToDoAndToReview(taskLiteApplication.getUser());
//groupTaskToDoBaseAdapter.notifyDataSetChanged();
Log.d(TAG, "on resume");
}
What exactly are your trying here:
listGroupTask = taskLiteApplication.getCtrlGroupTask().getListGroupTaskToDoAndToReview(taskLiteApplication.getUser());
Do you want a completely new set of data for your ListView. If so then implement some methods in your Adapter like add/remove/delete/replaceData and so on and after that call the
groupTaskToDoBaseAdapter.notifyDataSetChanged();