Ich kenne mich mit dem MediaStore nicht aus, aber es wäre hilfreicher (auch für andere), wenn du die genaue Exception dazuschreibst.
block_
Ich kenne mich mit dem MediaStore nicht aus, aber es wäre hilfreicher (auch für andere), wenn du die genaue Exception dazuschreibst.
block_
Es wurde kein Framework genutzt. Der Server, und der Client auch, wurde mit Java(Android) selbst implementiert (Plain Sockets).
Also die ganze App sieht bisher so aus:
In der App ist sowohl der Client-Anteil, als auch der Server-Anteil, damit die App unabhängig von externen Server ist (und man in jedem Netzwerk, in das man reinkommt, die App nutzen kann). Kommuniziert wird nur über WLAN, nicht übers Internet. Befinden sich mehrere Geräte im WLAN, kann eines davon einen Server starten mit dem sich die anderen verbinden und Daten austauschen können.
block_
Ein Paket mit den Klassen hab ich mir auch schon überlegt, allerdings bin ich mir nich sicher ob das so sinnvoll ist, da es schon jetzt eine Menge Befehle sind. Wenn man das laden dann noch mit Reflection lösen könnte, würde ich mir das nochmal überlegen, aber wie ich das gesehen hab geht das nicht so wirklich.
Müsste man mal ausporbieren, welche der beiden Methoden praktikabler ist.
block_
Okay, jetzt hab ichs verstanden
Allerdings würde ich den Context auch nicht statisch halten. Was passiert dann wenn die Activity mit dem Context vom System destroyed wird? Dann gibts doch auch Probleme und um das zu umgehen musst trotzdem in jeder Activity deine init() Methode ausführen.
block_
Also, ich habe eine Client/Server Anwendung geschrieben, die Daten und Befehle (einfache Strings) hin und her schickt. Die Verarbeitung übernimmt dabei ein eigenes Protokoll. Bislang sieht das so aus, das ich Konstanten habe, die die Befehle definieren und eine Methode mit sehr vielen If-Bedingungen, welche die weitere Verarbeitung übernimmt (je nachdem welcher Befehl gesendet wurde).
Dafür hab ich ein Interface,..
public interface Protocol
{
public static final String COMMAND_1 = "befehl1";
//[...]
public void process(String input);
}
... welches von zwei Klassen implementiert wird (jeweils ein ServerProtocol und ein ClientProtocol).
public class ServerProtocol implements Protocol
{
public void procss(String input)
{
if(input.equals(Protocol.COMMAND_1)
{ // tu was
}
// [... und viele weitere]
}
}
Das ist jedoch sehr Erweiterungs- und Wartungsunfreundlich wie ich finde. Wie könnte man das anders lösen?
Mein bisherigen Idee ist folgende:
Ich habe eine abstrakte Klasse für einen Befehl:
public abstract class Command
{
private String name;
public Command(String name)
{
this.name = name;
}
public abstract void execute();
public String getCommandName()
{
return name;
}
}
Alles anzeigen
In dem ServerProtocol gibt es nun eine Map, in der alle möglichen Befehle für die Server-Seite eingefügt werden.
private void init()
{
Map<String, Command> temp = new HashMap<String, Command>();
temp.put(COMMAND_1, new Command(COMMAND_1)
{
@Override
public void execute()
{
client.tuWas();
}
});
//[...]
commands = Collections.unmodifiableMap(temp);
}
Alles anzeigen
Aufgerufen wird das dann durch die process(String input) Methode.
Das ist schon besser als vorher, jedoch auch nicht ganz optimal, da man auch hier wieder suchen muss, wenn man einen Befehl ändern will. Hab da gedacht, man könnte eventuell etwas mit Reflection machen, aber das funktioniert auch nicht, da ich das nicht automatisieren kann, da die Verarbeitung eines Behfels ja immer unterschiedlich ist.
Also nochmal die Frage, gibt es eine bessere Möglichkeit?
block_
antifish
Zwei Klassen für eine Hilfsmethode halte ich persönlich etwas zu viel.
Statt der zweiten non-static Klasse kann man doch genauso gut direkt die statische Methode aufrufen. (Warum ist die Tools-Klasse abstract?)
public final class Tools
{
// verhindern das eine Instanz der Hilfsklasse erzeugt werden kann
private Tools(){}
private static vibrate(Context context, int length)
{
((Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE)).vibrate(length);
}
}
Alles anzeigen
Und Aufruf in der Activity:
So mach ich das immer und es funktioniert einwandfrei.
block_
Was spricht denn dagegen, die Methode einfach static zu machen?
So wie Lucas de Vil schon angedeutet hat (nur das der Context noch mitgegeben wird)
public static void vibrate(Context context, int length)
{
((Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE)).vibrate(length);
}
Diese Methode soll ja nicht den Zustand eines Objektes verändert, daher ist es in deiner Utility-Klasse ganz gut aufgehoben.
block_
Um die Dauer von etwas zu berechnen, würde ich nicht ein Date-Objekt nehmen. Das ist, wie du schon gesagt hast sehr ungenau. Nimm stattdessen
Die Differenz von beiden ergibt ein mehr oder weniger genaues Ergebnis (besser als Date )
Grundsätzlich lässt sich mit Java auch sehr perfomant arbeiten, solange man es richtig macht. Vorher würde ich prüfen ob du auch wirklich alles rausgeholt hast, was irgendwie möglich ist. Wenn du dann immer noch nativen Code einbinden möchtest, solltest du dir das Android NDK mal anschauen. Gibt auch eine Menge Tutorials dazu im Netzt.
block_
das wurde nicht nur angeschnitten das ist schon relativ verbreitet, aber leider wie mein vorredner erkannt hat, sehr instabil.
Meinst du jetzt JavaFX in Kombination mit Android oder JavaFX im Allgemeinen?
Das JavaFX weit verbreitet ist, ist mir bewusst, wird ja schließlich ab Java SE 7 mit ausgeliefert. Ich meinte die Unterstützung für Android wurde auf der JavaOne angeschnitte. Falls ich mich irre, lass ich mich gerne belehren Würde mich freuen genaueres dazu zu lesen, falls es so sein sollte.
block_
Also laut Logcat wird eine NPE geworfen und zwar in der onCreateView der Klasse Fragment_Map (Zeile 39). Jedoch passt das nicht zu dem von dir angegebenen Code. Sind die Klassen gekürzt(umbenannt) worden?
block_
Klar ist das möglich
Einfach zwischen den beiden Handys bzw. zwischen Handy -> Server <- Handy eine Socketkommunikation aufbauen. Um nicht das Rad nicht neu zu erfinden (so eine Socketkommunikation kann Spaß machen, aber auch einen echt frustrieren..), kannste dir mal Netty angucken. Das Regelt für dich Dinge wie Verbindungsabbrüche etc., sodass du das nicht alles zu Fuß machen musst.
Nun fordert PhoneA die Ip von PhoneB vom Server an und sendet dann an diese Ip das Datenpaket.
Das sollte gehen, jedoch nur wenn der Server sich auch in deinen eigenen Netz befindet. Wenn du das ganze auch über Internet haben willst, wirste spätestens hier Probleme mit der Firewall bekommen. In dem Fall würd ich alles über den Server laufen lassen.
block_
Ich hab mir mal JavaFX für ein paar Minuten nur angeguckt, sieht recht interessant aus, hab aber zu wenig Zeit um weiter zu machen.
Aber ich glaube nicht das JavaFX schon auf Android läuft. Soweit ich das gelesen hab, wurde das erst auf der letzten JavaOne angeschnitten, aber ob es demnächst kommt, ist eine andere Frage. Hab dazu jedenfalls nicht mehr viel gefunden.
block_
Wie Titus sagte.
Außer
Bevor du das mit deiner App versuchst sei dir gesagt es geht nicht.
im DDMS gibts im Panel "Devices" einen "STOP" Button, der die ausgewählte App einfach killt.
block_
Was für eine Fehlermeldung wird denn ausgegeben? Wie sieht deine Circle Klasse aus?
block_
Hast du ein Codebeispiel wie du den Text einliest/verschickst? (Sollte es nicht \n und \r sein? )
block_
Mit "==" prüfst du die beiden Referenzen der Strings und diese sind nunmal nicht gleich, daher immer false. Den Wert prüft man mit der equals()-Methode.
block_
Beim Testen von meinem Vorschlag hat alles soweit funktioniert und es wurde keine Exception geworfen. Habs jetzt mit dem Emulator nochmal getestet und den Fehler beseitig.
Client:
public class Client extends Activity {
private static TextView serverdaten;
static final Handler myHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
serverdaten.setText("Antwort vom Server: " + msg.obj);
}
};
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_client);
serverdaten = (TextView) findViewById(R.id.serverdaten);
Verbindung verbindung = new Verbindung(myHandler);
verbindung.start();
}
}
Alles anzeigen
Verbindung:
public class Verbindung implements Runnable {
private boolean running;
private Socket socket;
private BufferedReader input;
private Handler myHandler;
public Verbindung(Handler handler) {
myHandler = handler;
}
public void run() {
try {
socket = new Socket("192.168.0.101", 4444);
input = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
while (running) {
try {
Message msg = myHandler.obtainMessage();
msg.obj = input.readLine();
myHandler.sendMessage(msg);
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
public void start() {
new Thread(this).start();
running = true;
}
public void stop() {
running = false;
close();
}
private void close() {
if (input != null) {
try {
input.close();
} catch (IOException e) {
// fehlerbehandlung
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
// fehlerbehandlung
}
}
}
}
Alles anzeigen
Server:
public class TCPServer
{
static ServerSocket server;
static Socket client;
static BufferedWriter output;
static int n;
public static void main(String[] args)throws IOException
{
server = new ServerSocket(4444);
System.out.println("Server gestartet!");
client = server.accept();
output = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
final int[] array = { 1, 2, 3, 4, 5};
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask()
{
private int next = 0;
@Override
public void run()
{
n = (array[next % array.length]);
next++;
try {
String x = String.valueOf(n);
output.write(x);
System.out.println(x);
output.newLine();
output.flush();
} catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}, 0, 2000);
}
}
Alles anzeigen
block_
Da haben sich eine paar Fehler mit eingeschlichen, da ich das alles nur im Notepad geschrieben hab
Den Konstruktor nochmal:
public Verbindung() throws UnknownHostException, IOException {
socket = new Socket("192.168.2.3", 4444);
input = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
}
und in deine onCreate schreibste folgendes:
Verbindung verbindung;
try {
verbindung = new Verbindung();
verbindung.start();
} catch (UnknownHostException e) {
// fehlerbehandlung
} catch (IOException e) {
// fehlerbehandlung
}
Alles anzeigen
Hoffe das klappt jetzt so
block_
Also der Server sieht schon so okay aus.
Client:
class Verbindung implements Runnable
{
private running;
private Socket server;
private BufferedReader input;
public Verbindung()
{
server = new Socket("192.168.2.3", 4444);
input = new BufferedReader(new InputStreamReader(server.getInputStream()));
}
public void run()
{
while(running)
{
try
{
s = input.readLine();
Message msg = myHandler.obtainMessage();
msg.obj = s;
myHandler.sendMessage(msg);
}
catch (IOException e)
{
NachrichtText.setText(e.toString());
}
}
}
public void start()
{
new Thread(this).start();
running = true;
}
public void stop()
{
running = false;
close();
}
private close()
{
if(input != null)
{
try
{
input.close();
}
catch (IOException e)
{
// fehlerbehandlung
}
}
if(socket != null)
{
try
{
socket.close();
}
catch (IOException e)
{
// fehlerbehandlung
}
}
}
}
Alles anzeigen
Jetzt kannst du eine Instanz von Verbindung erstellen und durch die Methode start() einfach starten lassen.
Nun sollte immer die aktualisierte Zahl vom Server empfangen werden, solange der Thread läuft. Das Senden an den Server kannste normal um UI-Thread weitermachen, wie du es vorher hattest. Durch stop() sollte, die Verbindung dann geschlossen werden. Allerdings wird durch die Blockierung von der readline()-Methode das Schließen erst ausgeführt, nachdem eine weitere Nachricht empfangen wurde und somit die Schleife beendet werden konnte. Es gibt noch eine andere Methoden einen Thread zu beenden und zwar mit Interrupts, jedoch konnt ich das noch nicht testen, weil mein Eclipse streikt.
Zu den Tipps nochmal:
Die Namenskonventionen besagen, dass Variablennamen am Anfang klein geschrieben werden sollen. Zum Beispiel "NachrichtText" -> "nachrichtText".
Für den Leak: static final Handler myHandler {...}
Und zu der Klasse Verbindung: Verschiebe diese besser ans Ende der Datei, dadurch kann man den Code besser lesen, da die Klasse ansonsten logischen Gedanken unterbricht und man diese gegebenenfalls auch suchen muss (in deinem Fall nicht besonders schwer zu finden, aber wenn das Projekt größer werden könnte, oder mehrere Instanzen von Verbindung an unterschiedlichen Stellen benutzt werden).
Falls weitere Probleme auftauchen, sag bescheid
block_
Mit zwei Geräten läuft es ebenfalls nicht? Wo genau liegt das Problem? Wird keine Verbindung aufgebaut? Wie sieht dein Client/Server aus?
block_