从Firebase数据库检索数据时遇到问题。请原谅我缺乏技术演讲,因为这不是我的强项。 我的应用程序是创建一个Vehicle列表,该列表发布到带有RecyclerView的页面上。通过“ NewVehicle.class”添加了新的载具,并在自动生成的节点下将其保存到Firebase。用户可以从“ VehicleList.class”中选择车辆,这会将车辆重定向到“ PasswordProtected.class”。用户需要输入密码才能查看与车辆有关的数据。车辆和“ PasswordProtected.class”都已链接,换句话说,代码知道在数据库中查看哪辆车辆。用户将被重定向到“ DataDisplay.class”,在这里他们可以从想要查看的图形中进行选择。我现在遇到的问题是从一辆车辆上检索特定的“ VehiclesData”并将其显示在图表中。我还添加了一张图像,显示我的数据库在Firebase中的样子。
NewVehicle.class
public class NewVehicle extends AppCompatActivity
{
//XML variables
private ImageView newVehicleImage;
private EditText vehicleMake, vehicleModel, vehicleReg, password, con_password, engineSize;
private ProgressDialog progress;
private Uri vehicleImage = null;
private StorageReference storageRef;
private DatabaseReference databaseRef;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_new_vehicle);
storageRef = FirebaseStorage.getInstance().getReference();
databaseRef = FirebaseDatabase.getInstance().getReference().child("Vehicles");
newVehicleImage = findViewById(R.id.new_vehicle_image);
vehicleMake = findViewById(R.id.new_vehicle_make);
vehicleModel = findViewById(R.id.new_vehicle_model);
vehicleReg = findViewById(R.id.new_vehicle_reg);
engineSize = findViewById(R.id.new_vehicle_engine);
Button vehicleAdd = findViewById(R.id.save_btn);
password = findViewById(R.id.password);
con_password = findViewById(R.id.con_password);
progress = new ProgressDialog(this);
newVehicleImage.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
CropImage.activity()
.setGuidelines(CropImageView.Guidelines.ON)
.setMinCropResultSize(512, 512)
.setAspectRatio(1, 1)
.start(NewVehicle.this);
}
});
//When user selects the 'Add' button
vehicleAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v)
{
StartPosting();
}
});
}//End onCreate()
private void StartPosting()
{
progress.setMessage("Posting to Vehicle list");
//The make, model and reg is saved to Strings
final String make = vehicleMake.getText().toString().trim();
final String model = vehicleModel.getText().toString().trim();
final String reg = vehicleReg.getText().toString().trim();
final String pass = password.getText().toString().trim();
final String engine = engineSize.getText().toString().trim();
final String con_pass = con_password.getText().toString().trim();
//If the password length is less than six
if(con_pass.length()<6)
{
con_password.setError(getText(R.string.mini_length));
con_password.requestFocus();
}
if(pass.length()<6)
{
password.setError(getText(R.string.mini_length));
password.requestFocus();
}
if(!TextUtils.isEmpty(make) && !TextUtils.isEmpty(model) && !TextUtils.isEmpty(reg) &&
!TextUtils.isEmpty(engine) && !TextUtils.isEmpty(pass) &&
!TextUtils.isEmpty(con_pass) && vehicleImage != null)
{
if (pass.equals(con_pass))
{
progress.show();
StorageReference filePath = storageRef.child("vehicle_images").child(vehicleImage.getLastPathSegment());
filePath.putFile(vehicleImage).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>()
{
@Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot)
{
Uri downloadUrl = taskSnapshot.getDownloadUrl();
DatabaseReference newpost = databaseRef.push();
newpost.child("Make").setValue(make);
newpost.child("Model").setValue(model);
newpost.child("Reg").setValue(reg);
newpost.child("Password").setValue(pass);
newpost.child("Engine").setValue(engine);
newpost.child("Confirmed_Password").setValue(con_pass);
newpost.child("Image").setValue(Objects.requireNonNull(downloadUrl).toString());
progress.dismiss();
startActivity(new Intent(NewVehicle.this, VehicleList.class));
}
});
}
if (!pass.equals(con_pass))
{
Toast.makeText(getApplicationContext(), "Passwords must match", Toast.LENGTH_LONG).show();
}
}
else
{
Toast.makeText(getApplicationContext(), "Fields can not be left empty", Toast.LENGTH_LONG).show();
}
}
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE)
{
CropImage.ActivityResult result = CropImage.getActivityResult(data);
if (resultCode == RESULT_OK)
{
vehicleImage = result.getUri();
newVehicleImage.setImageURI(vehicleImage);
}
//If the resultCode has an error
else if (resultCode == CropImage.CROP_IMAGE_ACTIVITY_RESULT_ERROR_CODE)
{
Toast.makeText(NewVehicle.this, "Application Error", Toast.LENGTH_LONG).show();
}
}
}
}//End NewVehicle()
VehicleList.class
public class VehicleList extends AppCompatActivity
{
//Declaring RecyclerView
private RecyclerView vehicleList;
//Declaring DatabaseReference to FireBase
private DatabaseReference databaseRef;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//Sets the layout according to the XML file
setContentView(R.layout.activity_vehicle_list);
//Linking to the FireBase Real-time Database
databaseRef = FirebaseDatabase.getInstance().getReference().child("Vehicles");
//XML variable
vehicleList = findViewById(R.id.vehicle_list_view);
vehicleList.setHasFixedSize(true);
vehicleList.setLayoutManager(new LinearLayoutManager(this));
FloatingActionButton addVehicleBtn = findViewById(R.id.add_vehicle_btn);
//If the user taps the addPostBtn
addVehicleBtn.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
//They will be redirected to the 'NewPost' class where they can add a new post
Intent intent = new Intent(VehicleList.this, NewVehicle.class);
startActivity(intent);
}//End onClick()
});//End addVehicleBtn()
}//End onCreate()
@Override
protected void onStart()
{
super.onStart();
//Recycler Adapter for Vehicles
FirebaseRecyclerAdapter<VehicleLog, VehicleViewHolder> firebaseRecyclerAdapter
= new FirebaseRecyclerAdapter<VehicleLog, VehicleViewHolder>(
VehicleLog.class,
R.layout.vehicle_itemlist,
VehicleViewHolder.class,
databaseRef
){
@Override
protected void populateViewHolder(VehicleViewHolder viewHolder, VehicleLog model, int position)
{
//Get the unique identifier for each record in the database
final String vehicle_key = getRef(position).getKey();
//Gathers the data
viewHolder.setMakeText(model.getMake());
viewHolder.setModelText(model.getModel());
viewHolder.setRegText(model.getReg());
viewHolder.setImage(getApplicationContext(), model.getImage());
//If a record is tapped on
viewHolder.mView.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
//Users redirected to the next screen
Intent intent = new Intent(VehicleList.this, PasswordProtected.class);
intent.putExtra("Vehicle_id", vehicle_key);
startActivity(intent);
}//End onClick()
});//End OnClickListener()
}//End populateViewHolder()
};//End FirebaseRecyclerAdapter()
vehicleList.setAdapter(firebaseRecyclerAdapter);
}//End onStart()
public static class VehicleViewHolder extends RecyclerView.ViewHolder
{
View mView;
public VehicleViewHolder(View itemView)
{
super(itemView);
mView = itemView;
}//End VehicleViewHolder()
//Sets the vehicles make on screen
public void setMakeText(String make)
{
TextView vehicle_make = mView.findViewById(R.id.vehicle_make);
vehicle_make.setText(make);
}//End setMakeText()
//Sets the vehicles model on screen
public void setModelText(String model)
{
TextView vehicle_model = mView.findViewById(R.id.vehicle_model);
vehicle_model.setText(model);
}//End setModelText()
//Sets the vehicles reg on screen
public void setRegText(String reg)
{
TextView vehicle_reg = mView.findViewById(R.id.vehicle_reg);
vehicle_reg.setText(reg);
}//End setRegText()
//Sets the vehicles image on screen using Glide
public void setImage(Context ctx, String Image)
{
ImageView vehicle_image = mView.findViewById(R.id.post_image);
Glide.with(ctx).load(Image).into(vehicle_image);
}//End setImage()
}//End VehicleViewHolder()
}
PasswordProtected.class
public class PasswordProtected extends AppCompatActivity
{
//Declaring XML variables
private ImageView imageView;
private TextView vehicle_make, vehicle_model;
private EditText ent_pass;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_password_protected);
vehicle_model = findViewById(R.id.model);
vehicle_make = findViewById(R.id.make);
imageView = findViewById(R.id.image);
Button cont = findViewById(R.id.cont);
ent_pass = findViewById(R.id.editTextPassword);
DatabaseReference databaseRef = FirebaseDatabase.getInstance().getReference().child("Vehicles");
//Gathers the unique key of each record in the database
String vehicle_key =
Objects.requireNonNull(getIntent().getExtras()).getString("Vehicle_id");
databaseRef.child(Objects.requireNonNull(vehicle_key))
.addValueEventListener(new ValueEventListener()
{
public void onDataChange(DataSnapshot dataSnapshot)
{
String model = (String) dataSnapshot.child("Model").getValue();
String make = (String) dataSnapshot.child("Make").getValue();
String image = (String) dataSnapshot.child("Image").getValue();
vehicle_model.setText(model);
vehicle_make.setText(make);
Glide.with(PasswordProtected.this).load(image).into(imageView);
}
@Override
public void onCancelled(DatabaseError databaseError)
{
Toast.makeText(PasswordProtected.this, "Database Error!", Toast.LENGTH_LONG).show();
}
});
cont.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v)
{
final String enter_pass = ent_pass.getText().toString().trim();
final DatabaseReference databaseRef = FirebaseDatabase.getInstance().getReference().child("Vehicles");
String vehicle_key = Objects.requireNonNull(getIntent().getExtras()).getString("Vehicle_id");
databaseRef.child(Objects.requireNonNull(vehicle_key)).addValueEventListener(new ValueEventListener() {
public void onDataChange(DataSnapshot dataSnapshot)
{
String pass = (String) dataSnapshot.child("Password").getValue();
Log.v("Firebase:", pass);
if(Objects.equals(pass, enter_pass))
{
Intent intent = new Intent(PasswordProtected.this, DataDisplay.class);
startActivity(intent);
}
else
{
Toast.makeText(getApplicationContext(),"PASSWORD DONT MATCH", Toast.LENGTH_LONG).show();
}//End else()
}//End onDataChange()
public void onCancelled(DatabaseError databaseError)
{
Toast.makeText(PasswordProtected.this, "Database Error!", Toast.LENGTH_LONG).show();
}
});
if(enter_pass.isEmpty())
{
ent_pass.setError(getText(R.string.pass_empt));
ent_pass.requestFocus();
}
if(enter_pass.length()<6)
{
ent_pass.setError(getText(R.string.mini_length));
ent_pass.requestFocus();
}
}
});
}
}
DisplayData.class
public class DataDisplay extends AppCompatActivity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_data_display);
//XML variables
Button mass_air = findViewById(R.id.mass_air);
Button engine_load = findViewById(R.id.engine_throttle);
Button engine_RPM = findViewById(R.id.RPM);
Button engine_temps = findViewById(R.id.engine_temps);
mass_air.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Intent intent = new Intent(DataDisplay.this, GraphEngineAirflow.class);
startActivity(intent);
}
});
engine_temps.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Intent intent = new Intent(DataDisplay.this, GraphTempSpecs.class);
startActivity(intent);
}
});
engine_load.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Intent intent = new Intent(DataDisplay.this, GraphEngineSpecs.class);
startActivity(intent);
}
});
engine_RPM.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(DataDisplay.this, GraphEngineRPM.class);
startActivity(intent);
}
});
}
}
GraphEngineAirflow.class
public class GraphEngineAirflow extends Activity implements
OnChartGestureListener, OnChartValueSelectedListener
{
private static final String TAG = "GraphEngineAirflow";
private LineChart chart;
//Array to hold Mass Airflow data from Firebase
ArrayList<Entry> engineAirflow = new ArrayList<>();
//Variables
LineDataSet set1;
LineData data;
protected void onCreate(Bundle savedInstanceState) {
/*This creates an Alert dialog on this screen, it also sets it so the user can cancel the message
for the Mass Airflow rate information*/
AlertDialog.Builder builder = new AlertDialog.Builder(GraphEngineAirflow.this);
builder.setCancelable(true);
//Setting the title and message from the string.xml
builder.setTitle(GraphEngineAirflow.this.getString(R.string.engine_airflow_title));
builder.setMessage(GraphEngineAirflow.this.getString(R.string.engine_airflow_def));
//When the user selects the Cancel button the page will redirect back to the VehicleSpec page
builder.setNegativeButton(GraphEngineAirflow.this.getString(R.string.cancel), new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int whichButton) {
dialog.cancel();
Intent intent = new Intent(GraphEngineAirflow.this, DataDisplay.class);
startActivity(intent);
}//End onClick()
});//End setNegativeButton()
builder.setPositiveButton(GraphEngineAirflow.this.getString(R.string.Ok), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which)
{
}//End onClick()
});//End setPositiveButton()
builder.show();
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
//Sets the layout according to the XML file
setContentView(R.layout.activity_graph_engine_airflow);
//XML reference
chart = findViewById(R.id.linechart);
//Listens for on chart taps
chart.setOnChartGestureListener(GraphEngineAirflow.this);
chart.setOnChartValueSelectedListener(GraphEngineAirflow.this);
//Enable touch gestures
chart.setTouchEnabled(true);
//Enable scaling and dragging
chart.setDragEnabled(true);
chart.setScaleEnabled(false);
chart.setDrawGridBackground(false);
//Enable pinch zoom
chart.setPinchZoom(true);
//Background color
chart.setBackgroundColor(Color.LTGRAY);
//Setting YAxis
YAxis left = chart.getAxisLeft();
left.setAxisMinimum(0f);
left.setAxisMaximum(50f);
left.setTextSize(13f);
left.enableGridDashedLine(10f, 10f, 0f);
YAxis left2 = chart.getAxisRight();
left2.setEnabled(false);
chart.getAxisRight().setEnabled(false);
//Value string
String[] vals = new String[] {"0s", "1s", "2s", "3s", "4s", "5s", "6s", "7s", "8s", "9s", "10s", "11s"};
//Legend object
Legend i = chart.getLegend();
//Customise legend
i.setTextSize(15f);
i.setForm(Legend.LegendForm.CIRCLE);
i.setTextColor(Color.BLACK);
//Setting XAis
XAxis x = chart.getXAxis();
x.setTextSize(13f);
x.setValueFormatter(new MyXAxisValueFormatter(vals));
x.setGranularity(1);
x.setPosition(XAxis.XAxisPosition.BOTTOM);
//Adding value to array as system will crash without
engineAirflow.add(new Entry(0, 0));
engineAirflow.add(new Entry(1, 0));
//Setting the line
set1 = new LineDataSet(engineAirflow, "Engine AirFlow ");
set1.setFillAlpha(110);
set1.setColor(Color.RED);
set1.setLineWidth(3f);
set1.setValueTextSize(10f);
set1.setValueTextColor(Color.BLACK);
data = new LineData(set1);
chart.setData(data);
//Calls the downloadDatt()
downloadData();
//Change the chart when a change occurs
chart.notifyDataSetChanged();
//XML button
Button checkD = findViewById(R.id.checkdata);
//If the user taps the button
checkD.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
/*This creates an Alert dialog on this screen, it also sets it so the user can cancel the message
for the Mass Airflow rate information retrieved from the database*/
AlertDialog.Builder builder2 = new AlertDialog.Builder(GraphEngineAirflow.this);
builder2.setCancelable(true);
//Setting the title and message from the string.xml
builder2.setTitle(GraphEngineAirflow.this.getString(R.string.IMPORTANT));
builder2.setMessage(GraphEngineAirflow.this.getString(R.string.airflow_info));
//When the user selects the Cancel button the page will redirect back to the VehicleSpec page
builder2.setNegativeButton(GraphEngineAirflow.this.getString(R.string.cancel), new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int whichButton)
{
dialog.cancel();
Intent intent = new Intent(GraphEngineAirflow.this, DataDisplay.class);
startActivity(intent); }//End onClick()
});//End setNegativeButton()
//If the user taps Ok
builder2.setPositiveButton(GraphEngineAirflow.this.getString(R.string.Ok), new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
}//End onClick()
});//End setPositiveButton()
//Show the Dialogs on screen
builder2.show();
}//End onClick()
});//End OnClickListener()
}//End onCreate
//Downloads Data from FireBase
private void downloadData()
{
//ArrayAdapter
final ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(this,R.layout.activity_graph_engine_airflow);
//Connecting into table "VehicleData" on the FireBase database
DatabaseReference database = FirebaseDatabase.getInstance().getReference("Vehicles");
//ChildEventListener allows child events to be listened for
database.addChildEventListener(new ChildEventListener()
{
public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey)
{
//Holds the DataSnapshot value of the database as type String
VehicleData vehicleData = dataSnapshot.getValue(VehicleData.class);
//Prints values to console to prove the download is working
System.out.println("getmassAirflowRate: " + Objects.requireNonNull(vehicleData).getMassAirflowRate());
System.out.println("prevChildKey: " + prevChildKey);
System.out.println("data.key" + dataSnapshot.getKey());
//Converting value to integer
setData(Integer.parseInt(dataSnapshot.getKey()), vehicleData);
//Will refresh app when the data changes in the database
arrayAdapter.notifyDataSetChanged();
}//End onChildAdded()
//Will run when data within the database is changed/edited
public void onChildChanged(DataSnapshot dataSnapshot, String s)
{
}//End onChildChanged()
//Will run when data within the database is removed
public void onChildRemoved(DataSnapshot dataSnapshot)
{
}//End onChildRemoved()
//Will run when data within the database is moved to different location
public void onChildMoved(DataSnapshot dataSnapshot, String s)
{
}//End onChildMoved()
//Will run when any sort of error occurs
public void onCancelled(DatabaseError databaseError)
{
}//End onCancelled()
});//End addChildEventListener()
}//End DownloadData()
//Function sets the data on the graph
private void setData(int key, VehicleData vehicleData)
{
//Prints to console first
System.out.println("Using key: " + key);
System.out.println("Setting Mass Intake Airflow Rate: " + vehicleData.getMassAirflowRate());
//Adds new entries to the arrayList and converts the string into a float
engineAirflow.add(new Entry(key + 2, Float.parseFloat(vehicleData.getMassAirflowRate())));
//Change the chart when changes occurs
set1.notifyDataSetChanged();
data.notifyDataChanged();
this.chart.notifyDataSetChanged();
//Redisplay chart
chart.invalidate();
}//End setData()
//Using the String to change the values of the XAis
public class MyXAxisValueFormatter implements IAxisValueFormatter
{
private String[] mVals;
private MyXAxisValueFormatter(String[] vals)
{
this.mVals = vals;
}//End MyXAxisValueFormatter()
@Override
public String getFormattedValue(float value, AxisBase axis)
{
return mVals[(int)value];
}//End getFormattedValue()
}//End MyXAxisValueFormatter()
@Override
//Sends log message if action is performed
public void onChartGestureStart(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture)
{
Log.i(TAG, "onChartGestureStart: X:" + me.getX() + "Y:" + me.getY());
}//End()
@Override
//Sends log message if action is performed
public void onChartGestureEnd(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture)
{
Log.i(TAG, "onChartGestureEnd: " + lastPerformedGesture);
}//End()
@Override
//Sends log message if action is performed
public void onChartLongPressed(MotionEvent me)
{
Log.i(TAG, "onChartLongPressed: ");
}//End()
@Override
//Sends log message if action is performed
public void onChartDoubleTapped(MotionEvent me)
{
Log.i(TAG, "onChartDoubleTapped: ");
}//End()
@Override
//Sends log message if action is performed
public void onChartSingleTapped(MotionEvent me)
{
Log.i(TAG, "onChartSingleTapped: ");
}//End()
@Override
//Sends log message if action is performed
public void onChartFling(MotionEvent me1, MotionEvent me2, float velocityX, float velocityY)
{
Log.i(TAG, "onChartFling: veloX: " + velocityX + "veloY" + velocityY);
}//End()
@Override
//Sends log message if action is performed
public void onChartScale(MotionEvent me, float scaleX, float scaleY)
{
Log.i(TAG, "onChartScale: ScaleX: " + scaleX + "ScaleY: " + scaleY);
}//End()
@Override
//Sends log message if action is performed
public void onChartTranslate(MotionEvent me, float dX, float dY)
{
Log.i(TAG, "onChartTranslate: dX" + dX + "dY" + dY);
}//End()
@Override
//Sends log message if action is performed
public void onValueSelected(Entry e, Highlight h) {
Log.i(TAG, "onValueSelected: " + e.toString());
Toast.makeText(this, "onValueSelected: " + e.toString(), Toast.LENGTH_SHORT).show();
}//End()
@Override
//Sends log message if action is performed
public void onNothingSelected() {
Log.i(TAG, "onNothingSelected: ");
}//End()
}//End GraphEngineAirflow()
答案 0 :(得分:0)
更改:
DatabaseReference database = FirebaseDatabase.getInstance().getReference("Vehicles").child(vehicle_key).child("Vehicle data");
到
DatabaseReference database = FirebaseDatabase.getInstance().getReference("Vehicles").child(vehicle_key).child("VehiclesData");
您的代码应该没问题。
答案 1 :(得分:0)
在第一种情况下,请使用像这样的参考(不在根目录中)
DatabaseReference database = FirebaseDatabase.getInstance().getReference().child("VehicleData").child(your id here mean 0 1 2 how you set that simillarly get as it (check if is not null first) );
您未引用0 1 2 3 id,这意味着在Vehicle Data的根目录下,您会获得完整的子代作为值,这不是VehicleData类的有效类。因此,您需要移至0 1 2 3,您将拥有完整的车辆数据类