2016-03-02 110 views
1

我的Android应用程序中有另一个问题或错误。对不起,我是Android开发新手,但这是我的激情,我会坚持下去。按钮单击更新recyclerview

无论如何,我的代码在我的CustomAdapter类的方法调用中崩溃。

这是我CustomAdapter类在那里崩溃:

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.CustomViewHolder> { 
private ArrayList<UserInfo> arrayList = new ArrayList<UserInfo>(); 
float ratings; 

public CustomAdapter(ArrayList<UserInfo> arrayList){ 
    this.arrayList = arrayList; 
} 

@Override 
public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.userslayout, parent, false); 
    CustomViewHolder customViewHolder = new CustomViewHolder(view); 
    return customViewHolder; 
} 

@Override 
public void onBindViewHolder(final RecyclerViewHolder holder, int position) { 
    final UserInfo userInfo = arrayList.get(position); 
    holder.username.setText(userInfo.getMusicName()); 
    holder.forename.setText(userInfo.getMusicCategory()); 
    holder.surname.setText(userInfo.getFileType()); 
    // THE APP CRASHES WHEN I CLICK THIS BUTTON. THINGS UPDATE IN THE 
    // DATABASE - BUT THE RECYCLERVIEW CRASHES AND THE APP CRASHES 
    holder.buttonRefresh.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      String pressed = Integer.toString(userInfo.getPressedName()); 
      UserListRecycler userListRecycler = new UserListRecycler(); 
      UserListRecycler.UserPressedAsync userPressedAsync = userListRecycler.new UserPressedAsync(); 
      userPressedAsync.execute(username, pressed); 
     } 
    }); 
} 

}

这是我UserListRecycler类 - 主类和内部类UserPressedAsync

public class UserListRecycler extends Fragment { 
    RecyclerView recyclerView; 
    static UserAdapter adapter; 
    RecyclerView.LayoutManager layoutManager; 
    ArrayList<UserInfo> list; 


    @Override 
    public void onCreate(Bundle savedInstanceState){ 
     super.onCreate(savedInstanceState); 
    } 

    @Nullable 
    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     View rootView = inflater.inflate(R.layout.userlistGUI, container, false); 
     recyclerView = (RecyclerView) rootView.findViewById(R.id.reUsers); 
     recyclerView.setHasFixedSize(true); 
     list = new ArrayList<UserInfo>(); 
     // Instantiate new adapter here 
     adapter = new MusicRecyclerAdapter(list); 
     LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity()); 
     linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); 
     recyclerView.setLayoutManager(linearLayoutManager); 
     // Sets the adapter here 
     recyclerView.setAdapter(adapter); 
     adapter.notifyDataSetChanged(); 
     return rootView; 
    } 

    @Override 
    public void onStart() { 
     super.onStart(); 
     populateRecyclerList(); 
    } 


    public void populateList(){ 
     PopulateUsers userList = new PopulateUsers(list, adapter, recyclerView); 
     userList.execute(); 
    } 

    public class UserPressedAsync extends AsyncTask<String, String, String> { 
    @Override 
    protected String doInBackground(String... params) { 
     // REST STUFF HAPPENS HERE 
    } 

    @Override 
    protected void onPostExecute(String postData) { 
     // CRASHES HERE!!! 
     populateRecyclerList(); 
    } 
} 
} 

这是我的PopulateUsers班 - 我的服务器的详细信息通过REST

public class PopulateUsers extends AsyncTask<String, String, String> { 
    static ArrayList<UserInfo> list; 
    UserAdapter adapter; 
    RecyclerView recyclerView; 

public PopulateUsers(ArrayList<UserInfo> list, UserAdapter adapter, RecyclerView recyclerView) { 
    this.list = new ArrayList<UserInfo>(); 
    this.adapter = new UserAdapter(); 
    this.list = list; 
    this.adapter = adapter; 
    this.recyclerView = recyclerView; 
} 

@Override 
protected void onPreExecute() { 
    super.onPreExecute(); 
} 

@Override 
protected String doInBackground(String... params) { 
    // `REST` Activity happens here 
} 

@Override 
protected void onPostExecute(String s) { 
    try { 
     list.clear(); 
     JSONArray jsonArray = new JSONArray(s); 
     for (int i = 0; i < jsonArray.length(); i++) { 
      String forename = jsonArray.getJSONObject(i).getString("forename"); 
      String surname = jsonArray.getJSONObject(i).getString("surname"); 
      String nationality = jsonArray.getJSONObject(i).getString("nationality"); 
      UserInfo userInfo = new UserInfo(forename, surname, nationality); 
      list.add(userInfo); 
     } 
     recyclerView.setAdapter(adapter); 
     adapter.notifyDataSetChanged(); 
    } catch (JSONException e) { 
     e.printStackTrace(); 
    } 
} 
} 

基本上,单击该按钮时,事情正在朝着backend更新,即phpmyadminmysql服务器 - 但它崩溃的应用程序不与更新的列表刷新。这与UserListRecycler类中的populateList()方法有关,它指向PopulateUsers类中的recyclerView.setAdapter(adapter);错误 - 正好在中,错误类型为NullPointerException,但它在UserListRecycler类首次实例化并加载时工作正常。那么为什么它会崩溃,当我打电话给populateList()方法?

这是我的堆栈跟踪:

java.lang.NullPointerException 
      at lukasz.usersapp.PopulateUsers.onPostExecute(PopulateUsers.java:67) 
      at lukasz.usersapp.PopulateUsers.onPostExecute(PopulateUsers.java:27) 
      at android.os.AsyncTask.finish(AsyncTask.java:631) 
      at android.os.AsyncTask.access$600(AsyncTask.java:177) 
      at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:644) 
      at android.os.Handler.dispatchMessage(Handler.java:99) 
      at android.os.Looper.loop(Looper.java:137) 
      at android.app.ActivityThread.main(ActivityThread.java:5103) 
      at java.lang.reflect.Method.invokeNative(Native Method) 
      at java.lang.reflect.Method.invoke(Method.java:525) 
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737) 
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) 
      at dalvik.system.NativeStart.main(Native Method) 

这将真正意味着很多,其实有些睡眠自己,如果有人可以帮助我解决这个问题。这是一个可怕的错误!

回答

1

该错误基本上来自您正在访问您的recyclerview而其适配器尚未实例化的事实。这是因为您在主线程中显示recyclerview,同时在后台进行设置。在你的情况下,两个线程不同步,所以当你点击按钮时,recyclerview还没有正确设置,因此给你一个空指针异常。

我建议你找到解决办法,让数据显示出来,然后在显示之前设置你的回收站。

使用asynctask进行网络调用真的不是一个好主意,你通常必须使用像retrofit,gson,rxandroid等库,但是因为你刚刚开始,你必须用asynctask做。

我建议你做你的recyclerView.setAdapter(adapter)在你的主线程就像在你onCreate,因为你没有显示你的recyclerview所需的数据,你必须要么使用虚拟数据首次设置或者,更优选,唐不显示它,先显示一个进度条,告诉用户它还没有完成加载。

如果您按照我的建议进行操作,则无需在您的asynctask中致电recyclerView.setAdapter(adapter),您只需通知它您已进行更改,这当然是您的adapter.notifyDataSetChanged()

+0

那么我该如何解决这个可怕的错误?我实际上无法入睡,并且一直将我的头撞在墙上 –

+0

有没有办法可以修复我的代码?当然,它正在移动一条线 –

+0

你的json从哪里来?从api? – hehe

0

recyclerView.setAdapter(adapter);

您拨打的两倍。为什么不把它放在onCreateView中,并将其从postExecute中删除?只需将adapter.notifyDataSetChanged()保留在postExecute中,并将其从onCreateView中删除即可。这有什么不同吗?

我正在使用库Volley这些任务,它的使用相当简单。看起来也比ASyncTask好看。也许你可以试试看。

看一看那个页面:http://developer.android.com/training/volley/index.html

