마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

listview getdata오류

0 추천

안녕하세요 안드로이드 공부중인 학생입니다. 

인터넷에서 리스트뷰와 db를 연동하여 데이터를 받아오는 예제로 실습을 진행하고 있는데 

java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference

이와 같은 오류로 어플동작시 강제 종료 되는데 해결법을 찾지 못하겠습니다.. 도와주세요

전체 로그켓 에러는 다음과 같이 나옵니다.

2021-11-29 01:55:49.290 17623-17623/com.example.moim E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.moim, PID: 17623
    java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference
        at org.json.JSONTokener.nextCleanInternal(JSONTokener.java:121)
        at org.json.JSONTokener.nextValue(JSONTokener.java:98)
        at org.json.JSONObject.<init>(JSONObject.java:165)
        at org.json.JSONObject.<init>(JSONObject.java:182)
        at com.example.moim.Fragment.FragBoard.showList(FragBoard.java:84)
        at com.example.moim.Fragment.FragBoard$1GetDataJSON.onPostExecute(FragBoard.java:140)
        at com.example.moim.Fragment.FragBoard$1GetDataJSON.onPostExecute(FragBoard.java:114)
        at android.os.AsyncTask.finish(AsyncTask.java:771)
        at android.os.AsyncTask.access$900(AsyncTask.java:199)
        at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:788)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

 

package com.example.moim.Fragment;

import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;

import com.example.moim.EditBoard;
import com.example.moim.MainLogin;
import com.example.moim.MainMoim;
import com.example.moim.R;
import com.google.android.material.floatingactionbutton.FloatingActionButton;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;

public class FragBoard extends Fragment {
    private View view;
    private String TAG = "프래그먼트";
    String myJSON;

    private static final String TAG_RESULTS = "result";
    private static final String TAG_NAME = "name";
    private static final String TAG_CONTENT = "content";
    JSONArray boards = null;

    ArrayList<HashMap<String, String>> boardList;

    ListView lv;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        View v = inflater.inflate(R.layout.frag_board, container, false);

        FloatingActionButton edit = (FloatingActionButton) v.findViewById(R.id.fbtn_edit);
        edit.setOnClickListener(new View.OnClickListener() {


            @Override
            public void onClick(View v) {
                Intent edit = new Intent(getActivity(), EditBoard.class);
                startActivity(edit);
            }
        });

        //게시판 리스트
        lv = (ListView) v.findViewById(R.id.BoardNotice);
        boardList = new ArrayList<HashMap<String, String>>();
        getData("http://--나의ip주소--/connect.php");


        return v;


    }


    protected void showList() {
        try {
            JSONObject jsonObj = new JSONObject(myJSON);
            boards = jsonObj.getJSONArray(TAG_RESULTS);

            for (int i = 0; i < boards.length(); i++) {
                JSONObject c = boards.getJSONObject(i);
                String name = c.getString(TAG_NAME);
                String content = c.getString(TAG_CONTENT);

                HashMap<String, String> boards = new HashMap<String, String>();

                boards.put(TAG_NAME, name);
                boards.put(TAG_CONTENT, content);

                boardList.add(boards);
            }
            ListAdapter adapter = new SimpleAdapter(
                    getActivity(),
                    boardList,
                    R.layout.board_list_item,
                    new String[]{TAG_NAME, TAG_CONTENT},
                    new int[]{R.id.item_name, R.id.item_content}
            );
            lv.setAdapter(adapter);
        } catch (JSONException e) {
            e.printStackTrace();
        }

    }

    private void getData(String url) {
        class GetDataJSON extends AsyncTask<String, Void, String> {

            protected String doInBackground(String... params) {
                String uri = params[0];

                BufferedReader bufferedReader = null;
                try {
                    URL url = new URL(uri);
                    HttpURLConnection con = (HttpURLConnection) url.openConnection();
                    StringBuilder sb = new StringBuilder();

                    bufferedReader = new BufferedReader(new InputStreamReader(con.getInputStream()));

                    String json;
                    while ((json = bufferedReader.readLine()) != null) {
                        sb.append(json + "\n");
                    }
                    return sb.toString().trim();
                } catch (Exception e) {
                    return null;
                }
            }

            @Override
            protected void onPostExecute(String result) {
                myJSON = result;
                showList();
            }
        }
        GetDataJSON g = new GetDataJSON();
        g.execute(url);


    }


}

 

hi_i (290 포인트) 님이 2021년 11월 29일 질문

1개의 답변

+1 추천
 
채택된 답변

에러메세지 안에 모든 필요한 정보가 다 있기 때문에, 잘 분석을 해보면 원인을 찾을 수 있습니다.

java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference

에러와 관련된 Exception은 NullPointerException이고 이유는 String.length()를 사용할 때 num object reference를 사용했기 때문입니다. 즉 널오브젝트.length() 처럼 널인 오브젝트의 length()메소드를 호출했기 때문에 문제가 생겼던 겁니다.

