I have a main activity with three fragments. In the first fragment is a listview. I populate it in the fragment's onCreateView method like this:
private ArrayList<MobileNETDistinctChatInfo> m_parts = new ArrayList<MobileNETDistinctChatInfo>();
public MobileNETDistinctChatInfoAdapter m_adapter;
public ListView list;
public String logged_user;
onCreateView(){
LinearLayout view = (LinearLayout) inflater.inflate(R.layout.tab1, container, false);
list = (ListView)view.findViewById(R.id.chats_list)
m_parts = db.MESSAGES_getAllDistinctChatInfo(logged_user);
// adapter extends the ArrayAdapter
m_adapter = new MobileNETDistinctChatInfoAdapter(getActivity(), R.layout.chatlist_list_item, m_parts);
list.setAdapter(m_adapter);
return view;
}
I would like to refresh the listview in the onResume() method in fragment1, but I can't get it to work. I tried these two methods (If I use the first method, nothing happens. If I use the second, the app crashes, returning a NullPointerException):
# 1
public void onResume() {
super.onResume();
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
m_adapter.notifyDataSetChanged();
}
}
}
# 2
public void onResume() {
super.onResume();
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
m_parts.clear();
m_parts = db.MESSAGES_getAllDistinctChatInfo(logged_user);
ListView list = (ListView) getActivity().findViewById(R.id.chats_list);
MobileNETDistinctChatInfoAdapter caa = (MobileNETDistinctChatInfoAdapter) list.getAdapter();
caa.clear();
for(MobileNETDistinctChatInfo el : m_parts){
caa.add(el);
}
list.setAdapter(caa);
}
}
}
I've printed the size of m_parts and m_adapter in OnResume() and it seems the adapter isn't being refreshed, but m_parts is. Does anybody know why, or how I can solve this?
You are running a m_adapter.notifyDataSetChanged() in a separate thread which leads the execution of refreshing the list before even the list is modified or updated actually.
if you debeg your code then you can see that it is working fine because the thread got enough time to get executed.
Related
I wanna add items to my list but it only shows the first one:
public class MainActivity extends Activity {
Server server;
TextView infoip, msg;
TextView usersTitle;
String[] array = {"a"};
ArrayList<String> lst;
ArrayAdapter<String> adapter;
ListView userList;
#Override
public void onCreate(Bundle savedInstanceState) {
lst = new ArrayList<String>(Arrays.asList(array));
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, lst);
userList = (ListView) findViewById(R.id.userList);
userList.setAdapter(adapter);
From this other class method, everytime it is called I want the text to go below the first one. The method certainly runs but it does not put the text below the previous one. It just shows "a"! Anyone knows why?
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
activity.lst.add(message);
activity.adapter.notifyDataSetChanged();
}
});
I have also tried:
adapter.insert(String, int);
lst.add(int, String);
And even added in the onCreate method this:
lst.add(1, "2");
adapter.notifyDataSetChanged();
And still doesnt add the "2"!!
If you are adding items to Arraylist from another class ,you have to declare your Arraylist Static.So that it can hold items in memory.
Replace ArrayList lst with public static ArrayList
Here is the solution to your Problem.I have created an Activity class and Tests java class.
public class MainActivity extends Activity {
String[] array = {"a"};
public static ArrayList<String> lst;
ArrayAdapter<String> adapter;
ListView userList;
Tests tests = new Tests();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
userList = (ListView) findViewById(R.id.userList);
lst = new ArrayList<String>(Arrays.asList(array));
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, lst);
userList.setAdapter(adapter);
tests.callThread();
}
}
Here is the Tests.java Class
public class Tests {
int i = 0;
String message = "";
Thread runOnUiThread;
public void callThread()
{
new Thread(new Runnable() {
#Override
public void run() {
try {
while (i < 10) {
i = i + 1;
message = String.valueOf(i);
//Create a server socket object and bind it to a port
MainActivity.lst.add(message);
}
}catch(Exception e){
e.printStackTrace();
}
}
}).start();
}
}
Just call your service inside this thread where I have incremented variable i and by this way you can populate the list in right order.
Can you tell whether the other class is Activity or Fragment ?
And while adding the data into Arraylist, you don't need the Thread to be run in order to insert new data to Arraylist
Try to make "lst" and "adapter" both static.
I'm suspicious about the runOnUiThread. Can you provide more information why did you use this function? Also i highly recommend using RecyclerView
Also you can refer to this post for adding items to RecyclerView
I have read some similar questions and and i have tried to get it work but i can't understand why my adapter is not updating my recyclerview after return from my SaveItem activity. So i have two tabs: ALL notes and Favourite notes. To be more specific: App image
.
When i press the floating action button from the bottom it starts a new activity where i can record a new note, but when i return to MainActivity the first fragment it's not updating my recyclerview:
Here is where I fill my adapter:
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
adapter = new NoteAdapter(fillAdapter(),this,getActivity());
recycler.setAdapter(adapter);
recycler.setLayoutManager(new LinearLayoutManager(getActivity(),LinearLayoutManager.VERTICAL,false));
}
Here is where I try to update my recyclerview:
#Override
public void onResume() {
super.onResume();
adapter.addAll(fillAdapter());
recycler.setAdapter(adapter);
}
Here is my addAll method:
public class NoteAdapter extends RecyclerView.Adapter<NoteAdapter.ViewHolderNote> {
// Other codes....
public void addAll(List<Note> newNotes) {
this.notes.clear();
this.notes.addAll(newNotes);
this.notifyDataSetChanged();
}
}
Take a list of Note in your Fragment class.
private List<Note> allNotes;
Then inside your onActivityCreated
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
allNotes = fillAdapter();
adapter = new NoteAdapter(allNotes, this, getActivity());
recycler.setAdapter(adapter);
recycler.setLayoutManager(new LinearLayoutManager(getActivity(),LinearLayoutManager.VERTICAL,false));
}
Now to update your list call the fillAdapter function again to popuate the allNotes list again and modify your onResume like this.
#Override
public void onResume() {
super.onResume();
allNotes = fillAdapter();
adapter.notifyDatasetChanged();
}
The addAll function has no necessity right now. Remove the function from your NoteAdapter.
The key thing is the reference of your list which is being passed to the adapter.
How can I create a pull down to refresh list in android?
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pull_to_refresh);
// Set a listener to be invoked when the list should be refreshed.
((PullToRefreshListView) getListView()).setOnRefreshListener(new OnRefreshListener() {
#Override
public void onRefresh() {
// Do work to refresh the list here.
new GetDataTask().execute();
}
});
mListItems = new LinkedList<String>();
mListItems.addAll(Arrays.asList(mStrings));
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, mListItems);
setListAdapter(adapter);
}`
This is not an android design pattern. However, this excellent library lets you do it easily. Have a look at the examples.
Hope I helped.
Edit -- 12/06/2015 -- Disregard the previous statement:
This is now a design pattern that is fully supported by the SDK on Android.
It is very simple, you need to use a SwipeRefreshLayout as the parent view to your list (or other data you might want to refresh). You can put any view as a child, it will create a Pull-To-Refresh animation for that view.
Aftewards, you just need to implement SwipeRefreshLayout.OnRefreshListener to handle the network code of the actual data refresh:
public class MainActivity extends FragmentActivity implements OnRefreshListener {
private SwipeRefreshLayout _pullToRefreshLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_main);
_pullToRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_layout);
_pullToRefreshLayout.setOnRefreshListener(this);
super.onCreate(savedInstanceState);
}
#Override
public void onRefresh() {
//When this is called, your view has a little loader showing to show the user that a network call is in progress
Log.i("SO17065814", "Starting refresh...");
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
mSwipeRefreshLayout.setRefreshing(false); //This stops the refresh animation
Log.i("SO17065814", "Ending refresh...");
}
}, 5000);
}
}
I have a Tabs Activity that contains Fragments for tabs. One of the tabs displays a list of data from a SQLite databse table (or a different Fragment if the table is empty). When initially creating the tabs, the Tabs Activity checks to see if the table contains any data. If it does, then it initialises the list Fragment but doesn't set up the CursorAdapter. The CursorAdapter is initialised by an AsyncTask which syncs the SQLite database with a central database, and then creates the Cursors and CursorAdapters. The list Fragment displays a ProgressDialog while waiting for the AsyncTask to create the CursorAdapter. When the CurserAdapter is initialised, the ProgressDialog is dismissed but the ListView remains on its 'empty list' view, despite calls to notifyDataSetChanged(). If I switch tabs and come back, the ListView displays the data correctly. How can I make the ListView update once the CursorAdapter has been initialised?
Relevant bits of code:
Tabs:
private static ImageCursorAdapter friendCursorAdapter = null;
public static ImageCursorAdapter getFriendsListAdapter() {
return friendCursorAdapter;
}
public static void setFriendsListAdapter(ImageCursorAdapter adapter) {
friendCursorAdapter = adapter;
friendCursorAdapter.notifyDataSetChanged();
}
SyncTask:
protected Void doInBackground(Void... params) {
sql = "SELECT COUNT(*) FROM " + WhereWolfOpenHelper.FRIEND_TABLE_NAME;
statement = db.compileStatement(sql);
count = statement.simpleQueryForLong();
if(count>0) {
friendCursor = db.query(WhereWolfOpenHelper.FRIEND_TABLE_NAME, null, null, null, null, null, WhereWolfOpenHelper.FRIEND_FIRST_NAME_COLUMN+", "+WhereWolfOpenHelper.FRIEND_LAST_NAME_COLUMN);
}
statement.close();
}
#Override
protected void onPostExecute(Void param) {
if(friendCursor!=null) {
ImageCursorAdapter adapter = new ImageCursorAdapter(WhereWolfActivity.this, friendCursor, 0, ImageCursorAdapter.FRIENDS);
Tabs.setFriendsListAdapter(adapter);
}
}
FriendsList:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setListAdapter(Tabs.getFriendsListAdapter());
}
#Override
public void onStart() {
super.onStart();
if(Tabs.getFriendsListAdapter()==null) {
final ProgressDialog dialog = ProgressDialog.show(getActivity(), getString(R.string.loadingtitle), getString(R.string.loading), true, false);
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
while(Tabs.getFriendsListAdapter()==null) {}
dialog.dismiss();
Tabs.getFriendsListAdapter().notifyDataSetChanged();
}
});
thread.start();
}
}
You are creating a new adapter, but I don't see any code to set the adapter to the list. Since the list knows nothing about your brand new adapter, calling notifyDataSetChanged() doesn't help. BTW, if you are already using fragments, you might consider using a Loader.
I'm trying to use "http://github.com/commonsguy/cwac-endless" to implement pagination for my list views.
I'm getting the first page results correctly, when I scrolled down to the bottom of the 1st page, i'm seeing the spinning wheel but im not getting any results.
I noticed from the LogCat that, getPendingView(), cacheInBackground(), appendCachedData() and MyCustomAdapter's getView() are getting called infinately.
Can anybody plz help.
Thanks,
nehatha.
Here is my code snippet:
Activity{
onCreate() {
myList = new ArrayList<Item>();
setListAdapter(new DemoAdapter(myList));
nextLink = "service_url"; //for first page results (say 1-25)
}
final Handler handler = new Handler() {
public void handleMessage(final Message msg) {
//
updateList(jsonResponse);
}
};
updateList(String jsonString) {
//parse json
//add to `myList`
//update `nextLink`, if there is next page available
}
class DemoAdapter extends EndlessAdapter {
private RotateAnimation rotate=null;
DemoAdapter(List<Item> list) {
super(new MyCustomAdapter(LatestUpdatesList.this, R.layout.latest_update_item, list));
//rotate code
}
#Override
protected boolean cacheInBackground() {
if(nextLink != null && nextLink.length() > 0){
HttpHandler httpHandler = new HttpHandler(nextLink, "GET", handler);
Thread latestUpdatesThread = new Thread(httpHandler);
latestUpdatesThread.start();
return true;
}
return false;
}
#Override
protected void appendCachedData() {
MyCustomAdapter adapter = (MyCustomAdapter)getWrappedAdapter();
adapter.setList(myList);
}
} //DemoAdapter
} //Activitiy
I have fixed the issue by not calling my web service in a new thread (inside cacheInBackground() method). Instead i'm directly calling my HttpHandler's get() method directly. But I'm not sure this is the best fix.
Thanks,
nehatha