Please don't mark it as duplicate, as the solutions provided yesterday did not work.
I have populated a recyclerview, and it is working fine, albeit it loads a bit slowly.
However, say when I add a new name and update the recyclerview it crashes with the NullPointerException.
Below are the classes and code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mainOnes);
recyclerView = (RecyclerView) findViewById(R.id.recycleOnes);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setHasFixedSize(true);
adapter = new MusicRecyclerAdapter(list);
recyclerView.setAdapter(adapter);
populateList();
}
public void populateList(){
DisplayUsersList displayUsersList = new DisplayUsersList();
displayUsersList.execute();
}
public class DisplayUsersList extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... params) {
...
}
#Override
protected void onPostExecute(String postData) {
try {
list.clear();
JSONArray jsonArray = new JSONArray(postData);
for(int i=0; i < jsonArray.length(); i++){
String forename = jsonArray.getJSONObject(i).getString("forename");
String surname = jsonArray.getJSONObject(i).getString("surname");
UserDetails userDetails = new UserDetails(forename, musicName, surname);
list.add(userDetails);
}
adapter.notifyDataSetChanged();
} catch (JSONException e) {
e.printStackTrace();
}
}
}
public class AddUsers extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... params) {
...
}
#Override
protected void onPostExecute(String postData) {
populateList();
}
}
I think it is crashing because of the populateList() method call because I have already initialised everything
My logcat:
java.lang.NullPointerException
at georgezs.userdas.UserDBGUI$DisplayUsersList.onPostExecute(UserDBGUI.java:218)
at android.os.AsyncTask.finish(AsyncTask.java:741)
at android.os.AsyncTask.access$600(AsyncTask.java:197)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:654)
at android.os.Handler.dispatchMessage(Handler.java:100)
Line 218 is adapter.notifyDataSetChanged();
I tried instantiating the recyclerview in onPostExecute but it keeps crashing. My code works in the sense that it actually loads the data and displays it in a recyclerview. It just doesn't redisplay or reload when I call the populateList() method again.
This bug has been bugging me in my sleep literally - so any help and solutions would mean a lot to me
EDIT: I THINK I KNOW EXACTLY WHERE THE ERROR IS - IT IS IN THE POSTEXECUTE METHOD IN ADDUSERS CLASS.
Thanks
Just check if the adapter is not null before calling notifyDataSetChanged():
if (adapter != null) {
adapter.notifyDataSetChanged();
}
This happens because the AsyncTask executes asynchronously and by the time it finishes, the adapter might not be available anymore.
One option you could try is, instead of using
adapter.notifyDataSetChanged();
replace with
recyclerView.getAdapter().notifyDataSetChanged();
This is assuming for whatever reason, you have got your adapter set to null, but not shown in the code clearly above, while your recyclerview is still fully intact.
p/s: I also didn't see you update your latest retrieved data and insert into the adapter. You might want to check that as well.
You're handling variables outside the scope of your main class in a Threaded class which can always be sketchy. Granted AsyncTask is supposed to synchronize operations for you, I'm always cautious
Try passing your list and adapter to your DisplayUsersList class e.g.
DisplayUsersList displayUsersList = new DisplayUsersList(list, adapter);
displayUsersList.execute();
And in your DisplayUsersList make sure the reference of these is explicit e.g.
public class DisplayUsersList extends AsyncTask<String, String, String> {
private final List<UserDetails> list;
private final Adapter adapter;
public DisplayUsersList(List<UserDetails> list, Adapter adapter) {
this.list = list;
this.adapter = adapter;
}
...
Also, try moving the populateList(); to OnStart rather than onCreate
As although the variables are assigned they may still be initialising.
Edit
Could you try moving the call to the top level class e.g.
public void dataSetChangedCallback() {
adapter.notifyDataSetChanged();
}
And in your DisplayUsersList change adapter.notifyDataSetChanged(); to
...
dataSetChangedCallback();
...
Related
I have a Fragment with a RecyclerView. My fragment calls an AsyncTask, and after the request is completed the task returns to my Fragment which implements a processFinish method. in my processFinish I reference a global RV object and try to updated its' content
#Override
public void processFinish(String output, String id) {
switch (id){
case "exchange": {
Gson gson = new Gson();
JsonReader reader = new JsonReader(new
InputStreamReader( new ByteArrayInputStream(output.getBytes()) ));
Type type = new TypeToken<ExchangeResponse>(){}.getType();
ExchangeResponse data = gson.fromJson(reader, type);
homeRV.refreshDrawableState();
// This add doesn't work...
((DisplayableAdapter)homeRV.getAdapter()).addItem(new ExchangeDisplayable(data));
}
}
}
This is my addItem method.
public void addItem(Displayable d){
this.results.add(d);
this.notifyItemInserted(results.size() - 1);
this.notifyDataSetChanged();
}
If I update the adapter from onViewCreated it works well. But not from processFinish. I stopped the debugger right after adding the item, and it seems like the reference is not lost (like others with a similar issue posted). The size of my dataset is changed, but visually nothing happens.
EDIT - I've added my onViewCreated where homeRV is defined, and my onPostExecute.
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
homeRV = getView().findViewById(R.id.rv_home);
homeRV.setHasFixedSize(true);
homeRV.addItemDecoration(new DividerItemDecoration(homeRV.getContext(), DividerItemDecoration.VERTICAL));
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this.getContext());
homeRV.setLayoutManager(layoutManager);
homeRV.setAdapter(new DisplayableAdapter(new ArrayList<Displayable>()));
// This add works...
((DisplayableAdapter)homeRV.getAdapter()).addItem(new HomeDisplayable("Heads up", "this is where Heads Up info will be stored"));
getExchangeRates();
}
In AsyncTask:
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
response.processFinish(result, identifier);
}
Remove homeRV.setHasFixedSize(true); and see if it works. It is not updating width/height of recyclerview because of this line so you can't see new items.
More information on how setHasFixedSize works can be found here.
I have two classes , the first one is for the GUI , where I declared my listview and the adapter , and the setters , to call them from my second class .
public class AndroidGUIModifier implements IMyComponentGUIModifier, IFragmentEvents {
private transient ListView lv;
List<String> mydeviceslist;
ArrayAdapter<String> adapter ;
public void setAdapter(ArrayAdapter<String> adapter) {
this.adapter = adapter;
adapter.notifyDataSetChanged();
}
public void setMydeviceslist(List<String> mydeviceslist) {
this.mydeviceslist = mydeviceslist;
}
#Override
public void onCreateView() {
lv=(ListView) fragment.findViewById("xdevices") ;
mydeviceslist = new ArrayList<String>();
adapter = new ArrayAdapter<String>(fragment.getContext(),android.R.layout.simple_list_item_1,mydeviceslist);
lv.setAdapter(adapter);
In my second class I'll wait an event to receive the list that I want to load it in my listview , then I'll call the list setter to set the new received list and the adapter setter to update it , but it didn't work , nothing was displayed despite I receieved the list of devices in my log .
public class triprincipal extends BCModel {
public List<String> mydevices ;
BCEvent bcEvent;
final ArrayAdapter<String> adapter =guiModifier.getAdapter();
while (isRunning()) {
bcEvent = waitForBCEvent();
if (bcEvent.getID() == checkevent) {
mydevices = bcCommandSenderPlugin.getDevicesNames(); // here I get a list of my devices
Log.i("devices", mydevices.toString());
guiModifier.getFragment().getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
guiModifier.setMydeviceslist(mydevices);
guiModifier.setAdapter(adapter);
}
} );
In setMydeviceslist() do it like:
this.mydeviceslist.addAll(mydeviceslist);
adapter.notifyDataSetChanged();
Hope it will help you out.
adapter.notifyDataSetChanged() will not work in this case, as the value of the reference you have passed to the adapter doesn't actually change.
You will need to create a new Adapter and set it to the ListView to make it work. Change your setAdapter() to this :
public void setAdapter() {
this.adapter = new ArrayAdapter<String>(fragment.getContext(), android.R.layout.simple_list_item_1, mydeviceslist);
lv.setAdapter(adapter);
}
try to update the list in same fragment/activity and after update call notifyDataSetChanged() both in same activity/fragment ....donot set adapter on list repetedly......hope it helps
I'm writing a simple program to request a JOSN request of a list of earthquakes to display for users. I use Asynctask to put the request in the background thread and use an ArrayList Adaptor to display the relevant information. I declare an empty ArrayList and then extract the JOSN request and put them in a temporary list and then assign the temporary list to the empty ArrayList.
I use a debugger tool to see that in the updateEarthquakeList method. I set the break point in the updateEarthquakeList method. this.earthquak and earthquakes both have 10 elements. Pics are as follow:
But when I set the break point after task.execute(USGS_REQUEST_URL) in the onCreate method, I got this:
As the pics shown after execute the AsyncTask the ArrayList is empty. But inside the AsyncTask The array was actually updated. (To do a little experiment I create an int haha as 0 and change it to 1 in the Asynctask, but it changed back to 0 afterwards)
How is this happen and how do I supposted to make it right?
public class EarthquakeActivity extends AppCompatActivity {
public static final String LOG_TAG = EarthquakeActivity.class.getName();
ArrayList<Earthquake> earthquak = new ArrayList<Earthquake>();
int haha = 0;
private static final String USGS_REQUEST_URL = "http://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&eventtype=earthquake&orderby=time&minmag=6&limit=10";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.earthquake_activity);
EarthquakeAsyncTask task = new EarthquakeAsyncTask();
task.execute(USGS_REQUEST_URL);
// Create a fake list of earthquake locations.
// Find a reference to the {#link ListView} in the layout
ListView earthquakeListView = (ListView) findViewById(R.id.list);
// Create a new {#link ArrayAdapter} of earthquakes
EarthquakeAdapter adapter = new EarthquakeAdapter(this, earthquak);
// Set the adapter on the {#link ListView}
// so the list can be populated in the user interface
earthquakeListView.setAdapter(adapter);
//OPEN a web page of a specific when textview is clicked.
earthquakeListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(Intent.ACTION_VIEW, earthquak.get(position).getUrl());
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
}
});
}
private void updateEarthquakeList(ArrayList<Earthquake> earthquake) {
this.earthquak = earthquake;
haha = 1;
}
private class EarthquakeAsyncTask extends AsyncTask<String, Void, ArrayList<Earthquake>> {
#Override
protected ArrayList<Earthquake> doInBackground(String... urls) {
if (urls.length < 1 || urls[0] == null) {
return null;
}
ArrayList<Earthquake> earthquakes = QueryUtils.fetchEarthquakeData(urls[0]);
return earthquakes;
}
#Override
protected void onPostExecute(ArrayList<Earthquake> earthquakes) {
updateEarthquakeList(earthquakes);
}
}
I have a ListView.
I populate this list from 2 editTexts
When I move activity and go back to it the entries are gone again.
I kind of understand why this is but dont know how to correct it.
ListView lv2 = (ListView) findViewById(R.id.listView2);
final SimpleAdapter simpleAdpt = new SimpleAdapter(this, planetsList, android.R.layout.simple_list_item_1, new String[]{"planet"}, new int[]{android.R.id.text1});
planetsList.add(createPlanet("planet", "testme"));
lv2.setAdapter(simpleAdpt);
button21.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
iinitList();
simpleAdpt.notifyDataSetChanged();
editText5.setText("");
editText6.setText("");
}
});
}
private void iinitList() {
String st,str;
Double db;
if (editText5.getText().toString()!= "" && editText6.getText().toString()!="") {
st = editText5.getText().toString();
str = editText6.getText().toString();
db = Double.parseDouble(str);
planetsList.add(createPlanet("planet", ""+st+
": \n" +db+""));
}
}
HashMap<String, String> createPlanet(String key, String name) {
HashMap<String, String> planet = new HashMap<String, String>();
planet.put(key, name);
return planet;
}
As you can see I have added a value to the list manually called test also, when I move activity this stays in the list, I would love if the editText entries were to stay in there also when I move activities.
Activities can be destroyed when you navigate to a new one or rotate. This will clear anything that is only referenced by the activity, like your EditTexts. However, Android provides a nice utility for saving things you want to remain in a method called, which you can override in your activity:
#Override
protected void onSaveInstanceState(Bundle state) {
// Put your values in the state bundle here
}
#Override
protected void onCreate(Bundle savedState) {
// Load your UI elements as usual
if (savedState != null) {
// Load your state from the bundle
}
}
That same bundle will be given back to you in onCreate, where you create your UI to begin with so you can reload the state from it.
This is a really good description of how activities work:
http://developer.android.com/reference/android/app/Activity.html
I don't know why it shows an error. Can somebody help me.
public class MainActivityT extends Activity {
private VerlaufDataSource datasource;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_t);
datasource = new VerlaufDataSource(this);
datasource.open();
List<Entry> values = datasource.getAllEntries();
ArrayAdapter<Entry> adapter = new ArrayAdapter<Entry>(this,
android.R.layout.simple_list_item_1, values);
In the next Line it shows me an error, namely:
Multiple marlcers at this line
- The method setArrayAdapter(ArrayAdapter< Entry>) is undefined for the type MainActivityT
-Uno broakpoint:MainActivityT [lino: 3S] - onCroato(Bundlo)
- The method setlistAdapter(ArrayAdapter< Entrv>) is undefinod for tho type MainActivitvT
setListAdapter(adapter);
}
List<Entry> AufgabenListe = new ArrayList<Entry>();
public void VerlaufKlick(View view)
{
#SuppressWarnings("unchecked")
In the next Line it shows me an error, namely:
Multiple makers at this line
- The method getArrayAdapter() is undefined for the type MainActivityT
- The method qetlistAdapter() is undefined for the tvpe MainActivitvT
ArrayAdapter<Entry> adapter = (ArrayAdapter<Entry>) getListAdapter();
Entry comment = null;
switch (view.getId())
{
case R.id.button1:
String[] comments = new String[] { "Cool", "Very nice", "Hate it" };
int nextInt = new Random().nextInt(3);
comment = datasource.createEntry(comments[nextInt]);
adapter.add(comment);
break;
}
adapter.notifyDataSetChanged();
}
#Override
protected void onResume()
{
datasource.open();
super.onResume();
}
#Override
protected void onPause()
{
datasource.close();
super.onPause();
}
}
Your activity need to extend ListActivity instead of Activity.
There is no method setListAdapter/getListAdapter available in Activity class. They are available if you extend ListActivity.
Read this post on how to use ListActivity.
Use ListActivity instead of Activity as base class