Как отобразить дату из базы данных SQLite в виде оси X в GraphView другого действия, из показа только 1-1-1970? - PullRequest
0 голосов
/ 11 января 2019

Я создаю приложение, которое выполняет некоторые вычисления в MainActivity.java и сохраняет результаты в базе данных SQLite. Когда пользователь нажимает кнопку, открывается GraphActivity.java с соответствующим GraphView. Возможно, это потому, что у меня пока нет большого опыта работы с базами данных SQLite, но я не могу заставить ось X графика отображать дату, когда был сохранен каждый результат.

Итак, учитывая, что метод Вставка и График выполняются в отдельных действиях, как я могу получить сохраненные даты для отображения в виде оси X в GraphActivity?

Я следовал учебнику YouTube для GraphView date & SQLite, но в нем хранятся и График в одном действии. (https://www.youtube.com/watch?v=lSgK6-cKjmA&list=PLFh8wpMiEi88ojfNpavGpMB0dtP4mvEqa&index=16)

Я пытался отправить переменную даты с помощью Intent EXTRAS, но она вынуждает вас перейти к GraphActivity при нажатии кнопки Сохранить. Затем я попытался получить время в GraphActivity, которая работает, но показывает дату по оси X как непрерывную «1-1-1970» для каждого результата. Я использовал формат, чтобы показать текущую дату с отметкой времени, но все равно он не показывает дату, когда был сохранен каждый результат, а только текущую дату для всех.

MainActivity.java: метод вставки для результатов и даты

public void insertData() {
    try {
        (...)

        // Gets the time & date the results are stored

        String timeStamp = new SimpleDateFormat("d M yy hh:mm").format(Calendar.getInstance().getTime());

        // Create a ContentValues object where column names are the keys,
        // and container attributes from the MainActivity are the values.

        ContentValues values = new ContentValues();
        values.put(DexameniEntry.COLUMN_CONTAINER_NAME, "TODO");
        values.put(DexameniEntry.COLUMN_a, X1aInput);
        values.put(DexameniEntry.COLUMN_DATE, timeStamp);
        values.put(DexameniEntry.COLUMN_b, X1bInput);
        values.put(DexameniEntry.COLUMN_c, X1cInput);
        values.put(DexameniEntry.COLUMN_d, dX1StringDouble);
        values.put(DexameniEntry.COLUMN_e, eX1StringDouble);
        values.put(DexameniEntry.COLUMN_percent, percentX1fromDoubletoString);

        (...)
        } catch (NumberFormatException e) {

        } catch (NullPointerException e) {
        }
}

GraphActivity.java: настройка GraphView

public class GraphActivity extends AppCompatActivity { 
    (...)
    SimpleDateFormat sdf = new SimpleDateFormat("EEE d M yyyy h mm", Locale.US);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.graph_activity);

    GraphView bigGraphX1 = findViewById(R.id.bigGraph);
    mDbHelper = new ResultsDbHelper(this);
    sqLiteDatabase = mDbHelper.getWritableDatabase();

    bigGraphX1.getGridLabelRenderer().setLabelFormatter(new DefaultLabelFormatter() {

        @Override
        public String formatLabel(double value, boolean isValueX) {
            if (isValueX) {
                return
                        sdf.format(new Date((long)value));
            }else {
                return super.formatLabel(value, isValueX);
            }
        }
    });

    (...)

EDIT Класс DbHelper.class (с именем ResultsDbHelper)

public class ResultsDbHelper extends SQLiteOpenHelper {

   public static final String LOG_TAG = ResultsDbHelper.class.getSimpleName();

//    Name of the database in a String type constant (to be referenced later)
private static final String DATABASE_NAME = "containerResults.db";
//    Database version in a Integer type constant for updating the database
private static final int DATABASE_VERSION = 1;

//    Constructor: Constructs a new instance of ResultsDbHelper.
//     * @param is the context of the app

public ResultsDbHelper(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

//    Modify the onCreate method to have the table created on startup of the app
@Override
public void onCreate(SQLiteDatabase db) {

// Define the schema of the table: which columns will be created by the onCreate method.
//        The whole schema creation is put in a String variable (CREATE_RESULTS_TABLE) for easy reference

    String CREATE_RESULTS_TABLE = "CREATE TABLE " + DexameniEntry.TABLE_NAME + " ("
            + DexameniEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
            + DexameniEntry.COLUMN_CONTAINER_NAME + " TEXT NOT NULL, "
            + DexameniEntry.COLUMN_DATE + " TEXT NOT NULL, "
            + DexameniEntry.COLUMN_a + " REAL NOT NULL, "
            + DexameniEntry.COLUMN_b + " REAL NOT NULL, "
            + DexameniEntry.COLUMN_c + " REAL NOT NULL, "
            + DexameniEntry.COLUMN_d + " REAL NOT NULL, "
            + DexameniEntry.COLUMN_e + " REAL NOT NULL, "
            + DexameniEntry.COLUMN_percent + " REAL NOT NULL);";

//        Execute the SQL Statement (Create the table)
    db.execSQL(CREATE_RESULTS_TABLE);
}

/**
 * This is called when the database needs to be upgraded.
 */
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    final String LOG_TAG = ("Upgrading the database from version " + oldVersion + " to " + newVersion);
    // on upgrade drop older tables
    db.execSQL("DROP TABLE IF EXISTS " + DexameniEntry.TABLE_NAME);

    //        Recreate tables
    onCreate(db);
    }
}

Я ожидаю, что на оси X будет отображаться дата сохранения каждого результата, чтобы все значения отображались как LineSeries в GraphView. Но я не могу передать даты из базы данных в График, поэтому дата всегда одинакова для всех, а LineSeries не согласован.

EDIT : Перед публикацией вопроса я также начал искать способ добавить в GraphActivity ссылку на базу данных столбца DATE внутри метода FormatLabel . Например

@Override
    public String formatLabel(double value, boolean isValueX) {
        if (isValueX) {
            return
             sdf.format(new Date(**put here the DATE column variable so that the X-axis is populated the column's data**);
        }else {
            return super.formatLabel(value, isValueX);
        }

Я тоже не мог этого сделать, потому что не знаю, как написать этот код ...

РЕДАКТИРОВАТЬ : Изображение проблемы

Я не знаю, что еще сделать, чтобы решить эту проблему, не могли бы вы мне помочь?

РЕДАКТИРОВАТЬ 2 : GraphActivity после изменений (Похоже, что график все еще не заполнен данными БД. Может возникнуть проблема с сохранением данных в db? Idk .. )

1 Ответ

0 голосов
/ 12 января 2019

Вы пытаетесь сделать слишком много в MainActivity, и у вас, возможно, возникают проблемы с датой, поскольку из ваших комментариев видно, что они / она равна 0.

Как правило, вы, вероятно, хотите пройти критерии для создания графика (например, диапазон дат для графика), а затем извлечь данные из базы данных с помощью методов, закодированных в Databasehelper (ResultsHelper).

Вместо получения текущего времени при добавлении данных и сохранении их в базе данных в формате D M Y. Вы могли бы просто иметь значение (например, извлечение данных в соответствии с диапазоном дат), сохраняя дату в сортируемом формате и манипулируя / форматируя даты в формате, который удобен для SQLite, главным образом, ГГГГ-ММ-ДД ЧЧ: ММ: СС (хотя вы могли бы просто сохраните метку времени).

Поэтому я бы предложил несколько относительно простых изменений.

  1. Измените определение столбца даты на: -

    + DexameniEntry.COLUMN_DATE + " TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, " //<<<<<<<<<< LET SQLITE GET THE DATE TIME

    • Это позволяет SQLite сохранять текущую дату и время, если вы просто не предоставите значение, что делается закомментированием / удалением строки: - //values.put(DexameniEntry.COLUMN_DATE, timeStamp); //<<<<<<<<<< Use default
  2. Переместить метод insertData в ResultHeper (его затем можно использовать в другом месте)

  3. Добавить метод в ResultHelper для извлечения данных в Курсор, включая динамическое генерирование столбцов.

    • динамические столбцы - это дополнительные столбцы, генерируемые на лету, говорящие SQLite о том, что нужно делать.
    • например. скажем, вы хотите добавить 2 столбца a и b, вы можете сказать SELECT *, a + b AS my_addition FROM the_table;, и результат будет включать все столбцы И столбец my_addition.
  4. Передайте основные / минимальные критерии выбора для извлечения данных для графика из MainActivity в GraphActivity, а затем извлеките фактические данные в graphActivity.

Примечание. Изменено для заполнения графика метками даты.

Рабочий пример

Следующий код, основанный на вашем коде и приведенных выше пунктах, является рабочим примером (он не заполняет график, а получает данные).

DexameniEntry.java

public class DexameniEntry {

    public static final String[] WEEKDAYS_LONG = new String[]{"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
    public static final String[] WEEKDAYS_SHORT = new String[]{"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};

    public static final String _ID = BaseColumns._ID;
    public static final String TABLE_NAME = "container_results";
    public static final String COLUMN_CONTAINER_NAME = "container_name";
    public static final String COLUMN_DATE = "container_date";
    public static final String COLUMN_a = "container_value_a";
    public static final String COLUMN_b = "container_value_b";
    public static final String COLUMN_c = "container_value_c";
    public static final String COLUMN_d = "container_value_d";
    public static final String COLUMN_e = "container_value_e";
    public static final String COLUMN_percent = "container_percent";


    public static final String EXTRACT_COLUMN_DATELABEL = "date_label";
    public static final String EXTRACT_COLUMN_GRAPHDATELABEL = "graph_date_label";

    public static final String INTENTKEY_GRAPHVALUE = "ik_graph_value";
}
  • Это сделано главным образом с помощью догадки (имена столбцов и таблиц). Однако обратите внимание на следующие две константы (можно использовать константы WEEKDAYS_ ??)
    • EXTRACT_COLUMN_DATELABEL (динамически генерируемое имя столбца) и
    • EXTRACT_COLUMN_GRAPHDATELABEL (динамически генерируемая метка времени Unix)
    • INTENTKEY_GRAPHVALUE (используется для передачи значения намерения)

ResultHelper

public class ResultsDbHelper extends SQLiteOpenHelper {

    public static final String LOG_TAG = ResultsDbHelper.class.getSimpleName();

    // Date format that suits SQLite i.e. YYYY-MM-DD HH:MM:SS
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); // Not used but could be useful

    //    Name of the database in a String type constant (to be referenced later)
    private static final String DATABASE_NAME = "containerResults.db";
    //    Database version in a Integer type constant for updating the database
    private static final int DATABASE_VERSION = 1;

    SQLiteDatabase mDB;

//    Constructor: Constructs a new instance of ResultsDbHelper.
//     * @param is the context of the app

    public ResultsDbHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        mDB = this.getWritableDatabase(); // Sets mDB (also forces open of DB)
    }

    //    Modify the onCreate method to have the table created on startup of the app
    @Override
    public void onCreate(SQLiteDatabase db) {

// Define the schema of the table: which columns will be created by the onCreate method.
//        The whole schema creation is put in a String variable (CREATE_RESULTS_TABLE) for easy reference

        String CREATE_RESULTS_TABLE = "CREATE TABLE " + DexameniEntry.TABLE_NAME + " ("
                + DexameniEntry._ID + " INTEGER PRIMARY KEY, " //<<<<<<<<<< AUTOINCREMENT NOT REQD AS IS INEFFICIENT
                + DexameniEntry.COLUMN_CONTAINER_NAME + " TEXT NOT NULL, "
                + DexameniEntry.COLUMN_DATE + " TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, " //<<<<<<<<<< LET SQLITE GET THE DATE TIME
                + DexameniEntry.COLUMN_a + " REAL NOT NULL, "
                + DexameniEntry.COLUMN_b + " REAL NOT NULL, "
                + DexameniEntry.COLUMN_c + " REAL NOT NULL, "
                + DexameniEntry.COLUMN_d + " REAL NOT NULL, "
                + DexameniEntry.COLUMN_e + " REAL NOT NULL, "
                + DexameniEntry.COLUMN_percent + " REAL NOT NULL);";

//        Execute the SQL Statement (Create the table)
        db.execSQL(CREATE_RESULTS_TABLE);
    }

    /**
     * This is called when the database needs to be upgraded.
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

        final String LOG_TAG = ("Upgrading the database from version " + oldVersion + " to " + newVersion);
        // on upgrade drop older tables
        db.execSQL("DROP TABLE IF EXISTS " + DexameniEntry.TABLE_NAME);

        //        Recreate tables
        onCreate(db);
    }

    public void insertData(String name,
                           Double X1aInput,
                           Double X1bInput,
                           Double X1cInput,
                           Double X1dInput,
                           Double X1eInput,
                           Double percent) {

        String timeStamp = "";
        try {
            // Gets the time & date the results are stored
            //timeStamp = new SimpleDateFormat("d M yy hh:mm").format(Calendar.getInstance().getTime());
            timeStamp = sdf.format(Calendar.getInstance().getTime());

        } catch (NumberFormatException e) {

        } catch (NullPointerException e) {
        }

        // Create a ContentValues object where column names are the keys,
        // and container attributes from the MainActivity are the values.

        ContentValues values = new ContentValues();
        values.put(DexameniEntry.COLUMN_CONTAINER_NAME, name);
        values.put(DexameniEntry.COLUMN_a, X1aInput);
        //values.put(DexameniEntry.COLUMN_DATE, timeStamp); //<<<<<<<<<< Use default
        values.put(DexameniEntry.COLUMN_b, X1bInput);
        values.put(DexameniEntry.COLUMN_c, X1cInput);
        values.put(DexameniEntry.COLUMN_d, X1dInput);
        values.put(DexameniEntry.COLUMN_e, X1eInput);
        values.put(DexameniEntry.COLUMN_percent, percent);
        mDB.insert(DexameniEntry.TABLE_NAME,null,values);
    }

    public Cursor getAllResults() {
        String formatted_date = "strftime('%d %m %Y'," +
                DexameniEntry.COLUMN_DATE + ") AS " + DexameniEntry.EXTRACT_COLUMN_DATELABEL;
        String unixtype_date = "julianday(" + DexameniEntry.COLUMN_DATE + ") * 86400 * 1000 AS " +DexameniEntry.EXTRACT_COLUMN_GRAPHDATELABEL;
        String[] columns = new String[]{"*",formatted_date,unixtype_date};
        return mDB.query(DexameniEntry.TABLE_NAME,columns,null,null,null,null,DexameniEntry.COLUMN_DATE + " ASC");
    }
}
  • Столбец даты был изменен, чтобы иметь специальное значение DEFAULT CURRENT_TIMESTAMP
  • Метод insertData был перемещен сюда из MainActivity и теперь требует, чтобы ему были переданы параметры (смотрите, как он используется в MainActivity)
  • Был добавлен getAllResults (см. GrapActivty, где используется getAllreults)
    • обратите внимание, что результирующий курсор имеет все столбцы из таблицы ПЛЮС два дополнительных (динамически генерируемых) столбца , которые будут иметь дату в формате ДД ММ ГГГГ (столбец даты будет иметь дату в формате ГГГГ-ДД -MM HH: MM: формат SS (пример выводится позже)), а другой - как метка времени Unix. (julianday(the_column) * 86400 * 1000 AS the_column_name)

MainActivity.java

MainActivity загружает некоторые данные (только при первом запуске) и имеет кнопку, при нажатии которой запускается GraphActivity.

public class MainActivity extends AppCompatActivity {

    Button mShowGraph;
    Context mContext;
    ResultsDbHelper mDBHlpr;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = this;
        mShowGraph = this.findViewById(R.id.show_graph);
        setupShowGraphButton();

        //Instantiate the DatabaseHelper
        mDBHlpr = new ResultsDbHelper(this);

        // Add some data if none exists
        if (DatabaseUtils.queryNumEntries(mDBHlpr.getWritableDatabase(),DexameniEntry.TABLE_NAME) < 1) {
            mDBHlpr.insertData("C1", 10.12, 11.12, 12.12, 13.12, 14.12, 25D);
            mDBHlpr.insertData("C2", 20.12, 21.12, 22.12, 23.12, 24.12, 35D);
            mDBHlpr.insertData("C3", 31.12, 32.12, 33.12, 34.12, 35.12, 25D);
        }
    }

    // Setup the Buttons on click listener to start the GraphActivity
    private void setupShowGraphButton() {
        mShowGraph.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent i  = new Intent(mContext,GraphActivity.class);
                i.putExtra(DexameniEntry.INTENTKEY_GRAPHVALUE,100);
                startActivity(i);
            }
        });
    }
}

GraphActivity

Несмотря на то, что при этом отображается график, он не загружает никаких данных, скорее даты извлекаются из базы данных и записываются в журнал.

public class GraphActivity extends AppCompatActivity {

    Context mContext;
    Button mDone;
    GraphView mBigGraphX1;
    ResultsDbHelper mDBHlpr;
    Cursor mResults;
    LineGraphSeries<DataPoint> mLGS;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_graph);
        mContext = this;
        mDone = this.findViewById(R.id.done);
        setupDoneButton();
        mDBHlpr = new ResultsDbHelper(this);
        mResults = mDBHlpr.getAllResults();
        mBigGraphX1 = this.findViewById(R.id.graphview);
        demoDatesFromDB();
        doTheGraphLineStuff();
    }

    private void setupDoneButton() {
        mDone.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
    }

    @Override
    protected void onDestroy() {
        mResults.close(); //<<<<<<<<<< Should always close cursor when done
        super.onDestroy();
    }

    private void demoDatesFromDB() {
        StringBuilder sb = new StringBuilder("Data From Table ").append(DexameniEntry.TABLE_NAME).append(" as per :-");
        while (mResults.moveToNext()) {
            String date_asperdb = mResults.getString(mResults.getColumnIndex(DexameniEntry.COLUMN_DATE));
            String date_formatted = mResults.getString(mResults.getColumnIndex(DexameniEntry.EXTRACT_COLUMN_DATELABEL));
            long unix_date = mResults.getLong(mResults.getColumnIndex(DexameniEntry.EXTRACT_COLUMN_GRAPHDATELABEL));
            sb.append("\n\tResults for row ");
            sb.append(String.valueOf(mResults.getPosition() + 1));
            sb.append(" Date as per DB is ").append(date_asperdb);
            sb.append(" Formatted Date is ").append(date_formatted);
            sb.append(" Unix Date is ").append(unix_date);
        }
        Log.d("DEMODATEINFO",sb.toString());
    }

    private void doTheGraphLineStuff() {

        long one_day = 1000 * 60 * 60 * 24;
        mResults = mDBHlpr.getAllResults();
        int rowcount = mResults.getCount();


        long[] extracted_dates = new long[rowcount];

        DataPoint[] dataPoints = new DataPoint[rowcount];
        while (mResults.moveToNext()) {

            /**
             * NOTE  as all 3 rows are added within milliseconds this adds on a day
             */
            extracted_dates[mResults.getPosition()] = mResults.getLong(
                    mResults.getColumnIndex(
                            DexameniEntry.EXTRACT_COLUMN_GRAPHDATELABEL
                    ))
                    + (one_day * ((long)mResults.getPosition() + 1L) //<<<< Frig the data show it is one day more than the previous

            );
            dataPoints[mResults.getPosition()] = new DataPoint(
                    extracted_dates[mResults.getPosition()],
                    mResults.getDouble(mResults.getColumnIndex(DexameniEntry.COLUMN_a))
            );

        }
        mLGS = new LineGraphSeries<>(dataPoints);
        mBigGraphX1.addSeries(mLGS);
        mBigGraphX1.getGridLabelRenderer().setLabelFormatter(new DateAsXAxisLabelFormatter(mContext));
        mBigGraphX1.getGridLabelRenderer().setNumHorizontalLabels(rowcount);
        mBigGraphX1.getViewport().setMinX(extracted_dates[0]);
        mBigGraphX1.getViewport().setMaxX(extracted_dates[rowcount - 1]);
        mBigGraphX1.getViewport().setXAxisBoundsManual(true);
        mBigGraphX1.getGridLabelRenderer().setHumanRounding(false);

    }

Результат

В журнал выводится следующее: -

2019-01-12 09:01:07.194 3073-3073/so54140390.so54140390graph D/DEMODATEINFO: Data From Table container_results as per :-
        Results for row 1 Date as per DB is 2019-01-11 21:02:06 Formatted Date is 11 01 2019
        Results for row 2 Date as per DB is 2019-01-11 21:02:06 Formatted Date is 11 01 2019
        Results for row 3 Date as per DB is 2019-01-11 21:02:06 Formatted Date is 11 01 2019

Так что это просто вопрос, возможно, изменения или добавления форматов, чтобы удовлетворить. - Библия для этого - SQL, понятный SQLite - функции даты и времени

График сверху: -

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...