onDraw 函数被调用两次?

onDraw function gets called twice?

我很难找到这里的错误。我有一个 AlertDialog.Builder 启动一个自定义对话框,我应该在其中使用 arcDraw 和 Canvas 绘制饼图,问题是如果我使用调试器使用该应用程序,我可以看到我的图表第一次绘制正确第二个电话打进来,把一切都搞砸了,我不知道它是从哪里来的,需要帮助,一些想法吗?

代码:

package com.example.proiect_stroescumarius.ui;

import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RatingBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.fragment.app.Fragment;

import com.example.proiect_stroescumarius.OnDataPassListener;
import com.example.proiect_stroescumarius.R;
import com.example.proiect_stroescumarius.data.RoomDbInstance;
import com.example.proiect_stroescumarius.data.SharedPrefs;
import com.example.proiect_stroescumarius.data.User;

import java.util.ArrayList;
import java.util.List;

public class ListUsersFragment extends Fragment {

    private RatingBar ratingBar;
    private TextView tv;
    private TextView ipPrimit;
    private ListView listView;
    private RoomDbInstance roomDbInstance;
    private OnDataPassListener listener;
    private UserListAdapter userListAdapter;
    private Button pieChartBtn;
    private ListUsersFragment fragment = this;
    private int nrRecords = 0;
    private List<User> users;
    private ArrayList<User> arrayList = new ArrayList<>();
    boolean ponderiCalculate = false;


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

        View root = inflater.inflate(R.layout.fragment_listsearch, container, false);
        roomDbInstance = RoomDbInstance.getInstance(getContext());
        listView = root.findViewById(R.id.list_users);
        userListAdapter = new UserListAdapter(root.getContext(), R.layout.customadapter, arrayList);
        SharedPrefs sharedPrefs = new SharedPrefs(root.getContext());
        ratingBar = root.findViewById(R.id.ratingBar);
        tv = root.findViewById(R.id.ratingTV);
        ConstraintLayout layout = root.findViewById(R.id.layoutList);
        listener.convertFont(sharedPrefs.getFont(), this, layout);

        pieChartBtn = root.findViewById(R.id.pieChartBtn);
        populateAdapter();
        displayRating();
        updateListView();
        pieChartBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
                builder.setMessage("No entries so can't create any charts...");
                builder.setCancelable(true).setPositiveButton("OK", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        AlertDialog builder2 = builder.create();
                        builder2.dismiss();
                    }
                }).create();
                if (nrRecords == 0) builder.show();
                else {
                    AlertDialog.Builder builder1 = new AlertDialog.Builder(getActivity());
//                    LayoutInflater inflater = getLayoutInflater();
                    View v1 = inflater.inflate(R.layout.pie_chart,null);
                    RelativeLayout layout = v1.findViewById(R.id.layoutPieChart);

                    PieInfo pieInfo = calculPonderi();
                    builder1.setView(v1).show();

                    float[] deCalculat = new float[pieInfo.pondereCountries.size()];
                    Toast.makeText(getContext(), String.valueOf(deCalculat[0]), Toast.LENGTH_SHORT).show();
                    int index = 0;
                    for (Float f : pieInfo.pondereCountries) {
                        deCalculat[index++] = f;
                    }
//        Log.d("pie",String.valueOf(deCalculat.length));
//        layout.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));

                    float[] temp = new float[]{1, 2};

                    PieChartView pieChart = new PieChartView(getContext(), calculateValues(deCalculat));

                    RelativeLayout.LayoutParams pieLayout = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
                    pieLayout.setMargins(200, 10, 0, 0);
                    pieChart.setLayoutParams(pieLayout);
                    layout.addView(pieChart);

                    int x = 850;
                    int y = 860;
                    for (String country : pieInfo.listCountries) {
                        RelativeLayout.LayoutParams tvLayout = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
                                RelativeLayout.LayoutParams.WRAP_CONTENT);
                        tvLayout.setMargins(70, x, 0, 0);
                        x += 80;
                        TextView legend = new TextView(getContext());
                        legend.setText(country);
                        legend.setLayoutParams(tvLayout);
                        layout.addView(legend);
                        int[] colorsChart = pieChart.colors;
                        int nrCuloare = pieInfo.listCountries.indexOf(country);


                        RelativeLayout.LayoutParams imgViewLayout = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
                                RelativeLayout.LayoutParams.WRAP_CONTENT);
                        imgViewLayout.height = 50;
                        imgViewLayout.width = 50;
                        imgViewLayout.setMargins(10, y, 0, 0);
                        ImageView imageView = new ImageView(getContext());
                        imageView.setBackgroundColor(colorsChart[nrCuloare]);
                        imageView.setLayoutParams(imgViewLayout);
                        layout.addView(imageView);

                        y += 80;
                    }
                }

            }
        });

        return root;
    }

    private float[] calculateValues(float[] values) {
        Log.d("onDraw_CalculateValues","being_CALLED");
        float total = 0;
        float[] degreeValues = new float[values.length];
        for (int i = 0; i < values.length; i++) {
            total += values[i];
        }
        for (int i = 0; i < values.length; i++) {
            degreeValues[i] = 360 * (values[i] / total);
        }
        return degreeValues;
    }

    private void updateListView() {

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @SuppressLint("StaticFieldLeak")
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Object u = listView.getItemAtPosition(position);
                User user = (User) u;
                createDialog(user);
            }
        });

        listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @SuppressLint("StaticFieldLeak")
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                Object deleteUser = listView.getItemAtPosition(position);
                new AsyncTask<Void, Void, Void>() {
                    @Override
                    protected Void doInBackground(Void... voids) {
                        roomDbInstance.getUsersDao().eraseUser((User) deleteUser);
                        return null;
                    }

                    @Override
                    protected void onPostExecute(Void aVoid) {
                        super.onPostExecute(aVoid);
                        userListAdapter.remove((User) deleteUser);
                        nrRecords = userListAdapter.getCount();
                        userListAdapter.notifyDataSetChanged();
                    }
                }.execute();
                return false;
            }
        });
    }

    private void createDialog(User received) {
        AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
        LayoutInflater inflater = getLayoutInflater();
        View view = inflater.inflate(R.layout.update_user, null);
        TextView ip_Update = view.findViewById(R.id.ip_updateUser);
        TextView nickname = view.findViewById(R.id.nickname_updateUser);
        ip_Update.setText(received.getIp());
        nickname.setText(received.getNickname());
        Button updateBtn = view.findViewById(R.id.btn_update);
        builder.setView(view);
        AlertDialog dialog1 = builder.show();

        updateBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!nickname.getText().toString().equals(received.getNickname())) {
                    InputMethodManager inputMethodManager = (InputMethodManager)
                            getActivity().getApplicationContext().getSystemService(getContext().INPUT_METHOD_SERVICE);
                    // Hide the soft keyboard
                    inputMethodManager.hideSoftInputFromWindow(nickname.getWindowToken(), 0);
                    received.setNickname(nickname.getText().toString());
                    userListAdapter.notifyDataSetChanged();
                    updateOnDatabase(received.getId(), nickname.getText().toString());
                    dialog1.dismiss();
                } else {
                    AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
                    builder.setMessage("No changes?");
                    builder.setCancelable(true);
                    builder.setPositiveButton("Yup", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {

                        }
                    });
                    builder.setNegativeButton("Nope", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            dialog1.dismiss();
                        }
                    });
                    builder.show();
                }
            }

            @SuppressLint("StaticFieldLeak")
            private void updateOnDatabase(int id, String new_nickname) {
                new AsyncTask<Void, Void, Void>() {
                    @Override
                    protected Void doInBackground(Void... voids) {
                        roomDbInstance.getUsersDao().updateUser(id, new_nickname);
                        return null;
                    }
                }.execute();
            }
        });

        nickname.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                if (actionId == EditorInfo.IME_ACTION_DONE) {
                    InputMethodManager inputMethodManager = (InputMethodManager)
                            getActivity().getApplicationContext().getSystemService(getContext().INPUT_METHOD_SERVICE);
                    // Hide the soft keyboard
                    inputMethodManager.hideSoftInputFromWindow(nickname.getWindowToken(), 0);
//                    Toast.makeText(getContext(), nickname.getText(), Toast.LENGTH_SHORT).show();
                    return true;
                }
                return false;
            }
        });

    }

    public class PieInfo {
        ArrayList<String> listCountries = new ArrayList<>();
        ArrayList<Float> pondereCountries = new ArrayList<>();

        PieInfo() {

        }

        public ArrayList<String> getListCountries() {
            return listCountries;
        }

        public void setListCountries(ArrayList<String> listCountries) {
            this.listCountries = listCountries;
        }

        public ArrayList<Float> getPondereCountries() {
            return pondereCountries;
        }

        public void setPondereCountries(ArrayList<Float> pondereCountries) {
            this.pondereCountries = pondereCountries;
        }
    }

    private PieInfo calculPonderi() {
        PieInfo pieInfo = new PieInfo();
//         ArrayList<String> listCountries = new ArrayList<>();
//         ArrayList<Float> pondereCountries = new ArrayList<>();
        for (int j = 0; j < users.size(); j++) {
            float counterCountry = 1;
            String aux = users.get(j).getCountry();
            pieInfo.listCountries.add(aux);
            for (int i = 0; i < arrayList.size(); i++) {
                if (aux.equals(arrayList.get(i).getCountry())) {
                    counterCountry++;
                }
            }
//            Toast.makeText(getContext(),String.valueOf(counterCountry), Toast.LENGTH_SHORT).show();
            pieInfo.pondereCountries.add(counterCountry);
        }
        return pieInfo;
    }

    @SuppressLint("StaticFieldLeak")
    private void populateAdapter() {
//        Log.d("populateReached","Reached!");

        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... voids) {
                users = roomDbInstance.getUsersDao().getAllUsers();
                arrayList.addAll(users);
                return null;
            }

            @Override
            protected void onPostExecute(Void aVoid) {
                super.onPostExecute(aVoid);
                listView.setAdapter(userListAdapter);
                nrRecords = userListAdapter.getCount();
                userListAdapter.notifyDataSetChanged();
            }

        }.execute();

    }

    public ListUsersFragment() {
        //Required empty constructor
    }

    private void displayRating() {
        ratingBar.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener() {
            @Override
            public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) {
                Toast.makeText(getContext(), "" + rating, Toast.LENGTH_SHORT).show();
                tv.setText("Thanks for the feedback!");

            }
        });
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        listener = (OnDataPassListener) getActivity();
    }

    public class PieChartView extends View {

        private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        private int[] colors = {Color.BLACK, Color.CYAN, Color.GREEN, Color.RED, Color.BLUE};
        private RectF rectangle = new RectF(10, 10, 800, 800);
        private float[] valueDegrees;
        private float tmp = 0;

        public PieChartView(Context context, float[] values) {
            super(context);
            valueDegrees = new float[values.length];
            for (int i = 0; i < valueDegrees.length; i++) {
                valueDegrees[i] = values[i];
            }
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            for (int i = 0; i < valueDegrees.length; i++) {
                if (i == 0) {
                    paint.setColor(colors[i]);
                    canvas.drawArc(rectangle, 0, valueDegrees[i], true, paint);
                } else {
                    tmp += valueDegrees[i - 1];
                    paint.setColor(colors[i]);
                    canvas.drawArc(rectangle, tmp, valueDegrees[i], true, paint);
                }
            }
            Log.d("onDraw","beingCalled");
        }
    }
}

您必须了解 onDraw() 对于给定的 View 通常会被多次调用。它是 Android 屏幕刷新机制的一部分。在这种情况下,发生这种情况的原因可能是 View 尺寸略有变化(由于重新布局)。

因此,最好限制 onDraw() 函数更改对象的状态。您的 PieChartView 违反了该原则; tmp 正在更改。

要解决此问题,请将 tmp 设为局部变量,而不是成员变量。