그리고 관련된 클래스는 JSONTokener이고 소스코드의 121 라인에서 문제가 있었습니다. 

at org.json.JSONTokener.nextCleanInternal(JSONTokener.java:121)

아마, 로그의 다른 부분을 자세히 보시면, 님의 클래스 중에 어떤 클래스의 몇번째 라인이 문제인지 표시가 될겁니다.

에러로그는 스택이므로 아래쪽으로 갈 수록 직접적인 원인된 클래스를 찾을 수 있습니다.

com.example.moim.Fragment.FragBoard$1GetDataJSON.onPostExecute(FragBoard.java:114)

 

protected void showList() {
        try {
            JSONObject jsonObj = new JSONObject(myJSON);
            boards = jsonObj.getJSONArray(TAG_RESULTS);
 
            for (int i = 0; i < boards.length(); i++) {  // --> 요기  boards.length()
              
               ...
            }
            ...
        } catch (JSONException e) {
            e.printStackTrace();
        }
 
    }

로그로 추측해 볼 때 아마도 boards.length()를 호출할 때 boards가 널이었을 것으로 생각이 듭니다. 그 말은 바로 이전 라인인

boards = jsonObj.getJSONArray(TAG_RESULTS);
 

에서 JSON파싱이 제대로 안되었다는 것을 의미하므로 이 부분을 고치시면 해결되지 않을까 생각합니다.

spark (224,800 포인트) 님이 2021년 11월 29일 답변
hi_i님이 2021년 11월 29일 채택됨
가져올 내용이  ip주소/connect.php를통해 접속하면

{"result":[{"name":"kuk","content":"hi this table is test table wow..b"}]}
위와같은 값을 가져오는데

혹시 47번 코드의
JSONArray boards = null;
로 초기화한것이 boards에 null값이 들어가는 원인이 될까요?
아, 제가 좀 잘못 봤네요. 114라인이 boards가 아닌 것 같네요. 121라인이 어떤 줄인지 말씀해 보시겠어요?
알람이 확인되지 않아 늦은 답변 죄송합니다 ㅠㅠ
말씀주신 121번 라인은doInBackground try구문에 첫번째줄
URL url = new URL(uri); 입니다!!!

로그캣의 파란색줄 에러 84,140,114는 각각
84- showlist()의

JSONObject jsonObj = new JSONObject(myJSON); 부분

140- onPostExecute()의

showlist(); 부분

114 - getData()

class GetDataJSON extends AsyncTask<String, Void, String>  부분입니다!!
아아 혹시 말씀하시는 121번 라인이 JSONTokener.java:121 이부분이면
제가 생성한 클레스 파일이 아니라 자동생성된 라인인거같은데 첨부 드릴까요??
혹시 onPostExecute에서 myJSON에 어떤 값이 들어가는지 확인해 보실 수 있나요?
제가 작성해본 코드상으로는 JSONObject 내부의JSONArray에 result라는 이름이 들어가는것 같습니다만 실제로 어떤값이 들어가있는지 확인은 어떻게 하는지 잘 모르겠네요....ㅠㅠ
아래 링크에 가셔서 디버깅하는 방법을 확인해 보세요.
https://www.youtube.com/watch?v=2CHV0Gw41Kc
5분정도 부터 보시면 브레이크 포인트 사용하는 방법이 나옵니다.
많이 배워가는 중입니다 감사합니다!!
onPostExecute 에서 null값이 들어갑니다
result 가 null로 들어오는것 같습니다
그렇다면 이유는 getData에서 서버에서 데이터를 가져오는 부분에 있겠네요?

private void getData(String url) {
        class GetDataJSON extends AsyncTask<String, Void, String> {
 
            protected String doInBackground(String... params) {
                String uri = params[0];
 
                BufferedReader bufferedReader = null;
                try {
                    // 여기에서 에러 발생함.
                } catch (Exception e) {
                    return null; //---> 여기가 실행되는 걸로 보임. 따라서
                }
            }

            @Override
            protected void onPostExecute(String result) {
                ...
            }
        }
        ...
    }

try 블록 안에서 브레이크 포인트를 찍어서 정확하게 어디가 에러가 나는지 확인해 보세요. 그리고
서버에서 받은 JSON응답을 읽을 때, 아래처럼
sb.append(json);
마지막에 라인피드 문자는 빼세요.

참고로 대부분의 개발자들은 JSON을 서버에서 가져오기 위해  Retrofit란걸 사용합니다. 그리고 AsyncTask는 Android 11부터 deprecated 되어서 더이상 지원되지 않습니다.
String uri = params[0]; 요 구문이 문제였던것 같습니다.
uri에 바로 ip주소/connect.php 를 주어
바로 접근하게 하니 데이터가 불러와 집니다
감사합니다  답변주신 내용을 바탕으로
Retrofit에 대해서도 공부를 해봐야겠습니다. 늦은시간임에도 불구하고 답변 정말 감사드립니다. 많은것 배워갑니다!!
...