Java ExpandableListView作为ViewPager的子级

Java ExpandableListView作为ViewPager的子级,java,android,Java,Android,我正在写一个控制个人预算的应用程序。它现在的设计基本上是使用两个不同的可扩展列表视图,一个用于收入,另一个用于支出。用于设置收入/费用类别以及交易的膨胀对话框。应用程序将数据存储在SQLite数据库中 到目前为止,一切顺利。当我试图实施某种设计,按不同月份组织这些数据时,我的问题就来了。我考虑过ViewPager,因为我认为它是最接近这个实现的选项。我是Android开发的新手,所以不确定是否有更好的选项来实现这个功能 此视图的活动和片段如下所示: SummaryActivity.java im

我正在写一个控制个人预算的应用程序。它现在的设计基本上是使用两个不同的可扩展列表视图,一个用于收入,另一个用于支出。用于设置收入/费用类别以及交易的膨胀对话框。应用程序将数据存储在SQLite数据库中

到目前为止,一切顺利。当我试图实施某种设计,按不同月份组织这些数据时,我的问题就来了。我考虑过ViewPager,因为我认为它是最接近这个实现的选项。我是Android开发的新手,所以不确定是否有更好的选项来实现这个功能

此视图的活动和片段如下所示:

SummaryActivity.java

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Build;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.fragment.app.Fragment;