如果克隆Volley library(文件夹会下载),通过New>Import MODULE>path to library其导入到Android的工作室。然后,你需要把compile project(':volley')到您应用的Build gradle下的依赖 - 所以它看起来是这样的:

dependencies { 
    compile fileTree(dir: 'libs', include: ['*.jar']) 
    compile 'com.android.support:support-v4:23.1.1' 
    compile 'com.android.support:appcompat-v7:23.1.1' 
    compile 'com.android.support:design:23.1.1' 
    compile project(':volley') 
} 

这是我的方法,从我的PHP服务下载JSON的样子:

public void downloadEvents(String urlService) { 


    RequestQueue requestQueue = Volley.newRequestQueue(getActivity()); //getActivity because I'm calling it from a fragment, if called in Activity, use 'this' 
    JsonArrayRequest jsonArrayRequest = new JsonArrayRequest 
      (Request.Method.GET, urlService, null, new Response.Listener<JSONArray>() { 

       @Override 
       public void onResponse(JSONArray response) { 

        try { 


         for (int i = 0; i < response.length(); i++) { 
          JSONObject eventJson = response.getJSONObject(i); 

          String title = eventJson.getString("EventTitle"); 
          String body = eventJson.getString("EventBody"); 
          double price = Double.parseDouble(eventJson.getString("EventPrice")); 
          String date = eventJson.getString("EventDate"); 
          String time = eventJson.getString("EventTime"); 
          String place = eventJson.getString("EventPlace"); 
          String organ = eventJson.getString("Organization"); 

          Event event = new Event(title, body, price, date, time, durationStr, place, organ); 
          theEvents.add(event); 
          rAdapter.notifyItemInserted(i); 
         } 


         if (swipeRefreshLayout.isRefreshing()) { 
          swipeRefreshLayout.setRefreshing(false); 
         } 
        } catch (JSONException e) { 
         e.printStackTrace(); 
        } 


       } 


      }, new Response.ErrorListener() { 

       @Override 
       public void onErrorResponse(VolleyError error) { 
        Log.e("VOLLEY ERROR", "" + error); 

       } 
      } 
      ); 

    requestQueue.add(jsonArrayRequest); //important to add that otherwise the download wont be initiated. 
} 

你可以看到我如何处理我的JSON,以及在哪里可以使用像swipeRefreshLayout这样的东西。 请注意,这仍然是asynchronously

重要的是去检查您的JSON responses并查看响应是以对象还是数组开头。然后相应地调整Volley代码。它基本上将代码中的大多数Array关键字更改为Object(如果您正在接收包含您的数据的JSON对象)。例如:

JsonArrayRequest jsonArrayRequest = new JsonArrayRequest 
      (Request.Method.GET, urlService, null, new Response.Listener<JSONArray>() { 

成为

JsonObjectRequest jsonObjectRequest = new JsonObjectRequest 
      (Request.Method.GET, urlService, null, new Response.Listener<JSONObject>() { 

....

在我的onCreate,使用downloadEvents("http//example.com/service.php"); 我已经做了所有的RecyclerView和适配器代码之前:

 recyclerView = (RecyclerView) fragmentView.findViewById(R.id.rv); 
    LinearLayoutManager llm = new LinearLayoutManager(getActivity()); 
    recyclerView.setLayoutManager(llm); 
    theEvents = new ArrayList<>(); 
    rAdapter = new RecyclerAdapter(theEvents, recyclerView); 
    recyclerView.setAdapter(rAdapter); 

下载方法只是通知适配器。

+0

如何使用volley,is there任何方式我可以将我的代码转换为凌空? –

+0

我给你几乎完整的Volley教程。我希望它很简单,它可以帮助你。我这样做的方式(现在)这个方法是我设置数据的地方,所以我的列表和适配器在同一个类(片段)中。这就是为什么我只是添加到列表并通知我的适配器。 – iBobb

+0

谢谢,但是什么是事件事件=新事件(标题,正文,价格,日期,时间,durationStr,地点,器官);'?另外,如果我要将抽签代码放在一个单独的类中,它会起作用吗? –