尝试刷新内容时,Android JsonReader将关闭

时间:2017-01-02 19:23:37

标签: android listview refresh pull-to-refresh jsonreader

目前,我正在开发一个应用程序,该应用程序在列表视图中显示基于JSON的API的内容。获取数据并使用适配器填充列表视图第一次正常工作。但是当我尝试使用Swipe刷新内容时,我第一次尝试刷新时遇到IllegalStateException错误:

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)

但是,当我尝试第二次重新加载时,一切都正常工作。
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);
    }
}

布局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>

1 个答案:

答案 0 :(得分:0)

您在问题中发布的活动存在问题: -

  • 您不应该持有对上下文或任何视图的静态引用,它可能最终会导致内存泄漏
  • 当您使用AsynTask时,尝试通过一个接口来恢复通信,就像我在下面的活动中所做的那样。
  • 在后台进行JSON解析,因为它可能会以繁重的处理结束并向您显示ANR。
  

但是,当我尝试第二次重新加载时,一切都正常工作。

这种情况正在发生,因为你没有以同步的方式做事。 (即你没有等待AsynTask完成)

下面我已经提到了编写更清晰,更不容易出错的代码的参考资料: -


notamActivity Class:

public class notamActivity extends AppCompatActivity {
    private ListView lv;
    private AdapterNotam adbNotam;
    private SwipeRefreshLayout swipeContainer;
    private Context context;
    private DownloadNOTAMTask downloadNOTAMTask;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_notam);
        context = getApplicationContext();
        lv = (ListView) findViewById(R.id.list);

        //to initially get the list of Notams
        updateNOTAMS();

        swipeContainer = (SwipeRefreshLayout) findViewById(R.id.swiperefresh);
        swipeContainer.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                Log.i("Called onRefresh", "onRefresh called from SwipeRefreshLayout");
                updateNOTAMS();
            }
        });
    }

    public void cancelTask(DownloadNOTAMTask downloadNOTAMTask) {
        if (downloadNOTAMTask != null && downloadNOTAMTask.getStatus() == AsyncTask.Status.RUNNING)
            downloadNOTAMTask.cancel(true);
    }

    //you should create a reference to cancel the task when the activity is closing
    public void updateNOTAMS() {
        cancelTask(downloadNOTAMTask);
        downloadNOTAMTask = new DownloadNOTAMTask(new GenericCallBack() {
            @Override
            public void success(List<Notam> notamList) {
                //you don't need to setup adapter again and again 
                //just use setDataSetChanged
                adbNotam = new AdapterNotam(notamActivity.this, notamList);
                lv.setAdapter(adbNotam);
                swipeContainer.setRefreshing(false);
            }

            @Override
            public void failure() {
                swipeContainer.setRefreshing(false);
            }
        }).execute("http://cologne-international.com/notam/json.php");

    }

    //interface help you to get callback from the downloadNOTAMTask
    interface GenericCallBack {
        void success(List<Notam> notamList);

        void failure();
    }
}

DownloadNOTAMTask Class:

public class DownloadNOTAMTask extends AsyncTask<String, Void, List<Notam>> {
    private final notamActivity.GenericCallBack callBack;

    public DownloadNOTAMTask(notamActivity.GenericCallBack genericInterface) {
        this.callBack = genericInterface;
    }

    protected List<Notam> doInBackground(String... url) {
        JsonReader reader = null;
        List<Notam> notamList = null;
        try {

            InputStream ls = new URL(url[0]).openStream();
            reader = new JsonReader(new InputStreamReader(ls, "UTF-8"));
            notamList = readNotamArray(reader);
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return notamList;
    }


    @Override
    protected void onPostExecute(List<Notam> notams) {
        if (callBack != null) {
            if (notams != null)
                callBack.success(notams);
            else
                callBack.failure();
        }
    }

    private List<Notam> readNotamArray(JsonReader reader) throws IOException {
        List<Notam> notams = new ArrayList<>();
        reader.beginArray();
        while (reader.hasNext()) {
            notams.add(readNotam(reader));
        }
        reader.endArray();
        return notams;
    }

    private 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();
            switch (jname) {
                case "id":
                    id = Integer.parseInt(reader.nextString());
                    break;
                case "datestart":
                    datestart = reader.nextString();
                    break;
                case "dateend":
                    dateend = reader.nextString();
                    break;
                case "textde":
                    text = reader.nextString();
                    break;
                default:
                    reader.skipValue();
                    break;
            }

        }
        reader.endObject();
        return new Notam(id, text, datestart, dateend);
    }
}

布局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>