Android数据库可供所有活动读取



>UPDATE:我需要重写onDestroy方法来关闭数据库帮助程序类对象。 现在工作正常。只需在创建SQLiteOpenHelper类对象的任何活动中添加它即可。

Database dbHelper; //in class
dbHelper = new Database(this, "pulling data",null,1); //in onCreate
@Override
protected void onDestroy()
{
super.onDestroy();
dbHelper.close();
}

我从一个片段创建和更新一个数据库,其中包含大约每 2 秒从通过蓝牙连接到我的 Android 应用程序的传感器传入的数据。

我在应用程序中转到不同的活动,这些活动应该能够从数据库中读取以在列表/文本视图中显示数据,但问题是创建数据库和更新数据库的上下文来自片段。 有没有办法使所有活动都可以从数据库中读取?

我创建了一个扩展SQLiteOpenHelper的类,您可以在其中访问函数来执行CRUD操作,但是一旦我进入另一个活动并查询数据库,游标不会拉出任何内容,尽管我插入并正在后台从片段更新数据库。

请注意,我对Android开发很陌生,并且已经查看了其他问题/解决方案,但没有任何适合我的方法。感谢任何教程或建议,谢谢!

下面是我的SQLiteOpenHelper类:

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class Database extends SQLiteOpenHelper
{
public Context DBcontext = null;
//DatabaseContract version
public static final int DATABASE_VERSION = 1;
public static final String DATABASE_NAME = "Sensors";

public static final String SENSOR_DATA_TABLE_NAME ="SensorData";
public static final String SENSOR_DATA_COLUMN_ID = "SensorDataID";
public static final String NODE_COLUMN_NAME = "Nodes";
public static final String TEMP_COLUMN_NAME = "TemperatureData";
public static final String MOTION_COLUMN_NAME = "MotionData";
public static final String GAS_COLUMN_NAME = "GasData";
public static final String LIGHT_COLUMN_NAME = "LightData";

//Constructor for the Database activity
public DatabaseContract( Context context , String name, SQLiteDatabase.CursorFactory factory, int version) {
super( context, name, factory, version);
}

@Override
public void onCreate(SQLiteDatabase db) {

db.execSQL("CREATE TABLE "+SENSOR_DATA_TABLE_NAME+" ("+SENSOR_DATA_COLUMN_ID+" INTEGER PRIMARY KEY, "+NODE_COLUMN_NAME+ " STRING, "+TEMP_COLUMN_NAME+" STRING,     "+MOTION_COLUMN_NAME+" STRING, "+GAS_COLUMN_NAME+" STRING, "+ LIGHT_COLUMN_NAME+" STRING)");

}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
db.execSQL("DROP TABLE IF EXISTS " + SENSOR_DATA_TABLE_NAME);
onCreate(db);
}

public boolean checkExist()
{
SQLiteDatabase db = getReadableDatabase();
String query = "SELECT * FROM "+ SENSOR_DATA_TABLE_NAME;
Cursor res = db.rawQuery(query, null);

if(res.getCount() > 0){
res.close();
return true;
}else {
res.close();
return false;
}

}

public void updateSensorData(String node_number, String temp_data, String motion_data, String light_data, String gas_data)
{
SQLiteDatabase db = getWritableDatabase();
String query = "SELECT * FROM " + SENSOR_DATA_TABLE_NAME + " WHERE " + NODE_COLUMN_NAME + " ='" + node_number + "'";
Cursor res = db.rawQuery(query, null);

if (res.getCount() == 0){
res.close();
ContentValues content = new ContentValues();
content.put(NODE_COLUMN_NAME, node_number);
content.put(TEMP_COLUMN_NAME, temp_data);
content.put(MOTION_COLUMN_NAME, motion_data);
content.put(GAS_COLUMN_NAME, gas_data);
content.put(LIGHT_COLUMN_NAME, light_data);
db.insert(SENSOR_DATA_TABLE_NAME, null, content);

}else{
/**try to get ID from cursor, not working so hardcoded 1 for now to test**/
//String ID = Long.toString(res.getLong(res.getColumnIndex(SENSOR_DATA_COLUMN_ID)));
ContentValues contentValues = new ContentValues();
contentValues.put(NODE_COLUMN_NAME, node_number);
contentValues.put(TEMP_COLUMN_NAME, temp_data);
contentValues.put(MOTION_COLUMN_NAME, motion_data);
contentValues.put(GAS_COLUMN_NAME, gas_data);
contentValues.put(LIGHT_COLUMN_NAME, light_data);
//hardcoded ID = 1 just for testing
db.update(SENSOR_DATA_TABLE_NAME, contentValues, SENSOR_DATA_COLUMN_ID + " = ? ", new String[] { "1" } );

}

}

}