import com.robin.xbudget.database.TransactionBaseHelper;
import com.robin.xbudget.database.TransactionDbSchema;
import com.robin.xbudget.database.TransactionDbSchema.TransactionTable;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SummaryActivity extends SingleFragmentActivity implements
        NewCategoryIncome.NewCategoryActivityListener
        , NewTransactionIncome.NewIncomeActivityListener
        , NewCategoryExpense.NewCategoryActivityListener
        , NewTransactionExpense.NewExpenseActivityListener
        , SummaryFragment.SummaryFragmentActivityListener
        , Statistics.StatisticsListener {

    /**
     * Constants
     */
    private static final String TAG = "XSummaryActivity";
    public static final String mSalaryKey = "salaryKey";
    public static final String mCurrencyKey = "currencyKey";

    /**
     * Members
     */
    private SQLiteDatabase mDatabase;
    private Context mContext;

    /**
     * Incomes
     */
    private List<String> listIncomesDataGroup;
    private Map<String, List<Transaction>> listIncomesDataChild;

    /**
     * Expenses
     */
    private List<String> listExpensesDataGroup;
    private Map<String, List<Transaction>> listExpensesDataChild;

    /**
     * Expense Adapter
     */
    private ExpandableListViewAdapter expandableExpensesListViewAdapter;
    private ExpandableListViewAdapter expandableIncomesListViewAdapter;


    /**
     * Getters / Setters
     */

    @Override
    public List<String> getIncomesDataGroup() {
        return listIncomesDataGroup;
    }

    @Override
    public List<String> getExpensesDataGroup() {
        return listExpensesDataGroup;
    }

    @Override
    public Map<String, List<Transaction>> getExpensesDataChild() {
        return listExpensesDataChild;
    }

    @Override
    public ExpandableListViewAdapter getIncomesAdapter() {
        return expandableIncomesListViewAdapter;
    }

    @Override
    public ExpandableListViewAdapter getExpensesAdapter() {
        return expandableExpensesListViewAdapter;
    }


    @Override
    public double getTotalIncomes() {
        double total = 0;
        for (Map.Entry<String, List<Transaction>> set : listIncomesDataChild.entrySet()) {
            for (Transaction t : set.getValue()) {
                total += t.getQuantity();
            }
        }
        Log.d(TAG, "Total of Income Transactions is: " + total);
        return total;
    }

    @Override
    public double getTotalExpenses() {
        double total = 0;
        for (Map.Entry<String, List<Transaction>> set : listExpensesDataChild.entrySet()) {
            for (Transaction t : set.getValue()) {
                total += t.getQuantity();
            }
        }
        Log.d(TAG, "Total of Expense Transactions is: " + total);
        return total;
    }


    @RequiresApi(api = Build.VERSION_CODES.N)
    @Override
    protected Fragment createFragment() {
        Log.d(TAG, "onCreateFragment() was called");
        initObject();
        return SummaryFragment.newInstance();
    }


    @Override
    public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
        Log.d(TAG, "onCreate() was called");
        super.onCreate(savedInstanceState, persistentState);

    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    public void initObject() {
        Log.d(TAG, "initObject() was called");

        //Starting the databases
        mContext = getApplicationContext();
        mDatabase = new TransactionBaseHelper(mContext).getWritableDatabase();
        // initializing the list of groups
        listIncomesDataGroup = new ArrayList<>();
        listExpensesDataGroup = new ArrayList<>();

        // initializing the list of child
        listIncomesDataChild = new HashMap<>();
        listExpensesDataChild = new HashMap<>();

        // initializing the adapter object
        expandableIncomesListViewAdapter = new ExpandableListViewAdapter(getApplicationContext(), listIncomesDataGroup, listIncomesDataChild);
        expandableExpensesListViewAdapter = new ExpandableListViewAdapter(getApplicationContext(), listExpensesDataGroup, listExpensesDataChild);

        updateCategories();
        updateChilds();

    }

    /***
     * Listeners - (Interface Implementations)
     */

    @RequiresApi(api = Build.VERSION_CODES.N)
    @Override
    public void insertIncome(Transaction transaction) {
        //String value = transaction + "   " + mCurrency;
        listIncomesDataChild.get(transaction.getCategory()).add(transaction);
        //updateChilds();
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    @Override
    public void insertExpense(Transaction transaction) {
        ContentValues values = getContentValues(transaction);
        Log.d(TAG, "TRANSACTION TO INSERT IS: " + transaction);
        mDatabase.insert(TransactionTable.mTransactionExpense, null, values);
        updateChilds();
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    @Override
    public void updateExpense(Transaction transaction) {
        ContentValues values = getContentValues(transaction);
        String mIdString = transaction.getId().toString();
        mDatabase.update(TransactionTable.mTransactionExpense, values, TransactionTable.ChildCols.UUID + " = ?", new String[]{mIdString});
        updateChilds();
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    @Override
    public void deleteExpense(Transaction transaction) {
        String mIdString = transaction.getId().toString();
        Log.d(TAG, "mIdString is: " + mIdString);
        Log.d(TAG, "rows deleted are: " + mDatabase.delete(TransactionDbSchema.TransactionTable.mTransactionExpense, TransactionTable.ChildCols.UUID + " = ?", new String[]{mIdString}));
        updateChilds();
    }

    @Override
    public void insertCategoryExpense(String category) {
        if (category != null || !category.trim().isEmpty()) {
            mDatabase.execSQL("INSERT INTO " + TransactionTable.mCategoryExpense + " ('category') " + "VALUES (" + "'" + category + "'" + ")");
            updateCategories();
        }
    }

    
    
    private ContentValues getContentValues(Transaction transaction) {
        ContentValues values = new ContentValues();
        values.put(TransactionTable.ChildCols.CATEGORY, transaction.getCategory());
        values.put(TransactionTable.ChildCols.UUID, transaction.getId().toString());
        values.put(TransactionTable.ChildCols.NAME, transaction.getName());
        values.put(TransactionTable.ChildCols.QUANTITY, transaction.getQuantity());
        values.put(TransactionTable.ChildCols.DATE, transaction.getDate().getTime());

        return values;
    }


    public List<String> getCategoryByTable(String table) {
        List<String> categories = new ArrayList<>();
        String query = "SELECT * from " + TransactionTable.mCategoryExpense;
        Cursor c = mDatabase.rawQuery(query, null);

        if (c.moveToFirst()) {
            while (!c.isAfterLast()) {
                categories.add(c.getString(0));
                c.moveToNext();
            }
        }
        return categories;
    }

    private TransactionCursorWrapper queryTransactions(String table, String whereClause, String[] whereArgs) {
        Cursor cursor = mDatabase.query(
                table
                ,
                null, // columns - null selects all columns
                whereClause,
                whereArgs,
                null, // groupBy
                null, // having
                null // orderBy
        );
        return new TransactionCursorWrapper(cursor);
    }

    @Override
    public List<Transaction> getTransactionsByTable(String table) {
        List<Transaction> transactions = new ArrayList<>();

        TransactionCursorWrapper cursor = queryTransactions(table, null, null);

        try {
            cursor.moveToFirst();
            while (!cursor.isAfterLast()) {
                if (!transactions.contains(cursor.getTransaction()))
                    transactions.add(cursor.getTransaction());
                cursor.moveToNext();
            }
        } finally {
            cursor.close();
        }
        return transactions;
    }

    @Override
    public void updateCategories() {
        List list = getCategoryByTable(TransactionTable.mCategoryExpense);

        Log.d(TAG, "BEFORE: GROUP SIZE" + list.size());
        listExpensesDataGroup.clear();
        listExpensesDataGroup.addAll(list);
        for (String category : listExpensesDataGroup)
            if (!listExpensesDataChild.containsKey(category))
                listExpensesDataChild.put(category, new ArrayList<Transaction>());

        expandableExpensesListViewAdapter.notifyDataSetChanged();
    }


    @RequiresApi(api = Build.VERSION_CODES.N)
    public void updateChilds() {

        //Retrieve data from the DB
        List<Transaction> transactionList = getTransactionsByTable(TransactionTable.mTransactionExpense);

        //Clear lists inside the Map
        for (Map.Entry<String, List<Transaction>> set : getExpensesDataChild().entrySet())
            set.getValue().clear();

        //Add the values to each List from the DB
        for (Transaction transaction : transactionList) {
            Log.d(TAG, "transaction.getCategory() value is: " + transaction.getCategory());
            Log.d(TAG, "listener.getExpensesDataChild().get(transaction.getCategory())" + getExpensesDataChild().get(transaction.getCategory()));
            listExpensesDataChild.get(transaction.getCategory()).add(transaction);
        }

        expandableExpensesListViewAdapter.notifyDataSetChanged();

                /*
        //Remove the category from the view if it has no data
        //Working through a local List to avoid ConcurrentModificationException
        List <String> localListExpensesDataGroup = new ArrayList<>();
        if(!listExpensesDataGroup.isEmpty() || listExpensesDataGroup!=null)
{        for(String group:listExpensesDataGroup){
            if(localListExpensesDataChild.containsKey(group)) {
                localListExpensesDataGroup.add(group);
            }
        }
 */

    }
}
package com.robin.xbudget;

import android.content.Context;
import android.os.Build;
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.ExpandableListView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.fragment.app.Fragment;

import java.util.List;
import java.util.Map;

public class SummaryFragment extends Fragment {

    SummaryFragmentActivityListener listener;

    Button newIncomeGroupBtn;
    Button newExpenseGroupBtn;
    Button newIncomeTransactionBtn;
    Button newExpenseTransactionBtn;

    /**
     * Expandable views
     */
    private ExpandableListView expandableIncomesListView;
    private ExpandableListView expandableExpensesListView;

    /**
     * Static members / Constants
     */
    private static final String TAG = "XSecondActivity";

    public static SummaryFragment newInstance() {
        return new SummaryFragment();
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        try {
            listener = (SummaryFragmentActivityListener) context;
        } catch (ClassCastException cce) {
            throw new ClassCastException("class has to implement SummaryFragmentActivityListener");
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_summary, container, false);

        Log.d(TAG, "getContext onCreateView es: " + getContext());

        expandableIncomesListView = view.findViewById(R.id.expandableIncomingsListView);
        expandableExpensesListView = view.findViewById(R.id.expandableExpensesListView);

        newIncomeGroupBtn = (Button) view.findViewById(R.id.button_income_group);
        newExpenseGroupBtn = (Button) view.findViewById(R.id.button_expense_group);
        newIncomeTransactionBtn = (Button) view.findViewById(R.id.button_incoming);
        newExpenseTransactionBtn = (Button) view.findViewById(R.id.button_expense_transaction);

        // setting list adapter
        expandableIncomesListView.setAdapter(listener.getIncomesAdapter());
        expandableExpensesListView.setAdapter(listener.getExpensesAdapter());


        initListeners();

        return view;
    }


    /**
     * method to initialize listeners of the views
     */

    private void initListeners() {

        expandableExpensesListView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
            @Override
            public void onGroupExpand(int groupPosition) {
                //Log.d(TAG, "Group position is: " + groupPosition);
            }
        });

        expandableIncomesListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {

            @Override
            public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
                //Log.d(TAG, "Group INCOMINGS position is: " + groupPosition + " and Child posititon is: " + childPosition);
                Transaction transaction = new Transaction();
                transaction.getId();
                Bundle bundle = new Bundle();

                NewTransactionIncome incomeDialog = new NewTransactionIncome();
                incomeDialog.show(getFragmentManager(), "Input new income");

                return false;
            }
        });


        expandableExpensesListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {

            @Override
            public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
                NewTransactionExpense expenseDialog = new NewTransactionExpense();
                Bundle bundle = new Bundle();
                bundle.putSerializable(NewTransactionExpense.ARG_EXPENSE_ID, ((Transaction) listener.getExpensesAdapter().getChild(groupPosition, childPosition)).getId());

                expenseDialog.setArguments(bundle);
                expenseDialog.show(getFragmentManager(), "Input new income");

                return false;
            }
        });


        /**
         * Initialize Button listeners
         */

        newIncomeTransactionBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(@Nullable View v) {
                NewTransactionIncome incomeDialog = new NewTransactionIncome();

            }
        });

        newIncomeGroupBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                NewCategoryIncome categoryIncomeDialog = new NewCategoryIncome();
                categoryIncomeDialog.show(getFragmentManager(), "NewIncomeCategory");
            }
        });

        newExpenseTransactionBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(@Nullable View v) {
                NewTransactionExpense expenseDialog = new NewTransactionExpense();
                Transaction transaction = new Transaction();
                Bundle bundle = new Bundle();
                bundle.putSerializable(NewTransactionExpense.ARG_EXPENSE_ID, transaction.getId());
                //expenseDialog.setArguments(bundle);
                expenseDialog.show(getFragmentManager(), "Input new expense");
            }
        });

        newExpenseGroupBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                NewCategoryExpense categoryExpenseDialog = new NewCategoryExpense();
                categoryExpenseDialog.show(getFragmentManager(), "NewExpenseCategory");
            }
        });
    }


    public interface SummaryFragmentActivityListener {
        List<Transaction> getTransactionsByTable(String table);
        Map<String, List<Transaction>> getExpensesDataChild();
        ExpandableListViewAdapter getIncomesAdapter();
        ExpandableListViewAdapter getExpensesAdapter();

        void updateCategories();
    }
}
导入android.content.ContentValues;
导入android.content.Context;
导入android.database.Cursor;
导入android.database.sqlite.SQLiteDatabase;
导入android.os.Build;
导入android.os.Bundle;
导入android.os.PersistableBundle;
导入android.util.Log;
导入androidx.annotation.Nullable;
导入androidx.annotation.RequiresApi;
导入androidx.fragment.app.fragment;
导入com.robin.xbudget.database.TransactionBaseHelper;
导入com.robin.xbudget.database.TransactionDbSchema;
导入com.robin.xbudget.database.TransactionDbSchema.TransactionTable;
导入java.util.ArrayList;
导入java.util.HashMap;
导入java.util.List;
导入java.util.Map;
公共类SummaryActivity扩展了SingleFragmentActivity实现
NewCategoryIncome.NewCategoryActivityListener
,NewTransactionIncome.NewIncomeActivityListener
,NewCategoryExpense.NewCategoryActivityListener
,NewTransactionExpense.NewExpenseActivityListener
,SummaryFragment.SummaryFragmentActivityListener
,统计学{
/**
*常数
*/
私有静态最终字符串TAG=“XSummaryActivity”;
公共静态最终字符串mSalaryKey=“salaryKey”;
公共静态最终字符串mCurrencyKey=“currencyKey”;
/**
*成员
*/
私有SQLITE数据库mDatabase;
私有上下文;
/**
*收入
*/
私有列表listIncomesDataGroup;
私有地图listIncomesDataChild;
/**
*费用
*/
私有列表listExpensesDataGroup;
私有地图listensesdatachild;
/**
*费用适配器
*/
私有可扩展ListViewAdapter可扩展费用ListViewAdapter;
私有ExpandableListViewAdapter ExpandableIncomeListViewAdapter;
/**
*能手/二传手
*/
@凌驾
公共列表getIncomesDataGroup(){
返回listIncomesDataGroup;
}
@凌驾
公共列表getExpensesDataGroup(){
返回listExpensesDataGroup;
}
@凌驾
公共地图GetExpenseSdatchild(){
返回ListExpenseSdatchild;
}
@凌驾
公共可扩展ListViewAdapter GetIncomeAdapter(){
返回ExpandableIncomeListViewAdapter;
}
@凌驾
public ExpandableListViewAdapter getExpensesAdapter(){
返回expandableExpensesListViewAdapter;
}
@凌驾
公共双getTotalIncomes(){
双倍合计=0;
对于(Map.Entry集:listIncomesDataChild.entrySet()){
对于(事务t:set.getValue()){
总计+=t.getQuantity();
}
}
Log.d(标签“收入交易总额为:“+总额”);
返回总数;
}
@凌驾
公共双getTotalExpenses(){
双倍合计=0;
对于(Map.Entry集:listExpensesDataChild.entrySet()){
对于(事务t:set.getValue()){
总计+=t.getQuantity();
}
}
Log.d(标签“费用交易总额为:”+总计);
返回总数;
}
@RequiresApi(api=Build.VERSION\u code.N)
@凌驾
受保护的片段createFragment(){
d(标记“onCreateFragment()被调用”);
initObject();
返回SummaryFragment.newInstance();
}
@凌驾
创建时的公共void(@Nullable Bundle savedInstanceState,@Nullable persistable Bundle persistentState){
d(标记“onCreate()被调用”);
super.onCreate(savedInstanceState、persistentState);
}
@RequiresApi(api=Build.VERSION\u code.N)
public void initObject(){
d(标记“initObject()被调用”);
//启动数据库
mContext=getApplicationContext();
mDatabase=newTransactionBaseHelper(mContext.getWritableDatabase();
//正在初始化组列表
listIncomesDataGroup=new ArrayList();
listExpensesDataGroup=new ArrayList();
//正在初始化子对象列表
listIncomesDataChild=新HashMap();
ListExpenseSdatchild=newHashMap();
//初始化适配器对象
expandableIncomesListViewAdapter=新的ExpandableListViewAdapter(getApplicationContext(),listIncomesDataGroup,listIncomesDataChild);
expandableExpensesListViewAdapter=新的ExpandableListViewAdapter(getApplicationContext(),listExpensesDataGroup,listExpensesDataChild);
updateCategories();
updateChilds();
}
/***
*侦听器-(接口实现)
*/
@RequiresApi(api=Build.VERSION\u code.N)
@凌驾
公共void insertIncome(事务处理){
//字符串值=事务+“”+mCurrency;
listIncomesDataChild.get(transaction.getCategory()).add(transaction);
//updateChilds();
}
@RequiresApi(api=Build.VERSION\u code.N)
@凌驾
公开作废插入费用(交易){
ContentValues=getContentValues(事务);
Log.d(标记“要插入的事务是:“+事务”);
mDatabase.insert(TransactionTable.mtTransactionExpense,null,值);
向上的