问题描述
我正在处理一个项目,我需要连接到服务器以获取数据并在地图上从该数据中绘制标记,每当数据发生变化时,我需要使用新位置更新地图。
>我正在使用 Roomdatabase、Livedata 来观察更改和连接到服务器并将任何更新发送到存储库的服务。但最好的方法是什么?
提前致谢
编辑:
到目前为止,这是我的代码,我将尝试解释我设想它应该如何工作的方式
@Entity(tableName = "gateway_table")
public class Gateway {
private float temp;
private float wertX;
private float wertY;
private String title;
private boolean drawn;
private ArrayList<String> ObjectANames = new ArrayList<>();
@PrimaryKey(autoGenerate = true)
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public float getWertX() {
return wertX;
}
public float getWertY() {
return wertY;
}
public void setWertX(float wertX) {
this.wertX = wertX;
}
public void setWertY(float wertY) {
this.wertY = wertY;
}
public boolean isDrawn() {
return drawn;
}
public void setDrawn(boolean drawn) {
this.drawn = drawn;
}
public float getTemp() {
return temp;
}
public void setTemp(float temp) {
this.temp = temp;
}
public ArrayList<String> getobjectANames() {
return ObjectANames;
}
public Gateway (float wertX,float wertY,String title,boolean drawn,ArrayList<String> ObjectANames){
this.wertX = wertX;
this.wertY = wertY;
this.title = title;
this.drawn = drawn;
this.ObjectANames.addAll(ObjectANames);
}
}
和一个实体对象A
@Entity(tableName = "objectA_table")
public class ObjectA {
private String gateway;
private String name;
private boolean drawn;
@PrimaryKey(autoGenerate = true)
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public String getGateway() {
return gateway;
}
public void setGateway(String gateway) {
this.gateway = gateway;
}
public boolean isDrawn() {
return drawn;
}
public void setDrawn(boolean drawn) {
this.drawn = drawn;
}
public ObjectA(String gateway,String name,boolean drawn) {
this.gateway = gateway;
this.name = name;
this.drawn = drawn;
}
}
基本上每个网关在地图上都有一个位置(来自两个浮点数)、一个标题、一个布尔值和一个包含来自 ObjectA 的名称的数组列表。 ObjectA 有一个名称、一个包含它分配给的网关的字符串和一个布尔值。 所以一个网关可以有多个对象A,但每个对象A只有一个网关。
在两个 DAOS 中,我都有一个 findGateway/ObjectA 方法,在该方法中,我提供标题或名称,然后返回具有该名称的网关或 objectA。
这是视图模型:
public class viewmodel extends Androidviewmodel {
private Repository repository;
private LiveData<List<ObjectA>> allObjectA;
private LiveData<List<Gateway>> allGateways;
private mutablelivedata<SocketService.mybinder> binderviewmodel = new mutablelivedata<>();
public viewmodel(@NonNull Application application) {
super(application);
repository = new Repository(application);
allObjectA = repository.getAllObjectA();
allGateways = repository.getAllGateways();
}
public void insert(ObjectA objectA) throws InterruptedException {
repository.insert(objectA);
}
public void delete(ObjectA objectA) throws InterruptedException {
repository.delete(objectA);
}
public void deleteallObjectA() throws InterruptedException {
repository.deleteallObjectA();
}
public void update(ObjectA objectA) throws InterruptedException {
repository.update(objectA);
}
public ObjectA findobjectA(String ObjectAName) throws InterruptedException { return repository.findobjectA(ObjectAName);}
public LiveData<List<ObjectA>> getAllObjectA(){
return allObjectA;
}
public void insert(Gateway gateway) throws InterruptedException {
repository.insert(gateway);
}
public void delete(Gateway gateway) throws InterruptedException {
repository.delete(gateway);
}
public void deleteallGateways() throws InterruptedException {
repository.deleteallGateways();
}
public void update(Gateway gateway) throws InterruptedException {
repository.update(gateway);
}
public Gateway findGateway(String gatewayDesignation) throws InterruptedException { return repository.findGateway(gatewayDesignation);}
public LiveData<List<Gateway>> getAllGateways(){
return allGateways;
}
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name,IBinder iBinder) {
SocketService.mybinder binder = (SocketService.mybinder) iBinder;
binderviewmodel.postValue(binder);
}
@Override
public void onServicedisconnected(ComponentName name) {
binderviewmodel.postValue(null);
}
};
public ServiceConnection getServiceConnection(){
return serviceConnection;
}
public LiveData<SocketService.mybinder> getmybinder(){
return binderviewmodel;
}
}
这是我的服务:
public class SocketService extends Service {
//public static final String IP_ADDRESS = "172.17.100.77";
// public static final int SERVER_PORT = 5566;
public static final int CONNECTION_STATUS=0;
private Repository repository;
private final IBinder mybinder = new mybinder();
Thread thread;
PrintWriter output;
BufferedReader input;
Socket socket;
MediaPlayer player;
ArrayList<ObjectA> objectAArrayList;
@Override
public IBinder onBind(Intent intent) {
System.out.println("I am in Ibinder onBind method");
return mybinder;
}
public class mybinder extends Binder {
public SocketService getService() {
System.out.println("I am in Localbinder ");
return SocketService.this;
}
}
@Override
public void onCreate() {
super.onCreate();
repository = new Repository(getApplication());
player = MediaPlayer.create(getApplicationContext(),Settings.System.DEFAULT_ringtone_URI);
player.setLooping(true);
player.start();
}
private void sendMessageConnected() {
EventBus.getDefault().post(new IntentServiceResult(CONNECTION_STATUS,"Song is playing"));
}
private void sendMessageObjectGone(ObjectA objectA,ObjectA objectAOld) {
EventBus.getDefault().post(new IntentServiceResult(1,objectA,objectAOld));
}
@Override
public int onStartCommand(Intent intent,int flags,int startId) {
super.onStartCommand(intent,flags,startId);
objectAArrayList = new ArrayList<>();
objectAArrayList.add(new ObjectA("gate3","ObjectA1",false));
objectAArrayList.add(new ObjectA("gate2","ObjectA2","ObjectA3",false));
objectAArrayList.add(new ObjectA("gate4",false));
objectAArrayList.add(new ObjectA("gate3",false));
thread = new Thread(new connectSocket());
thread.start();
return START_STICKY;
}
class connectSocket implements Runnable {
@Override
public void run() {
while (player.isPlaying()) {
sendMessageConnected();
for (int i = 0; i< objectAArrayList.size(); i++){
try {
if(repository.findobjectA(objectAArrayList.get(i).getName()) == null){
repository.insert(objectAArrayList.get(i));
repository.update(objectAArrayList.get(i));
Gateway gateway = repository.findGateway(objectAArrayList.get(i).getGateway());
gateway.getobjectANames().add(objectAArrayList.get(i).getName());
if(repository.findGateway(gateway.getTitle()).isDrawn()){
gateway.setDrawn(true);
repository.update(gateway);
}else{
gateway.setDrawn(false);
repository.update(gateway);
}
Thread.sleep(2000);
}else {
ObjectA objectA = repository.findobjectA(objectAArrayList.get(i).getName());
ObjectA ObjectAold = repository.findobjectA(objectAArrayList.get(i).getName());
Gateway oldGateway = repository.findGateway(objectA.getGateway());
objectA.setGateway(objectAArrayList.get(i).getGateway());
repository.update(objectA);
Gateway newGateway = repository.findGateway(objectAArrayList.get(i).getGateway());
if(repository.findGateway(oldGateway.getTitle()).isDrawn() && repository.findGateway(objectAArrayList.get(i).getGateway()).isDrawn())
{
sendMessageObjectGone(objectA,ObjectAold);
}else
{
oldGateway.getobjectANames().remove(ObjectAold.getName());
newGateway.getobjectANames().add(objectA.getName());
repository.update(oldGateway);
repository.update(newGateway);
}
ObjectA objectA1 = repository.findobjectA(objectAArrayList.get(i).getName());
objectA1.setDrawn(false);
repository.update(objectA1);
Thread.sleep(2000);
}
} catch (InterruptedException e) {
e.printstacktrace();
}
}
}
}
}
@Override
public void onDestroy() {
super.onDestroy();
/*try {
socket.close();
} catch (IOException e) {
e.printstacktrace();
}*/
player.stop();
}
}
我还没有访问服务器的权限,所以我只是在运行一个模拟。我正在启动一个播放器,只要它在服务上就应该继续工作。 我在开始时初始化了对某些 ObjectA 的一些更新,并在每次更新存储库时检查它们。
最后但并非最不重要的地图活动,但首先我想解释它应该如何工作。每个网关可以有多个 ObjectA,但在地图上,每个网关旁边只应绘制其中的三个。所以在绘制标记之前,我总是检查三个位置中的一个是否空闲。
这是 GatewayMarker 类,它有一个布尔数组,用于查看哪些位置是空闲的
public class GatewayMarker extends MapMarker {
private Gateway gateway;
private boolean[] posTaken;
public GatewayMarker(Context context,Gateway gateway,boolean[] posTaken) {
super(context,gateway.getWertX(),gateway.getWertY(),gateway.getTitle());
this.gateway = gateway;
this.posTaken = posTaken;
setimageResource(R.drawable.gateway_foreground);
}
public float getXfirstPos() {
return gateway.getWertX() + 0.05f;
}
public float getYfirstPos() {
return gateway.getWertY() + 0.05f;
}
public float getXSecondPos() {
return gateway.getWertX() - 0.05f;
}
public float getYSecondPos() {
return gateway.getWertY() + 0.05f;
}
public float getXThirdPos() {
return gateway.getWertX();
}
public float getYThirdPos() {
return gateway.getWertY() - 0.05f;
}
public boolean[] getPosTaken() {
return posTaken;
}
}
这是 ObjectAMarker
public class ObjectAMarker extends MapMarker {
private int pos;
public ObjectAMarker(Context context,float x,float y,int pos) {
super(context,x,y,name);
this.pos = pos;
setimageResource(R.drawable.kuh2_foreground);
}
public int getPos() {
return pos;
}
}
和地图活动
public class MapMarkerActivity extends AppCompatActivity {
public static final int REQUEST_CONNECTION_STATUS = 0;
private MapViewExt mapView;
private TextView textView;
private EditText textx;
private EditText textY;
private Button button;
private Button buttonDelete;
private Boolean calledFirstTime = true;
private Boolean gatewayMoved = false;
private FrameLayout frameLayout;
private Observer<List<Gateway>> observerGateways;
private Observer<List<ObjectA>> observerObjectA;
private ArrayList<GatewayMarker> gatewayMarkers;
private ArrayList<ObjectAMarker> ObjectAMarkers;
private viewmodel viewmodel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_marker);
textx = findViewById(R.id.edit_text_x);
textY = findViewById(R.id.edit_text_y);
button = findViewById(R.id.button);
buttonDelete = findViewById(R.id.button_delete);
frameLayout = findViewById(R.id.frame_layout_show_barn);
textView = findViewById(R.id.text_view_connection_mapmarker);
viewmodel = new viewmodelProvider(this,viewmodelProvider.AndroidviewmodelFactory.getInstance(this.getApplication())).get(viewmodel.class);
buttonDelete.setEnabled(false);
button.setEnabled(false);
mapView = makeMapView();
if (mapView != null) {
mapView.setId(R.id.mapview_id);
mapView.setSaveEnabled(true);
frameLayout.addView(mapView);
}
}
private MapViewExt makeMapView() {
// hier Code to create the map
}
private GatewayMarker findGatewayMarker(String title) {
GatewayMarker gatewayMarker1 = null;
for (GatewayMarker gatewayMarker : gatewayMarkers) {
if (gatewayMarker.getName().equals(title)) {
gatewayMarker1 = gatewayMarker;
}
}
return gatewayMarker1;
}
private ObjectAMarker findobjectAMarker(String name) {
ObjectAMarker objectAMarker = null;
for (ObjectAMarker objectAMarker1 : ObjectAMarkers) {
if (objectAMarker1.getName().equals(name)) {
objectAMarker = objectAMarker1;
}
}
return objectAMarker;
}
private ObjectAMarker addNewObjectAMarker(MapViewExt mapView,int pos) {
ObjectAMarker objectAMarker = new ObjectAMarker(this,name,pos);
mapView.addMarker(objectAMarker);
return objectAMarker;
//MarkerApiKt.addMarker(mapView,marker,-0.5f,0f,0f);
}
private GatewayMarker addNewGatewayMarker(MapViewExt mapView,Gateway gateway) {
boolean[] posTaken = new boolean[3];
posTaken[0] = false;
posTaken[1] = false;
posTaken[2] = false;
GatewayMarker gatewayMarker = new GatewayMarker(this,gateway,posTaken);
mapView.addMarker(gatewayMarker);
return gatewayMarker;
}
@Override
protected void onResume() {
super.onResume();
EventBus.getDefault().register(this);
gatewayMarkers = new ArrayList<>();
ObjectAMarkers = new ArrayList<>();
observerGateways = new Observer<List<Gateway>>() {
@Override
public void onChanged(List<Gateway> gateways) {
for (Gateway gateway : gateways) {
if (!gateway.isDrawn()) {
if (calledFirstTime || gatewayMoved) {
gatewayMoved = false;
GatewayMarker gatewayMarker = addNewGatewayMarker(mapView,gateway);
gatewayMarkers.add(gatewayMarker);
gateway.setDrawn(true);
try {
viewmodel.update(gateway);
} catch (InterruptedException e) {
e.printstacktrace();
}
for (int i = 0; i < gateway.getobjectANames().size(); i++) {
ObjectAMarker objectAMarker;
if (!gatewayMarker.getPosTaken()[0]) {
objectAMarker = addNewObjectAMarker(mapView,gatewayMarker.getXfirstPos(),gatewayMarker.getYfirstPos(),gateway.getobjectANames().get(i),0);
ObjectAMarkers.add(objectAMarker);
try {
ObjectA objectA = viewmodel.findobjectA(gateway.getobjectANames().get(i));
objectA.setDrawn(true);
viewmodel.update(objectA);
} catch (InterruptedException e) {
e.printstacktrace();
}
gatewayMarker.getPosTaken()[0] = true;
} else if (!gatewayMarker.getPosTaken()[1]) {
objectAMarker = addNewObjectAMarker(mapView,gatewayMarker.getXSecondPos(),gatewayMarker.getYSecondPos(),1);
ObjectAMarkers.add(objectAMarker);
try {
ObjectA objectA = viewmodel.findobjectA(gateway.getobjectANames().get(i));
objectA.setDrawn(true);
viewmodel.update(objectA);
} catch (InterruptedException e) {
e.printstacktrace();
}
gatewayMarker.getPosTaken()[1] = true;
} else if (!gatewayMarker.getPosTaken()[2]) {
objectAMarker = addNewObjectAMarker(mapView,gatewayMarker.getXThirdPos(),gatewayMarker.getYThirdPos(),2);
ObjectAMarkers.add(objectAMarker);
try {
ObjectA objectA = viewmodel.findobjectA(gateway.getobjectANames().get(i));
objectA.setDrawn(true);
viewmodel.update(objectA);
} catch (InterruptedException e) {
e.printstacktrace();
}
gatewayMarker.getPosTaken()[2] = true;
return;
}
}
}
} else {
GatewayMarker gatewayMarker = findGatewayMarker(gateway.getTitle());
for (int i = 0; i < gateway.getobjectANames().size(); i++) {
try {
if (!viewmodel.findobjectA(gateway.getobjectANames().get(i)).isDrawn()) {
if (!gatewayMarker.getPosTaken()[0]) {
ObjectAMarker objectAMarker = findobjectAMarker(gateway.getobjectANames().get(i));
ObjectAMarkers.remove(objectAMarker);
ObjectAMarkers.add(addNewObjectAMarker(mapView,0));
try {
ObjectA objectA = viewmodel.findobjectA(gateway.getobjectANames().get(i));
objectA.setDrawn(true);
viewmodel.update(objectA);
} catch (InterruptedException e) {
e.printstacktrace();
}
gatewayMarker.getPosTaken()[0] = true;
} else if (!gatewayMarker.getPosTaken()[1]) {
ObjectAMarker objectAMarker = findobjectAMarker(gateway.getobjectANames().get(i));
ObjectAMarkers.remove(objectAMarker);
ObjectAMarkers.add(addNewObjectAMarker(mapView,1));
try {
ObjectA objectA = viewmodel.findobjectA(gateway.getobjectANames().get(i));
objectA.setDrawn(true);
viewmodel.update(objectA);
} catch (InterruptedException e) {
e.printstacktrace();
}
gatewayMarker.getPosTaken()[1] = true;
} else if (!gatewayMarker.getPosTaken()[2]) {
ObjectAMarker objectAMarker = findobjectAMarker(gateway.getobjectANames().get(i));
ObjectAMarkers.remove(objectAMarker);
ObjectAMarkers.add(addNewObjectAMarker(mapView,2));
try {
ObjectA objectA = viewmodel.findobjectA(gateway.getobjectANames().get(i));
objectA.setDrawn(true);
viewmodel.update(objectA);
} catch (InterruptedException e) {
e.printstacktrace();
}
gatewayMarker.getPosTaken()[2] = true;
} else {
return;
}
}
} catch (InterruptedException e) {
e.printstacktrace();
}
}
}
}
calledFirstTime = false;
}
};
observerObjectA = new Observer<List<ObjectA>>() {
@Override
public void onChanged(List<ObjectA> objectAS) {
}
};
viewmodel.getAllObjectA().observe(this,observerObjectA);
viewmodel.getAllGateways().observe(this,observerGateways);
}
@Override
protected void onPause() {
super.onPause();
List<ObjectA> allKühe = viewmodel.getAllObjectA().getValue();
List<Gateway> allGateways = viewmodel.getAllGateways().getValue();
for (ObjectA objectA : allKühe) {
objectA.setDrawn(false);
try {
viewmodel.update(objectA);
} catch (InterruptedException e) {
e.printstacktrace();
}
}
for (Gateway gateway : allGateways) {
gateway.setDrawn(false);
try {
viewmodel.update(gateway);
} catch (InterruptedException e) {
e.printstacktrace();
}
}
viewmodel.getAllGateways().removeObserver(observerGateways);
viewmodel.getAllObjectA().removeObserver(observerObjectA);
calledFirstTime = true;
for (int i = 0; i < ObjectAMarkers.size(); i++) {
MarkerApiKt.removeMarker(mapView,ObjectAMarkers.get(i));
}
ObjectAMarkers.clear();
for (int i = 0; i < gatewayMarkers.size(); i++) {
MarkerApiKt.removeMarker(mapView,gatewayMarkers.get(i));
}
gatewayMarkers.clear();
EventBus.getDefault().unregister(this);
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void getconnectionstatus(IntentServiceResult intentServiceResult) throws InterruptedException {
if (intentServiceResult.getResult() == REQUEST_CONNECTION_STATUS) {
textView.setText(intentServiceResult.getResultvalue());
}
if (intentServiceResult.getResult() == 1) {
ObjectA objectA = intentServiceResult.getResultObjectA();
ObjectA objectAOld = intentServiceResult.getResultObjectAOld();
Gateway gateway = viewmodel.findGateway(objectA.getGateway());
Gateway gatewayOld = viewmodel.findGateway(objectAOld.getGateway());
gatewayOld.getobjectANames().remove(objectAOld.getName());
gateway.getobjectANames().add(objectA.getName());
viewmodel.update(gatewayOld);
viewmodel.update(gateway);
ObjectAMarker objectAMarker = findobjectAMarker(objectAOld.getName());
GatewayMarker gatewayMarker = findGatewayMarker(gatewayOld.getTitle());
gatewayMarker.getPosTaken()[objectAMarker.getPos()] = false;
MarkerApiKt.removeMarker(mapView,objectAMarker);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
基本上问题是什么,当我打开地图Activity时它正常工作,但是假设我在mapActivity之上打开另一个Activity并且数据库中发生了变化,当我回到mapActivity时我发现了两个实例相同的标记。我通过数据库检查器注意到,我最终在 Gateaway 对象的 ArrayList 中得到了两个相同的字符串,这是不应该发生的。
另一个问题是,现在该服务设置为进行更改并休眠 2 秒,这可能不会保持这种状态,但是当我不让它休眠时,即使我在 Map Activity 中我确实有不一致之处。
编辑 2: 数据库:
@androidx.room.Database(entities = {ObjectA.class,Gateway.class},version = 26)
@TypeConverters({Converters.class})
public abstract class Database extends RoomDatabase {
private static volatile Database instance;
public abstract ObjectADAO cowDAO();
public abstract GatewayDAO gatewayDAO();
public static synchronized Database getInstance(Context context){
if (instance == null){
instance = Room.databaseBuilder(context.getApplicationContext(),Database.class,"database")
.fallbackToDestructiveMigration()
.build();
}
return instance;
}
}
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)