簡體   English   中英

單擊按鈕更新recyclerview

[英]Update recyclerview on button click

我的Android應用程序中還有另一個問題或錯誤。 抱歉,我是Android開發的新手,但這是我的熱情,我會堅持不懈。

無論如何,我的代碼在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中即會更新內容,即phpmyadmin mysql服務器-但是應用程序崩潰時不會重新加載更新后的列表。 這與我的UserListRecycler類中的populateList()方法有關,它將錯誤指向recyclerView.setAdapter(adapter); PopulateUsers類中-確切地說在onPostExecute() ,作為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)

這確實意味着很多,實際上,如果有人可以幫助我解決這個問題,我自己就要睡一覺。 這是一個可怕的錯誤!

該錯誤基本上是由於您正在訪問recyclerview而其適配器尚未實例化的事實造成的。 那是因為您在后台設置recyclerview時在主線程中顯示它。 在您的情況下,兩個線程不同步,因此當您單擊按鈕時,recyclerview尚未正確設置,因此為您提供了空指針異常。

我建議您尋找一種解決方法來顯示數據,然后在顯示之前設置您的recyclerview。

使用asynctask進行網絡調用確實不是一個好主意,通常必須使用諸如retrofit,gson,rxandroid等之類的庫,但是由於您剛剛開始,因此必須使用asynctask。

我建議您像在onCreate一樣在主線程中執行recyclerView.setAdapter(adapter) ,因為您沒有顯示recyclerview所需的數據,因此必須先使用虛擬數據進行設置,或更優選地,如果尚未顯示,請先顯示一個進度條,以告訴用戶尚未完成加載。

如果您按照我的建議去做,則不必在asynctask中調用recyclerView.setAdapter(adapter) ,只需通知它您已進行更改,當然就是您的adapter.notifyDataSetChanged()

recyclerView.setAdapter(adapter);

您打了兩次電話。 為什么不將其保留在onCreateView中並從postExecute刪除它呢? 只需在adapter.notifyDataSetChanged()保留adapter.notifyDataSetChanged()並將其從onCreateView中刪除即可。 這有什么不同嗎?

我正在將Volley庫用於這些任務,並且使用起來相當容易。 看起來也比ASyncTask整潔。 也許您可以嘗試一下。

看一下該頁面: http : //developer.android.com/training/volley/index.html

如果克隆Volley library (下載了一個文件夾),請通過New>Import MODULE>path to library其導入Android Studio。 然后,您需要在依賴Build gradle下將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類的swipeRefreshLayout 注意,這仍然是asynchronously完成的。

重要的是去檢查JSON responses ,看看響應是否以對象或數組開頭。 然后相應地調整Volley代碼。 基本上,這Array代碼中的大多數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);

下載方法只是通知適配器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM