I have a problem about refreshing the screen after i add a string to my listview. I add the string and then i use adapter.notifyDataSetChanged() but the screen doesn't refresh until the function is over. I need it to refresh immediately after i add the string to the listview
public class MainActivity extends AppCompatActivity {
public ArrayList listaConectados;
private TextView estado;
private ListView listaView;
public static int x;
private ArrayAdapter<String> adapter;
private ArrayList<String> arrayList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
estado = (TextView)findViewById(R.id.estado_TextView);
listaConectados = new ArrayList<Dispositivos>();
arrayList = new ArrayList<String>();
listaView = (ListView) findViewById(R.id.listaConectados_listView);
adapter = new ArrayAdapter<String>(getApplicationContext(),
android.R.layout.simple_list_item_1,arrayList);
listaView.setAdapter(adapter);
}
public void searchConnectedDispositives(View view) {
ArrayList listaParaActualizar = new ArrayList<String>();
int i;
int x;
String ip = getIpAddress();
String ipVariable = ip.substring(0,10);
for(i=0;i<255;i++){
int result=10;
String ipTemp = ipVariable +String.valueOf(i);
try {
result=pingHost(ipTemp);
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
if(result==0){
Dispositivos nuevo = new Dispositivos(ipTemp);
arrayList.add(ipTemp);
adapter.add(ipTemp);
adapter.notifyDataSetChanged();
}
}
The function searchConnectedDispositives is called when I touch one button. When this function ends, the Activity is refreshed.
Observing your code leads me to find out that the real cause of your problem is pingHost() which has proc.waitFor(); and waitFor() is a blocking call.
That means you are holding the UI thread (because this is the thread where you are performing your operation).
And the reason why your ListView gets refreshed only in the last and I'm sure it gets updated only in the last iteration of your for loop is the same problem as here and I have posted the answer for the same. You can read it .
Related
I wrote this Java code for Android:
public class MainActivity extends AppCompatActivity
{
private static final String WEBSITE_URL = "http://www.anywebsite.com/forum/";
private ListView _lvForums;
private ForumAdapter _forumAdapter;
private List<ForumContent> _forumContents;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
//_lvForums = findViewById(R.id.lvForums);
_lvForums = new ListView(this);
_lvForums.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
_forumContents = new ArrayList<>();
setContentView(_lvForums);
new Thread(new Runnable() {
#Override
public void run() {
try {
Document doc = Jsoup.connect(WEBSITE_URL).get();
//MainActivity.this.getActionBar().setTitle(doc.title());
Elements forumContents = doc.select("div.forum_content.forum_forum");
for (Element forum : forumContents) {
String forumName = forum.select("span.name > a").text();
String link = forum.select("span.name > a").attr("abs:href");
String threadCount = forum.select("td.threadcount").text();
String postCount = forum.select("td.postcount").text();
Element lastPost = forum.select("td.lastpost").first();
Element linkElement = lastPost.getElementsByTag("a").first();
String lastPostText = lastPost.childNode(0).toString();
String lastPostLink = linkElement.attr("abs:href");
_forumContents.add(new ForumContent(
forumName, link, threadCount, postCount, lastPostText, lastPostLink));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
runOnUiThread(new Runnable() {
#Override
public void run() {
_forumAdapter = new ForumAdapter(MainActivity.this, _forumContents);
_lvForums.setAdapter(_forumAdapter);
}
});
}
}
When I run the app on Android, I see an empty white screen but I can't see ListView items. I'm pretty sure that ForumAdapter and ForumContent are working so good. Because if I try like this, I can see ListView items:
_forumContents.add(new ForumContent("Data1", "Data2", "Data3", "Data4", "Data5", "Data6"));
And I'm pretty sure that my JSoup codes, because I can get same datas with same code on Java console app.
What is the problem? How can I see ListView items who fetched data from the website?
See what you're doing is, you're scraping your content in a new thread. But you're already immediately creating your Adapter in your main thread. So, basically your adapter has already been set, but your app is still busy scraping in the background.
You can make your rows "visible" by calling notifyDataSetChanged() on your adapter.
I'm developing a feed app, where people can make posts and these posts will populate a RecyclerView.
I have a FAB button that leads to a post activity, but when I post and then comeback to the MainActivity the list is not updated. But when I use the logout button and log back in, the list gets updated, or when I launch the activity it works.
I think this happens because my Async function gets called to work on onCreate, but I can't work like these, I need the AsyncTask to automatically fetch, otherwise people won't get the list updated in real time.
Could you please show me a light in the dark? Here are the codes for MainActivity, PostActivity and logout function from another class.
Main Activity:
public class MainActivity extends AppCompatActivity {
private AppCompatActivity activity = MainActivity.this;
private RecyclerView recyclerViewNews;
private List<Noticia> listNoticias;
private NewsRecyclerAdapter newsRecyclerAdapter;
private DBNoticias databaseHelper;
private Button btnLogout;
private LinearLayoutManager mLayoutManager;
UserSession userSession;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
userSession = new UserSession(getApplicationContext());
recyclerViewNews = findViewById(R.id.recyclerViewNews);
btnLogout = findViewById(R.id.btlogout);
TextView usuario = findViewById(R.id.textView5);
/**
* Olá mundo by Alciomar
*/
SharedPreferences sharedPreferences = getSharedPreferences("Reg", Context.MODE_PRIVATE);
String uName = sharedPreferences.getString("Name", "");
usuario.setText(uName.toUpperCase());
try {
btnLogout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
userSession.logoutUser();
}
});
} catch (Exception e) {
e.printStackTrace();
}
initStuff();
getDataFromPostgres();
FloatingActionButton fab = findViewById(R.id.fabNews);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, PostNews.class);
startActivity(intent);
}
});
}
/**
* This method is to initialize objects to be used
*/
private void initStuff() {
try {
listNoticias = new ArrayList<>();
newsRecyclerAdapter = new NewsRecyclerAdapter(listNoticias);
mLayoutManager = new LinearLayoutManager(getApplicationContext());
mLayoutManager.setReverseLayout(true);
mLayoutManager.setStackFromEnd(true);
recyclerViewNews.setLayoutManager(mLayoutManager);
recyclerViewNews.setItemAnimator(new DefaultItemAnimator());
recyclerViewNews.setHasFixedSize(true);
recyclerViewNews.setAdapter(newsRecyclerAdapter);
databaseHelper = new DBNoticias(activity);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* This method is to fetch all user records from SQLite
*/
private void getDataFromPostgres() {
// AsyncTask is used that SQLite operation not blocks the UI Thread.
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
listNoticias.clear();
for (DBNoticias dbNoticias : databaseHelper.getNewsList()) {
Noticia noticia = new Noticia();
noticia.setUser_id(dbNoticias.getId());
noticia.setNewsTitle(dbNoticias.getNewsTitle());
noticia.setNewsMessage(dbNoticias.getNewsPost());
listNoticias.add(noticia);
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
newsRecyclerAdapter.notifyDataSetChanged();
}
}.execute();
}
Post News Activity:
public class PostNews extends AppCompatActivity {
private DBNoticias dbNoticias;
private Button btnpostar;
private EditText editTextCDNewsTitle;
private EditText editTextCDNewsPost;
private Noticia noticia;
private SharedPreferences sharedPreferences;
public void alert(String titulo, String txt){
AlertDialog alertDialog = new AlertDialog.Builder(PostNews.this).create();
alertDialog.setTitle(titulo);
alertDialog.setMessage(txt);
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alertDialog.show();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_post_news);
btnpostar = findViewById(R.id.btn_postar);
dbNoticias = new DBNoticias();
editTextCDNewsTitle = findViewById(R.id.EditTextNewsTitle);
editTextCDNewsPost = findViewById(R.id.EditTextNewsPost);
}
public void salvarNoticia(View view) {
try {
{
String newsTitle = editTextCDNewsTitle.getText().toString();
String newsPost = editTextCDNewsPost.getText().toString();
if (!(editTextCDNewsTitle.getText().toString().equals("") || editTextCDNewsTitle.getText() == null ||
editTextCDNewsPost.getText().toString().equals("") || editTextCDNewsPost.getText() == null
)) {
sharedPreferences = getSharedPreferences("Reg", Context.MODE_PRIVATE);
String uName = sharedPreferences.getString("Name", "");
String uEmail = sharedPreferences.getString("Email", "");
int uIdUser = sharedPreferences.getInt("IdUser", 0);
dbNoticias.setNewsTitle(newsTitle);
dbNoticias.setNewsPost(newsPost);
dbNoticias.setIdUser(uIdUser);
dbNoticias.salvar();
noticia = new Noticia();
Toast.makeText(getApplicationContext(), "Notícia postada com sucesso",
Toast.LENGTH_LONG).show();
editTextCDNewsTitle.setText("");
editTextCDNewsPost.setText("");
}
}
}
catch (Exception e){
alert("Erro", e.getMessage());
}
}
Thank you in advance if you read and try to help!
There are multiple ways to do this:
Method 1 – Use onResume()
If you call your getDataFromPostgres() method in onResume instead of onCreate, it'll fetch data and refresh list every time the activity wakes from a pause (for example coming back from another activity)
// existing code
#Override
public void onResume(){
super.onResume();
getDataFromPostgres()
}
(This would be the simplest solution)
Method 2 – Poll the DB continuously
If there are other services that might be updating the database and you need to always show the latest state in the activity, another way (although really inefficient) would be to keep refreshing the list after a defined time period (let's say 10 seconds as an example).
How to run an async task for every x mins in android?
Method 3 – Use onActivityResult
If you want to update the list only when a new entry has been created in the second activity, you can use onActivityResult to notify the first activity on action and then refresh your list there.
How to manage `startActivityForResult` on Android?
Please use this, it's working for me
newsRecyclerAdapter.notifyItemInserted(position);
newsRecyclerAdapter.notifyDataSetChanged();
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 am programming a messaging app and I want to add users in a group. However, when a list of users pops up and I select one from the list, it doesn't pass the string (the username) to the other activity. All I get is an empty list.
Here is my code:
First Activity = Sending data (usernames from list) through putExtra()
public class ListUsersActivity extends Activity {
private String currentUserId;
private ArrayAdapter<String> namesArrayAdapter;
private ArrayList<String> names;
private ListView usersListView;
private Button logoutButton;
private ProgressDialog progressDialog;
private BroadcastReceiver receiver = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_users);
Parse.initialize(this, "embpZ0spRUv5XwDgI23innll1sgHg0KZNiKzg6kl", "LPsU4UffPeqFXkQB1GfLCIJ4kvg20llPgbOnLise");
currentUserId = ParseUser.getCurrentUser().getObjectId();
names = new ArrayList<>();
ParseQuery<ParseUser> query = ParseUser.getQuery();
query.whereNotEqualTo("objectId", currentUserId);
query.findInBackground(new FindCallback<ParseUser>() {
public void done(List<ParseUser> userList, com.parse.ParseException e) {
if (e == null) {
for (int i=0; i<userList.size(); i++) {
names.add(userList.get(i).getUsername().toString());
}
usersListView = (ListView)findViewById(R.id.usersListView);
namesArrayAdapter =
new ArrayAdapter<String>(getApplicationContext(),
R.layout.user_list_item, names);
usersListView.setAdapter(namesArrayAdapter);
usersListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> a, View v, int i, long l) {
Intent goBackToAddPoolIntent = new Intent(ListUsersActivity.this, addNewPoolActivity.class);
addNewPoolActivity checker = new addNewPoolActivity();
checker.checkIfUserIsSelected(usersListView.getItemAtPosition(i).toString());
goBackToAddPoolIntent.putExtra("username", usersListView.getItemAtPosition(i).toString());
startActivity(goBackToAddPoolIntent);
}
});
} else {
Toast.makeText(getApplicationContext(),
"Error loading user list",
Toast.LENGTH_LONG).show();
}
}
});
}
Second Activity = Receiving data from putExtra()
public class addNewPoolActivity extends Activity {
private static ArrayList<String> addedUsers;
private ArrayAdapter <String> addedUserAdapter;
private boolean userIsSelected;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_new_pool);
Button addMembers = (Button) findViewById(R.id.bAddMembers);
addedUsers = new ArrayList<>();
//addedUsers.add("Group Members");
addMembers.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent showUsersToSelect = new Intent(addNewPoolActivity.this, ListUsersActivity.class);
startActivity(showUsersToSelect);
}
});
ListView addedUsersList = (ListView) findViewById(R.id.addedUsersListView);
addedUserAdapter = new ArrayAdapter<>(this, R.layout.user_list_item, addedUsers);
addedUsersList.setAdapter(addedUserAdapter);
if(userIsSelected){
Bundle extras = getIntent().getExtras();
addedUsers.add(extras.getString("username"));
}
}
public void checkIfUserIsSelected(String user){
if (user!=null){
userIsSelected = true;
}else{
userIsSelected = false;
}
}
Since the default value for a boolean is false, the code is never called because
if(userIsSelected){
will always evaluate to false since you have declared the varaible as
private boolean userIsSelected;
and the first snippet here is in onCreate() so it will only run the first time the Activity is created.
Maybe you are wanting to call checkIfUserIsSelected(someUser) before that code but without more context of what you hope to accomplish, it's hard to say.
Possibly, you want to use startActivityForResult() in some way?
In addition to #codeMagic 's answer (Since your boolean value is false, it won't call the statement that you are adding the new data). It's also because of you parse the Data "username" after you setAdapter of your ListView. So basically you are setting the data, and then trying to add the new data you parsed to the list. Either you need to do it before setting your data set to your adapter, or call addedUsersAdapter.notifyDataSetChanged() to refresh your listView's data set.
addedUserAdapter = new ArrayAdapter<>(this, R.layout.user_list_item, addedUsers);
addedUsersList.setAdapter(addedUserAdapter);
Bundle extras = getIntent().getExtras();
// Check if the username has been sent to this Activity.
if(extras != null && extras.containsKey("username")){
addedUsers.add(extras.getString("username"));
// Refresh Your Data Set
addedUserAdapter.notifyDataSetChanged();
}
Here is the code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
overridePendingTransition(R.anim.fadein, R.anim.fadeout);
setContentView(R.layout.startpage);
rowItems = new ArrayList<RowItem>();
//... Filling this array.
}
Later, from another activity StartPage.rowItems.size() throw NullPointerException
It can be 0 (failed to retrieve data or I did .clear()), but how, the hell, it became null? I definitely never set it to null.
One more point - this array variable is public static and I use it from another activity. Can it be possible android unloads parent activity (what contains all global variables for the whole app)?
P.S. I cannot check it more thoroughly, because this error is not appears in my emulator/devices, but I got reported it on Google Play. So I can't check what was before and when the array became null...
Thank you
More exact code:
public class StartPage extends Activity implements View.OnTouchListener {
public static List<RowItem> rowItems;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
overridePendingTransition(R.anim.fadein, R.anim.fadeout);
setContentView(R.layout.startpage);
rowItems = new ArrayList<RowItem>();
pDialog = new ProgressDialog(this);
pDialog.setMessage("Loading data...");
pDialog.setCancelable(false);
pDialog.show();
gc=new GetData();gc.execute();
}
public class GetData extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
rowItems.clear();
inProgress=true;
}
#Override
protected Void doInBackground(Void... arg0) {
ServiceHandler sh = new ServiceHandler();
String jsonStr = sh.makeServiceCall(url, ServiceHandler.GET);
if (jsonStr != null) {
try {
JSONObject jsonObj = new JSONObject(jsonStr);
items = jsonObj.getJSONArray(TAG_COINS);
for (int i = 0; i < itemss.length(); i++) {
JSONObject c = items.getJSONObject(i);
String id = c.getString(TAG_ID).toUpperCase();
String price = c.getString(TAG_PRICE);
String name = c.getString(TAG_NAME);
RowItem item = new RowItem(id, name, price);
rowItems.add(item);
}
} catch (JSONException e) {
e.printStackTrace();
}
} else {
Log.e("ServiceHandler", "Couldn't get any data from the url");
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
inProgress=false;
pDialog.dismiss();
}
}
Then call another activity:
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_UP:
int x = (int) event.getX();
int y = (int) event.getY();
int w=view.getWidth()-20;
int h=view.getHeight()-20;
if (x<w*0.05 || x>w*0.95 || y<h*0.13 ) return false; // Misclicked
if (x<w*0.5 && y<h*0.38) {
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
}
}
return true;
}
On another activity (MainActivity), try to refresh the listview with the data from main activity:
public class MainActivity extends ListActivity implements View.OnClickListener {
void refresh_list() {
if (StartPage.rowItems.size()>0) { <-- Here is NPE
ListAdapter adapter = new CustomListAdapter(MainActivity.this,R.layout.list_item,StartPage.rowItems);
setListAdapter(adapter);
((BaseAdapter) getListAdapter()).notifyDataSetChanged();
}
}
Google play report:
Caused by: java.lang.NullPointerException
at halfprice.coinmanager.MainActivity.refresh_list(MainActivity.java:116)
at halfprice.coinmanager.MainActivity.onCreate(MainActivity.java:105)
at android.app.Activity.performCreate(Activity.java)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java)
Hope this helps...
you are loading your data in static ArrayList and Acessing it to different activity. its not good practice to do.
Let me first tell your answer as you have created this object in Oncreate(). Its better you make create it Globally than this problem will not occure.
Example :
public class StartPage extends Activity implements View.OnTouchListener {
public static List<RowItem> rowItems = new ArrayList<RowItem>();
OnCreate(){
//and perform the action you want to do.
}
//Hope this will help you definately.
Now Another Method which is the good Practice in Programming language
Passing data object from one Activity to another is simple, If you want to pass Array object than the object should be serialized. Eg;
ArrayList rowItems = new ArrayList();
for Passing array object you have to use intent PutExtra, Eg:
Intent intent = new Intent(SplashScreen.this, MainActivity.class);
intent.putExtra("key",array); startActivity(intent);
//intent.putExtra("key",array); will show error if your Model class is not implements Serializable eg: public class Model implements Serializable{
String id;
String price;
String name;
//generate your getter setter and set data in to this.
}
//For getting data in to another class just use
ArrayList<Model> data = (ArrayList<Model>)getIntent().getSerializable("key");
Now you can play arround with this data object. You should always try to play around with private or protected object.
Hope this will help you.
If i'm not mistaken:
When your activity is launched, the onCreate() method is called.
But when you come back to the same activity from another activity, then the onCreate method is skipped and onResume() method is called..so my suggestion is to initialize in the onResume() method
#Override
protected void onResume(Bundle savedInstanceState) {
overridePendingTransition(R.anim.fadein, R.anim.fadeout);
setContentView(R.layout.startpage);
rowItems = new ArrayList<RowItem>();
//... Filling this array.
}
This answer might not solve your current problem ( not enough code to give a suggestion) but will help you head in the right direction.
Do provide a central data store for your objects, you should consider using singleton design pattern. Also, since the data will be accessed from multiple threads, you should make the arraylist (in your case) thread safe.
Note: if you are using synchronized list, you should lock the object to prevent access when it is iterated.