Currently, I'm working on an app that shows contents of an JSON-based API in a listview. Fetching the data and using the adapter to fill the listview works fine the first time. But when I try to refresh the contents using Swipe to refresh, the first time I try to refresh I get an IllegalStateException Error:
W/System.err: java.lang.IllegalStateException: JsonReader is closed
W/System.err: at android.util.JsonReader.peek(JsonReader.java:361)
W/System.err: at android.util.JsonReader.expect(JsonReader.java:308)
W/System.err: at android.util.JsonReader.beginArray(JsonReader.java:277)
W/System.err: at com.cologne_international.cologneinternationalapp.notamActivity.readNotamArray(notamActivity.java:71)
W/System.err: at com.cologne_international.cologneinternationalapp.notamActivity.readJsonStream(notamActivity.java:63)
W/System.err: at com.cologne_international.cologneinternationalapp.notamActivity.updateNOTAMS(notamActivity.java:122)
W/System.err: at com.cologne_international.cologneinternationalapp.notamActivity$1.onRefresh(notamActivity.java:48)
W/System.err: at android.support.v4.widget.SwipeRefreshLayout$1.onAnimationEnd(SwipeRefreshLayout.java:187)
W/System.err: at android.support.v4.widget.CircleImageView.onAnimationEnd(CircleImageView.java:106)
W/System.err: at android.view.ViewGroup.finishAnimatingView(ViewGroup.java:6237)
W/System.err: at android.view.View.draw(View.java:17129)
W/System.err: at android.view.ViewGroup.drawChild(ViewGroup.java:3727)
W/System.err: at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)
W/System.err: at android.view.View.draw(View.java:17188)
W/System.err: at android.view.View.updateDisplayListIfDirty(View.java:16167)
W/System.err: at android.view.View.draw(View.java:16951)
W/System.err: at android.view.ViewGroup.drawChild(ViewGroup.java:3727)
W/System.err: at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)
W/System.err: at android.view.View.updateDisplayListIfDirty(View.java:16162)
W/System.err: at android.view.View.draw(View.java:16951)
W/System.err: at android.view.ViewGroup.drawChild(ViewGroup.java:3727)
W/System.err: at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)
W/System.err: at android.view.View.updateDisplayListIfDirty(View.java:16162)
W/System.err: at android.view.View.draw(View.java:16951)
W/System.err: at android.view.ViewGroup.drawChild(ViewGroup.java:3727)
W/System.err: at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)
W/System.err: at android.view.View.updateDisplayListIfDirty(View.java:16162)
W/System.err: at android.view.View.draw(View.java:16951)
W/System.err: at android.view.ViewGroup.drawChild(ViewGroup.java:3727)
W/System.err: at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)
W/System.err: at android.view.View.updateDisplayListIfDirty(View.java:16162)
W/System.err: at android.view.View.draw(View.java:16951)
W/System.err: at android.view.ViewGroup.drawChild(ViewGroup.java:3727)
W/System.err: at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)
W/System.err: at android.view.View.updateDisplayListIfDirty(View.java:16162)
W/System.err: at android.view.View.draw(View.java:16951)
W/System.err: at android.view.ViewGroup.drawChild(ViewGroup.java:3727)
W/System.err: at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)
W/System.err: at android.view.View.draw(View.java:17188)
W/System.err: at com.android.internal.policy.DecorView.draw(DecorView.java:753)
W/System.err: at android.view.View.updateDisplayListIfDirty(View.java:16167)
W/System.err: at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:648)
W/System.err: at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:654)
W/System.err: at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:762)
W/System.err: at android.view.ViewRootImpl.draw(ViewRootImpl.java:2800)
W/System.err: at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2608)
W/System.err: at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2215)
W/System.err: at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1254)
W/System.err: at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6337)
W/System.err: at android.view.Choreographer$CallbackRecord.run(Choreographer.java:874)
W/System.err: at android.view.Choreographer.doCallbacks(Choreographer.java:686)
W/System.err: at android.view.Choreographer.doFrame(Choreographer.java:621)
W/System.err: at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:860)
W/System.err: at android.os.Handler.handleCallback(Handler.java:751)
W/System.err: at android.os.Handler.dispatchMessage(Handler.java:95)
W/System.err: at android.os.Looper.loop(Looper.java:154)
W/System.err: at android.app.ActivityThread.main(ActivityThread.java:6119)
W/System.err: at java.lang.reflect.Method.invoke(Native Method)
W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
However, when I try to reload for a second time, everything is working as it should.
notamActivity Class:
public class notamActivity extends AppCompatActivity {
private static ListView lv;
private static AdapterNotam adbNotam;
private static SwipeRefreshLayout swipeContainer;
private static JsonReader reader;
private static Context context;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_notam);
context = getApplicationContext();
lv = (ListView) findViewById(R.id.list);
try {
adbNotam = new AdapterNotam(this, readJsonStream());
} catch (Exception e) {
e.printStackTrace();
}
lv.setAdapter(adbNotam);
swipeContainer = (SwipeRefreshLayout) findViewById(R.id.swiperefresh);
swipeContainer.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
Log.i("Called onRefresh", "onRefresh called from SwipeRefreshLayout");
notamActivity.updateNOTAMS();
}
});
}
public static List<Notam> readJsonStream() throws IOException {
try {
return readNotamArray(reader);
} finally {
reader.close();
}
}
public static List<Notam> readNotamArray(JsonReader reader) throws IOException {
List<Notam> notams = new ArrayList<Notam>();
reader.beginArray();
while (reader.hasNext()) {
notams.add(readNotam(reader));
}
reader.endArray();
return notams;
}
public static Notam readNotam(JsonReader reader) throws IOException {
int id = 0;
String datestart = null;
String dateend = null;
String text = null;
reader.beginObject();
while (reader.hasNext()) {
String jname = reader.nextName();
if (jname.equals("id")) {
id = Integer.parseInt(reader.nextString());
} else if (jname.equals("datestart")) {
datestart = reader.nextString();
} else if (jname.equals("dateend")) {
dateend = reader.nextString();
} else if (jname.equals("textde")) {
text = reader.nextString();
} else {
reader.skipValue();
}
}
reader.endObject();
return new Notam(id, text, datestart, dateend);
}
public static void setReader(JsonReader pReader){
reader = pReader;
}
public static Context getContext(){
return context;
}
public static void updateNOTAMS(){
new downloadNOTAMTask().execute("http://cologne-international.com/notam/json.php");
try {
adbNotam = new AdapterNotam(getContext(), readJsonStream());
} catch (Exception e) {
e.printStackTrace();
}
lv.setAdapter(adbNotam);
swipeContainer.setRefreshing(false);
}
}
downloadNOTAMTask Class:
class downloadNOTAMTask extends AsyncTask<String,Void,JsonReader>{
protected JsonReader doInBackground(String... url){
JsonReader reader = null;
try {
InputStream ls = new URL(url[0]).openStream();
reader = new JsonReader(new InputStreamReader(ls, "UTF-8"));
}catch(Exception e){
e.printStackTrace();
}
return reader;
}
protected void onPostExecute(JsonReader result){
notamActivity.setReader(result);
}
}
Layout xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_event"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.cologne_international.cologneinternationalapp.eventActivity">
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/swiperefresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/bt_back">
<ListView
android:id="@+id/list"
android:layout_width="fill_parent"
android:layout_height="match_parent"
/>
</android.support.v4.widget.SwipeRefreshLayout>
<Button
android:text="@string/button_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:id="@+id/bt_back"
android:layout_alignParentEnd="true"
android:layout_alignParentStart="true"
android:onClick="back"
style="@android:style/Widget.Holo.Button" />
</RelativeLayout>
There is a problem with the activity that you have published in the question:-
It is happening because you are not doing things in synchronous manner. (ie. You are not waiting for AsynTask to get finished)
Below I have given you the reference to write more cleaner and less error prone code:-
notamActivity Class:
DownloadNOTAMTask Class:
Layout xml: