#java #android #android-studio
#java #Android #android-studio
Вопрос:
У меня есть метод setValuesCategories(View view, String category, int position), который я использую для программной установки текста нескольких TextViews в GridLayout. Этот метод вызывается в первый раз при создании фрагмента со строковым значением первого элемента в счетчике. Текстовые представления, объявленные внутри метода, имеют значение, и текст правильно изменен.
Проблема заключается в том, когда мы выбираем другой элемент в счетчике, и тот же метод вызывается снова. В этом случае текстовые представления, объявленные в методе, имеют нулевое значение, и я получаю исключение NullPointerException.
Я вообще не понимаю, почему я получаю это, поскольку метод синхронизирован, и это должно помешать второму потоку попытаться присвоить строковое значение до инициализации объекта TextView.
Заранее благодарю вас!
package com.robin.miniBudget;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.GridLayout;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import com.robin.miniBudget.database.DatabaseSchema;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class StatisticsFragment extends Fragment {
private OuterListener mOuterListener;
private ViewPager2 viewPager;
private Spinner pagerSpinner;
private StatisticsFragment.DemoCollectionAdapter demoCollectionAdapter;
StatisticsFragment stats;
public static StatisticsFragment newInstance() {
return new StatisticsFragment();
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_pager, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
demoCollectionAdapter = new StatisticsFragment.DemoCollectionAdapter(this);
viewPager = view.findViewById(R.id.pager);
viewPager.setAdapter(demoCollectionAdapter);
viewPager.setPageTransformer(new ZoomOutPageTransformer());
stats = StatisticsFragment.newInstance();
pagerSpinner = view.findViewById(R.id.spinner_month);
pagerSpinner.setVisibility(View.GONE);
TabLayout tabLayout = view.findViewById(R.id.tab_layout);
new TabLayoutMediator(tabLayout, viewPager,
(tab, position) -> tab.setText(position == 0 ? "Incomes" : (position == 1) ? "Expenses" : "Savings")
).attach();
}
public class DemoCollectionAdapter extends FragmentStateAdapter {
public DemoCollectionAdapter(Fragment fragment) {
super(fragment);
}
@NonNull
@Override
public Fragment createFragment(int position) {
// Return a NEW fragment instance in createFragment(int)
Fragment fragment = new StatisticsFragment.DemoObjectFragment();
Bundle args = new Bundle();
// Our object is just an integer :-P
args.putInt(StatisticsFragment.DemoObjectFragment.POSITION, position);
fragment.setArguments(args);
return fragment;
}
@Override
public int getItemCount() {
return 3;
}
}
// Instances of this class are fragments representing a single
// object in our collection.
public static class DemoObjectFragment extends Fragment {
public static final String POSITION = "Statistics ";
int flagItemSelected = 0;
InnerListener mInnerListener;
ScrollView sv;
int position;
Spinner mSpinner;
Set mCategoriesSet;
List <Category> mCategoriesList;
ArrayAdapter spinnerAdapter;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_statistics, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
Bundle args = getArguments();
position = args.getInt(POSITION);
Toast.makeText(getContext(),"position is: " position,Toast.LENGTH_SHORT).show();
Log.d("position ","position is: " position);
sv = view.findViewById(R.id.scroll_stats_1);
mSpinner = view.findViewById(R.id.spinner_fragment_stats);
if(position==2)mSpinner.setVisibility(View.GONE);
mCategoriesList = mInnerListener.getCategories(DatabaseSchema.TransactionTable.mCategories, "CAST(group_id as TEXT) = ?", new String[]{String.valueOf(position 1)});
mCategoriesSet = new HashSet();
for (Category c : mCategoriesList) mCategoriesSet.add(c.getName());
spinnerAdapter = new ArrayAdapter(getContext(),android.R.layout.simple_spinner_dropdown_item, new ArrayList<String>(mCategoriesSet));
mSpinner.setAdapter(spinnerAdapter);
mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
//Toast.makeText(getContext(), "" spinnerAdapter.getItem(i), Toast.LENGTH_SHORT).show();
//if(position!=2)setValues(view, (String) mSpinner.getSelectedItem(), position);
if(flagItemSelected > 0 amp;amp; position!=2) setValuesCategories(view,(String) mCategoriesSet.toArray()[1], position);
;
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
setName(view, position);
setDrawable(view, position);
if(position!=2) {
setValuesTransactions(view, (String) mCategoriesSet.toArray()[0], position);
setValuesCategories(view,(String) mCategoriesSet.toArray()[0], position);
}
if(position==2) setValuesSavings(view);
}
void setName(View view, int position) {
List<String> type = Arrays.asList("incomes", "expenses", "savings");
String group = type.get(position);
for (char c : "abc".toCharArray()) {
for (int i = 1; i <= 8; i ) {
((TextView) view.findViewById(getResources().getIdentifier("title_" String.valueOf(c) i, "id", getContext().getPackageName()))).
setText(getResources().getIdentifier("text_" group "_" String.valueOf(c) i, "string", getContext().getPackageName()));
}
}
}
void setDrawable(View view, int position) {
List<String> type = Arrays.asList("incomes", "expenses", "savings");
String group = type.get(position);
for (char c : "abc".toCharArray()) {
for (int i = 1; i <= 4; i ) {
((LinearLayout) view.findViewById(getResources().getIdentifier("grid_" String.valueOf(c) i, "id", getContext().getPackageName())))
.setBackground(ContextCompat.getDrawable(getContext(),
getResources().getIdentifier("backcolor_trans_" group, "drawable", getContext().getPackageName())));
}
if (position != 2)
for (int i = 5; i <= 8; i ) {
((LinearLayout) view.findViewById(getResources().getIdentifier("grid_" String.valueOf(c) i, "id", getContext().getPackageName())))
.setBackground(ContextCompat.getDrawable(getContext(),
getResources().getIdentifier("backcolor_cat_" group, "drawable", getContext().getPackageName())));
}
for (int i = 2; i <= 8; i ) {
if (position == 2)
((LinearLayout) view.findViewById(getResources().getIdentifier("grid_" String.valueOf(c) i, "id", getContext().getPackageName()))).setVisibility(View.INVISIBLE);
}
}
if (position != 2) ((TextView) view.findViewById(R.id.category_name)).setVisibility(View.VISIBLE);
else ((TextView) view.findViewById(R.id.category_name)).setVisibility(View.INVISIBLE);
}
synchronized void setValuesTransactions(View view, String category, int position) {
Log.d("position", " setValues() was called");
//Toast.makeText(getContext(),"position is: " position,Toast.LENGTH_SHORT).show();
if (position!=2) {
for (int i = 1; i <= 4; i ) {
TextView a1to4 = ((TextView) view.findViewById(getResources().getIdentifier("value_a" i, "id", getContext().getPackageName())));
TextView b1to4 = ((TextView) view.findViewById(getResources().getIdentifier("value_b" i, "id", getContext().getPackageName())));
TextView c1to4 = ((TextView) view.findViewById(getResources().getIdentifier("value_c" i, "id", getContext().getPackageName())));
String getTransDiff = mInnerListener.getTransDiff(DatabaseSchema.TransactionTable.mTransactions, position 1, i);
String getTransDiffAvg = mInnerListener.getTransDiffAvg(DatabaseSchema.TransactionTable.mTransactions, position 1, i);
a1to4.setText(String.valueOf(mInnerListener.getTransAmount(DatabaseSchema.TransactionTable.mTransactions, position 1, i)));
b1to4.setText(String.valueOf(getTransDiff));
c1to4.setText(String.valueOf(getTransDiffAvg));
if (getTransDiff.contains(" "))
b1to4.setTextColor(position == 1 || position == 2 ? getResources().getColor(R.color.expenses_cat) : getResources().getColor(R.color.savings_trans));
else {
if (getTransDiff.contains("-")) {
b1to4.setTextColor(position == 1 || position == 2 ? getResources().getColor(R.color.savings_trans) : getResources().getColor(R.color.expenses_cat));
} else {
b1to4.setTextColor(getResources().getColor(R.color.dark_grey));
}
}
if (getTransDiffAvg.contains(" "))
c1to4.setTextColor(position == 1 || position == 2 ? getResources().getColor(R.color.expenses_cat) : getResources().getColor(R.color.savings_trans));
else {
if (getTransDiffAvg.contains("-")) {
c1to4.setTextColor(position == 1 || position == 2 ? getResources().getColor(R.color.savings_trans) : getResources().getColor(R.color.expenses_cat));
} else {
c1to4.setTextColor(getResources().getColor(R.color.dark_grey));
}
}
}
}
}
synchronized void setValuesCategories(View view, String category, int position){
for (int i = 5; i <= 8; i ) {
Log.d("position", "position is :" position " and i value is: " i " and Category is: " category " getContext().getPackageName() " getContext().getPackageName());
TextView a5to8 = ((TextView) view.findViewById(getResources().getIdentifier("value_a" i, "id", getContext().getPackageName())));
TextView b5to8 = ((TextView) view.findViewById(getResources().getIdentifier("value_b" i, "id", getContext().getPackageName())));
TextView c5to8 = ((TextView) view.findViewById(getResources().getIdentifier("value_c" i, "id", getContext().getPackageName())));
Double getCatsAmount = mInnerListener.getCatsAmount(DatabaseSchema.TransactionTable.mCategories, category, position 1, i);
String getCatsDiff = mInnerListener.getCatsDiff(DatabaseSchema.TransactionTable.mCategories, category, position 1, i);
String getCatsAvgDiff = mInnerListener.getCatsDiffAvg(DatabaseSchema.TransactionTable.mTransactions, category, position 1, i);
a5to8.setText(String.valueOf(getCatsAmount));
b5to8.setText(String.valueOf(getCatsDiff));
if (position != 2)
c5to8.setText(String.valueOf(getCatsAvgDiff));
if (getCatsDiff.contains(" "))
b5to8.setTextColor(position == 1 || position == 2 ? getResources().getColor(R.color.expenses_cat) : getResources().getColor(R.color.savings_trans));
else {
if (getCatsDiff.contains("-")) {
b5to8.setTextColor(position == 1 || position == 2 ? getResources().getColor(R.color.savings_trans) : getResources().getColor(R.color.expenses_cat));
} else {
b5to8.setTextColor(getResources().getColor(R.color.dark_grey));
}
}
if (getCatsAvgDiff.contains(" "))
b5to8.setTextColor(position == 1 || position == 2 ? getResources().getColor(R.color.expenses_cat) : getResources().getColor(R.color.savings_trans));
else {
if (getCatsAvgDiff.contains("-")) {
b5to8.setTextColor(position == 1 || position == 2 ? getResources().getColor(R.color.savings_trans) : getResources().getColor(R.color.expenses_cat));
} else {
c5to8.setTextColor(getResources().getColor(R.color.dark_grey));
}
}
}
}
synchronized void setValuesSavings(View view){
GridLayout gl = view.findViewById(getResources().getIdentifier("layout_grid_categories", "id", getContext().getPackageName()));
gl.setVisibility(View.GONE);
Toast.makeText(getContext(), "setvaluesavings called", Toast.LENGTH_SHORT).show();
TextView a1 = ((TextView) view.findViewById(getResources().getIdentifier("value_a1", "id", getContext().getPackageName())));
TextView b1 = ((TextView) view.findViewById(getResources().getIdentifier("value_b1", "id", getContext().getPackageName())));
TextView c1 = ((TextView) view.findViewById(getResources().getIdentifier("value_c1", "id", getContext().getPackageName())));
a1.setText(String.valueOf(mInnerListener.getMonthlySavingsAmount()));
b1.setText(mInnerListener.getSavingsDiff());
c1.setText(mInnerListener.getSavingsDiffAvg());
if (mInnerListener.getSavingsDiff().contains(" "))
b1.setTextColor(getResources().getColor(R.color.savings_trans));
else {
if (mInnerListener.getSavingsDiff().contains("-")) {
b1.setTextColor(getResources().getColor(R.color.expenses_cat));
} else {
b1.setTextColor(getResources().getColor(R.color.dark_grey));
}
}
if (mInnerListener.getSavingsDiffAvg().contains(" "))
c1.setTextColor(getResources().getColor(R.color.savings_trans));
else {
if (mInnerListener.getSavingsDiffAvg().contains("-")) {
c1.setTextColor(getResources().getColor(R.color.expenses_cat));
} else {
c1.setTextColor(getResources().getColor(R.color.dark_grey));
}
}
}
void resetSpinner(int position){
mCategoriesList = mInnerListener.getCategories(DatabaseSchema.TransactionTable.mCategories, "CAST(group_id as TEXT) = ?", new String[]{String.valueOf( position)});
Set mCategoriesSet = new HashSet();
for (Category c : mCategoriesList) mCategoriesSet.add(c.getName());
spinnerAdapter = new ArrayAdapter(getContext(), android.R.layout.simple_spinner_dropdown_item, mCategoriesSet.toArray());
mSpinner.setAdapter(spinnerAdapter);
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
try {
mInnerListener = (StatisticsFragment.DemoObjectFragment.InnerListener) context;
} catch (ClassCastException cce) {
throw new ClassCastException("Class must implement StatisticListener");
}
}
public interface InnerListener {
double getTransAmount(String tableName, int group_id, int period);
double getMonthlySavingsAmount();
String getSavingsDiff();
String getSavingsDiffAvg();
String getTransDiff(String tableName, int group_id, int period);
String getTransDiffAvg(String tableName, int group_id, int period);
double getCatsAmount(String tableName, String name, int group_id, int period);
String getCatsDiff(String tableName, String name, int group_id, int period);
String getCatsDiffAvg(String tableName, String name, int group_id, int period);
List<Category> getCategories(String table, String whereClause, String[] whereArgs);
}
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
try {
mOuterListener = (StatisticsFragment.OuterListener) context;
} catch (ClassCastException cce) {
throw new ClassCastException("Class must implement StatisticListener");
}
}
interface OuterListener {
List<Category> getCategories(String table, String whereClause, String[] whereArgs);
}
}
Трассировка ошибки в стеке
2021-01-22 18:08:33.980 12639-12639/com.robin.miniBudget D/position: position is: 1
2021-01-22 18:08:33.994 12639-12639/com.robin.miniBudget D/position: setValues() was called
2021-01-22 18:08:33.995 12639-12639/com.robin.miniBudget D/position: position is :1 and i value is: 1 and Category is: Groceries getContext().getPackageName() com.robin.miniBudget
2021-01-22 18:08:33.995 12639-12639/com.robin.miniBudget D/position: a1to4androidx.appcompat.widget.AppCompatTextView{9c39159 V.ED..... ......ID 0,0-0,0 #7f0a01e3 app:id/value_a1}
2021-01-22 18:08:33.995 12639-12639/com.robin.miniBudget D/position: b1to4androidx.appcompat.widget.AppCompatTextView{264311e V.ED..... ......ID 0,0-0,0 #7f0a01eb app:id/value_b1}
2021-01-22 18:08:33.995 12639-12639/com.robin.miniBudget D/position: c1to4androidx.appcompat.widget.AppCompatTextView{6d43dff V.ED..... ......ID 0,0-0,0 #7f0a01f3 app:id/value_c1}
2021-01-22 18:08:34.007 12639-12639/com.robin.miniBudget D/position: position is :1 and i value is: 2 and Category is: Groceries getContext().getPackageName() com.robin.miniBudget
2021-01-22 18:08:34.007 12639-12639/com.robin.miniBudget D/position: a1to4androidx.appcompat.widget.AppCompatTextView{57c47cc V.ED..... ......ID 0,0-0,0 #7f0a01e4 app:id/value_a2}
2021-01-22 18:08:34.008 12639-12639/com.robin.miniBudget D/position: b1to4androidx.appcompat.widget.AppCompatTextView{792ea15 V.ED..... ......ID 0,0-0,0 #7f0a01ec app:id/value_b2}
2021-01-22 18:08:34.008 12639-12639/com.robin.miniBudget D/position: c1to4androidx.appcompat.widget.AppCompatTextView{e1e412a V.ED..... ......ID 0,0-0,0 #7f0a01f4 app:id/value_c2}
2021-01-22 18:08:34.019 12639-12639/com.robin.miniBudget D/position: position is :1 and i value is: 3 and Category is: Groceries getContext().getPackageName() com.robin.miniBudget
2021-01-22 18:08:34.019 12639-12639/com.robin.miniBudget D/position: a1to4androidx.appcompat.widget.AppCompatTextView{b38bb1b V.ED..... ......ID 0,0-0,0 #7f0a01e5 app:id/value_a3}
2021-01-22 18:08:34.019 12639-12639/com.robin.miniBudget D/position: b1to4androidx.appcompat.widget.AppCompatTextView{20c14b8 V.ED..... ......ID 0,0-0,0 #7f0a01ed app:id/value_b3}
2021-01-22 18:08:34.020 12639-12639/com.robin.miniBudget D/position: c1to4androidx.appcompat.widget.AppCompatTextView{bc51291 V.ED..... ......ID 0,0-0,0 #7f0a01f5 app:id/value_c3}
2021-01-22 18:08:34.067 12639-12639/com.robin.miniBudget D/position: position is :1 and i value is: 4 and Category is: Groceries getContext().getPackageName() com.robin.miniBudget
2021-01-22 18:08:34.068 12639-12639/com.robin.miniBudget D/position: a1to4androidx.appcompat.widget.AppCompatTextView{bb745f6 V.ED..... ......ID 0,0-0,0 #7f0a01e6 app:id/value_a4}
2021-01-22 18:08:34.068 12639-12639/com.robin.miniBudget D/position: b1to4androidx.appcompat.widget.AppCompatTextView{69dedf7 V.ED..... ......ID 0,0-0,0 #7f0a01ee app:id/value_b4}
2021-01-22 18:08:34.068 12639-12639/com.robin.miniBudget D/position: c1to4androidx.appcompat.widget.AppCompatTextView{3c9c464 V.ED..... ......ID 0,0-0,0 #7f0a01f6 app:id/value_c4}
2021-01-22 18:08:34.225 12639-12639/com.robin.miniBudget D/position: position is: 2
2021-01-22 18:08:34.242 12639-12639/com.robin.miniBudget D/MainActivity: AMOUNT currentperiod 77.5
2021-01-22 18:08:34.242 12639-12639/com.robin.miniBudget D/MainActivity: AMOUNT previousperiod 400.0
2021-01-22 18:08:34.251 12639-12639/com.robin.miniBudget D/MainActivity: AMOUNT currentperiod 77.5
2021-01-22 18:08:34.251 12639-12639/com.robin.miniBudget D/MainActivity: AMOUNT previousperiod 400.0
2021-01-22 18:08:34.256 12639-12639/com.robin.miniBudget D/MainActivity: AMOUNT currentperiod 77.5
2021-01-22 18:08:34.256 12639-12639/com.robin.miniBudget D/MainActivity: AMOUNT previousperiod 400.0
2021-01-22 18:08:34.556 12639-12698/com.robin.miniBudget D/EGL_emulation: eglMakeCurrent: 0x76bbfb68c260: ver 2 0 (tinfo 0x76bc126f3820)
2021-01-22 18:08:34.575 12639-12698/com.robin.miniBudget D/EGL_emulation: eglMakeCurrent: 0x76bbfb68c260: ver 2 0 (tinfo 0x76bc126f3820)
2021-01-22 18:08:37.167 12639-12639/com.robin.miniBudget W/obin.miniBudge: Accessing hidden field Landroid/widget/AbsListView;->mIsChildViewEnabled:Z (light greylist, reflection)
2021-01-22 18:08:37.273 12639-12698/com.robin.miniBudget D/EGL_emulation: eglMakeCurrent: 0x76bbfb68c260: ver 2 0 (tinfo 0x76bc126f3820)
2021-01-22 18:08:37.370 12639-12698/com.robin.miniBudget I/chatty: uid=10109(com.robin.miniBudget) RenderThread identical 3 lines
2021-01-22 18:08:37.411 12639-12698/com.robin.miniBudget D/EGL_emulation: eglMakeCurrent: 0x76bbfb68c260: ver 2 0 (tinfo 0x76bc126f3820)
2021-01-22 18:08:38.064 12639-12698/com.robin.miniBudget D/EGL_emulation: eglMakeCurrent: 0x76bbfb68c260: ver 2 0 (tinfo 0x76bc126f3820)
2021-01-22 18:08:38.104 12639-12698/com.robin.miniBudget I/chatty: uid=10109(com.robin.miniBudget) RenderThread identical 1 line
2021-01-22 18:08:38.122 12639-12698/com.robin.miniBudget D/EGL_emulation: eglMakeCurrent: 0x76bbfb68c260: ver 2 0 (tinfo 0x76bc126f3820)
2021-01-22 18:08:38.129 12639-12639/com.robin.miniBudget D/AndroidRuntime: Shutting down VM
2021-01-22 18:08:38.131 12639-12639/com.robin.miniBudget E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.robin.miniBudget, PID: 12639
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
at com.robin.miniBudget.StatisticsFragment$DemoObjectFragment.setValuesCategories(StatisticsFragment.java:330)
at com.robin.miniBudget.StatisticsFragment$DemoObjectFragment$1.onItemSelected(StatisticsFragment.java:210)
at android.widget.AdapterView.fireOnSelected(AdapterView.java:944)
at android.widget.AdapterView.dispatchOnItemSelected(AdapterView.java:933)
at android.widget.AdapterView.access$300(AdapterView.java:53)
at android.widget.AdapterView$SelectionNotifier.run(AdapterView.java:898)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
2021-01-22 18:08:38.140 12639-12639/com.robin.miniBudget I/Process: Sending signal. PID: 12639 SIG: 9
Ответ №1:
Представление представления параметров в методе SetValuesCategories было затенено в прослушивателе Spinner.
Решил проблему, переименовав этот параметр в прослушивателе.
выбрана общедоступная пустота onItemSelected(AdapterView<?> AdapterView, View v, int i, long l)