下面是从上面与类交互以在数据库中插入/更新数据的片段。 我采用了谷歌蓝牙聊天应用程序并对其进行了修改,使其符合我的预期目的。此片段与处理程序中的数据库类交互以进行MESSAGE_READ。我解析发送给我的数据,然后将其作为参数传递给数据库函数 updateSensorData,在那里它负责插入然后更新数据。

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;

public class Bluetooth extends Fragment
{
private static final String TAG = "Bluetooth";
// Intent request codes
private static final int REQUEST_CONNECT_DEVICE_INSECURE = 1;
private static final int REQUEST_ENABLE_BT = 2;
// Layout Views
private Button scan_button;
private Button move;
private DatabaseContract dbHelper;
/**
* Name of the connected device
*/
private String mConnectedDeviceName = null;

/**
* Local Bluetooth adapter
*/
private BluetoothAdapter BAdapter = null;
/**
* Member object for the chat services
*/
private BluetoothChatService mChatService = null;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
// Get local Bluetooth adapter
BAdapter = BluetoothAdapter.getDefaultAdapter();

if (BAdapter == null)
{
FragmentActivity activity = getActivity();
new AlertDialog.Builder(activity)
.setTitle("Error: Not compatible")
.setMessage("Your phone does not support Bluetooth")
.setPositiveButton("Exit", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
System.exit(0);
}
})
.setIcon(android.R.drawable.ic_dialog_alert)
.show();
}
}

@Override
public void onStart()
{
super.onStart();
if (!BAdapter.isEnabled())
{
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
// Otherwise, setup the chat session
}
else if (mChatService == null)
{
setupChat();
}
}
@Override
public void onDestroy()
{
super.onDestroy();
if (mChatService != null)
{
mChatService.stop();
}
}

@Override
public void onResume()
{
super.onResume();
// Performing this check in onResume() covers the case in which BT was
// not enabled during onStart(), so we were paused to enable it...
// onResume() will be called when ACTION_REQUEST_ENABLE activity returns.
if (mChatService != null)
{
// Only if the state is STATE_NONE, do we know that we haven't started already
if (mChatService.getState() == BluetoothChatService.STATE_NONE)
{
// Start the Bluetooth chat services
mChatService.start();
}
}
scan_button.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
Intent serverIntent = new Intent(getActivity(), DeviceList.class);
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_INSECURE);
}
});
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState)
{
View v = inflater.inflate(R.layout.bluetooth, container, false);
Button move = (Button)v.findViewById(R.id.move);
move.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), Network.class);
startActivity(intent);
}
});
return v;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState)
{
scan_button = (Button) view.findViewById(R.id.scan_button);
move = (Button) view.findViewById(R.id.move);
}
/**
* Set up the UI and background operations for chat.
*/
private void setupChat()
{
scan_button.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
Intent serverIntent = new Intent(getActivity(), DeviceList.class);
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_INSECURE);
}
});

// Initialize the BluetoothChatService to perform bluetooth connections
mChatService = new BluetoothChatService(getActivity(), mHandler);

}

private final Handler mHandler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
FragmentActivity activity = getActivity();
switch (msg.what)
{
case Constants.MESSAGE_STATE_CHANGE:
switch (msg.arg1)
{
case BluetoothChatService.STATE_CONNECTED:
Toast.makeText(getActivity(), "Connected to "+mConnectedDeviceName+" setting up network. . .", Toast.LENGTH_SHORT).show();
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
move.setVisibility(View.VISIBLE);
scan_button.setVisibility(View.INVISIBLE);
}
}, 4000);
break;
case BluetoothChatService.STATE_CONNECTING:
Toast.makeText(getActivity(), "Connecting. . .", Toast.LENGTH_SHORT).show();
break;
case BluetoothChatService.STATE_LISTEN:
case BluetoothChatService.STATE_NONE:
scan_button.setVisibility(View.VISIBLE);
move.setVisibility(View.INVISIBLE);
}
break;
/******************************** where this fragment interacts with SQLiteOpenHelper class for database******************************/

case Constants.MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
String readMessage = new String(readBuf, 0, msg.arg1);
dbHelper = new DatabaseContract(getActivity(), "data transfer for sensors", null, 1);
int node = readMessage.indexOf("node");
int temp_number = readMessage.indexOf("t");
int motion_number = readMessage.indexOf("m");
int light_number = readMessage.indexOf("l");
int gas_number = readMessage.indexOf("g");
String node_number = readMessage.substring(node + 5, node + 6);
String temp_data = readMessage.substring(temp_number, motion_number);
String motion_data = readMessage.substring(motion_number, light_number);
String light_data = readMessage.substring(light_number, gas_number);
String gas_data = readMessage.substring(gas_number);
dbHelper.updateSensorData(node_number, temp_data, motion_data, light_data, gas_data);

break;
case Constants.MESSAGE_DEVICE_NAME:
// save the connected device's name
mConnectedDeviceName = msg.getData().getString(Constants.DEVICE_NAME);
break;
case Constants.MESSAGE_TOAST:
if (null != activity) {
Toast.makeText(activity, msg.getData().getString(Constants.TOAST),
Toast.LENGTH_SHORT).show();
}
break;
}
}
};
//automatically invoked when app starts up
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
switch (requestCode)
{
case REQUEST_CONNECT_DEVICE_INSECURE:
// When DeviceList returns with a device to connect
if (resultCode == Activity.RESULT_OK)
{
connectDevice(data, false);
}
break;
case REQUEST_ENABLE_BT:
// When the request to enable Bluetooth returns
if (resultCode == Activity.RESULT_OK)
{
// Bluetooth is now enabled, so set up a chat session
setupChat();
}
else
{
FragmentActivity activity = getActivity();
new AlertDialog.Builder(activity)
.setTitle("Error")
.setMessage("Bluetooth is disabled")
.setPositiveButton("ENABLE", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, 8);
onDestroy();
onResume();
}
})
.setIcon(android.R.drawable.ic_dialog_alert)
.show();
}
}
}

private void connectDevice(Intent data, boolean insecure)
{
// Get the device MAC address
String address = data.getExtras()
.getString(DeviceList.EXTRA_DEVICE_ADDRESS);
// Get the BluetoothDevice object
BluetoothDevice device = BAdapter.getRemoteDevice(address);
// Attempt to connect to the device
mChatService.connect(device, insecure);
}

}

下面是需要访问数据库中信息的不同类之一的示例。我使用 checkExist() 函数对其进行了测试,它返回 false,尽管在片段中我确实成功插入然后更新了传感器数据。这就是我的问题所在,不知道为什么它没有从数据库中提取任何内容

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ListView;
import android.widget.TextView;

/**Here is an example of one of the activities that needs to pull readings from the database to display**/
public class NodeData extends AppCompatActivity
{

private DatabaseContract dbHelper;
private TextView tempDisplay;
private TextView motionDisplay;
private TextView gasDisplay;
private TextView lightDisplay;
private ListView dataDisplay;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.nodedata);
String node_number = getIntent().getExtras().getString("node_number");
String label = "Node "+node_number+" Data";
TextView textViewToChange = (TextView) findViewById(R.id.node_data_label);
textViewToChange.setText(label);

dbHelper = new DatabaseContract(getApplicationContext(), "data transfer for sensors", null, 1);

boolean test = dbHelper.checkExist();
Toast.makeText(getApplicationContext(), "testing: "+test, Toast.LENGTH_SHORT).show();
}

}

在活动中扩展 LoaderManager.LoaderCallbacks 以从数据库加载数据。

有关更多信息,您可以阅读: https://developer.android.com/guide/components/loaders.html

看到这个: http://guides.codepath.com/android/local-databases-with-sqliteopenhelper

  1. 我建议您使用单例模式以避免泄漏,并每次重新分配数据库。
  2. 强烈建议使用 startTransaction 和 endTransaction,如上面的链接中所述。

如果它仍然不起作用,我还建议您按照@Bruno建议使用加载器。

不管你的问题,只是一个小的潜在错误修复 - 在函数updateSensorDataDatabase类中,你忘记关闭 else 流中的Cursor

最新更新