I am writing a simple server client code to exchange messages, but my app terminates when I try running client.Following is my code for client:
public class Client extends AppCompatActivity {
public void SMessage() throws IOException {
EditText ip = (EditText) findViewById(R.id.ip);
String ipadd, edttxt, output;
PrintStream ps = null;
Intent i;
Scanner sc = null;
ipadd = ip.getText().toString();
Socket s = null;
s = new Socket(ipadd,1234);
i = new Intent(getApplicationContext(), new_activity.class);
startActivity(i);
ScrollView Rl = (ScrollView) findViewById(R.id.scrollView);
sc = new Scanner(s.getInputStream());
EditText et = (EditText) findViewById(R.id.message_txt);
edttxt = et.getText().toString();
ps = new PrintStream(s.getOutputStream());
ps.println(edttxt);
TextView tv1 = new TextView(this);
tv1.setText(edttxt);
tv1.setLayoutParams(new ActionBar.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
tv1.setBackground(getDrawable(R.drawable.ic_action_msg));
}
tv1.setGravity(View.FOCUS_LEFT);
Rl.addView(tv1);
output = sc.nextLine();
if (output.equals("END")) {
s.close();
return;
}
TextView tv2 = new TextView(this);
tv2.setText(output);
tv2.setLayoutParams(new ActionBar.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
tv2.setBackground(getDrawable(R.drawable.ic_action_msg));
}
tv2.setGravity(View.FOCUS_RIGHT);
Rl.addView(tv2);
}
}
Log when app terminates:
E/AndroidRuntime: FATAL EXCEPTION: Thread-4
Process: com.example.devanshi.testapp, PID: 2325
java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.Window$Callback android.view.Window.getCallback()' on a null object reference
at android.support.v7.app.AppCompatDelegateImplBase.<init>(AppCompatDelegateImplBase.java:120)
at android.support.v7.app.AppCompatDelegateImplV9.<init>(AppCompatDelegateImplV9.java:151)
at android.support.v7.app.AppCompatDelegateImplV11.<init>(AppCompatDelegateImplV11.java:31)
at android.support.v7.app.AppCompatDelegateImplV14.<init>(AppCompatDelegateImplV14.java:55)
at android.support.v7.app.AppCompatDelegateImplV23.<init>(AppCompatDelegateImplV23.java:33)
at android.support.v7.app.AppCompatDelegateImplN.<init>(AppCompatDelegateImplN.java:33)
at android.support.v7.app.AppCompatDelegate.create(AppCompatDelegate.java:201)
at android.support.v7.app.AppCompatDelegate.create(AppCompatDelegate.java:185)
at android.support.v7.app.AppCompatActivity.getDelegate(AppCompatActivity.java:519)
at android.support.v7.app.AppCompatActivity.findViewById(AppCompatActivity.java:190)
at com.example.devanshi.testapp.Client.SMessage(Client.java:27)
at com.example.devanshi.testapp.MainActivity$2.run(MainActivity.java:60)
Main Activity when i call client is as follows:
public void client(View view) {
final Client c = new Client();
Thread t=new Thread(){
public void run(){
try {
c.SMessage();
} catch (IOException e) {
e.printStackTrace();
}
}
};
t.start();
}
I would like to know where did I go wrong and how can I solve it.
Thanks in advance for your response. :)
First, you should set your layout to the activity so you can bind views. Like this
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
Second, i am realy confused what are you trying to do in SMessage() method. I think you should do some research about application logic, starting activity and activity lifecycle
I suggest you to use a Service for communication between client and server. It will run in background but you can communicate with server via it. If you start a new activity it will stop your current activity and put it in backstack. Your current activity will not be accessible from the new activity. And you can't run two activity at the same time. So use a service to handle client-server communication and change your client view according to the response received from server via service. It will be a good practice
Related
Hello software developers.
I'm developing an android application that consumes a REST service so I'm using the Http Client Library (http://loopj.com/android-async-http/), but I want to populate a spinner control so I first call to the method fillSpinnerTiposSiniestros and populate an ArrayList to later use that ArrayList to fill the adapter of the spinner, but I do not know why the adapter is first established and then called the REST client, so the spinner remains empty.
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_edit_sinister);
editTextValorClave = (EditText) findViewById(R.id.editTextSinisterValorClave);
editTextValorCurp = (EditText) findViewById(R.id.editTextSinisterValorCurp);
editTextValorDependencia = (EditText) findViewById(R.id.editTextSinisterValorDependencia);
editTextValorRFC = (EditText) findViewById(R.id.editTextSinisterValorRFC);
editTextValorStatus = (EditText) findViewById(R.id.editTextSinisterValorStatus);
//editTextValorTipoSiniestro = (EditText) findViewById(R.id.editTextSinisterValorTipoSiniestro);
spinnerTipoSiniestro = (Spinner) findViewById(R.id.spinnerTipoSiniestro);
editTextValorNumAmbulancia = (EditText) findViewById(R.id.editTextSinisterNumAmbulancia);
editTextValorNombreSieniestro = (EditText) findViewById(R.id.editTextSinisterNombreSieniestro);
editTextValorLocalizacion = (EditText) findViewById(R.id.editTextSinisterValorLocalizacion);
textViewMuestraEncabezado = (TextView) findViewById(R.id.textViewTitulo);
botonAccionAddEdit = (Button) findViewById(R.id.buttonSinisterAddEdit);
botonAccionAddEdit.setOnClickListener(eventoAccionBotonAddEdit);
Bundle miBlunde = getIntent().getExtras();
opcion = miBlunde.getInt("Opcion");
claveGlobal = miBlunde.getInt("Clave");
CargarDatosSpinner;
}
private void rellenarSpinnerTiposSiniestros(){
List<Header> encabezados = new ArrayList<Header>();
encabezados.add(new BasicHeader("Accept", "application/json"));
SiniestroRESTClient.get(AddEditSinisterActivity.this, "api/TipoSiniestro", encabezados.toArray(new Header[encabezados.size()]), null,
new JsonHttpResponseHandler()
{
#Override
public void onSuccess(int statusCode, Header[] headers, JSONArray response)
{
arrayTipoSiniestro = new ArrayList<TipoSiniestro>();
tipoSiniestroAdapter = new SpinnerTipoSiniestroAdapter(getApplicationContext(), android.R.layout.simple_spinner_dropdown_item, (TipoSiniestro[]) arrayTipoSiniestro.toArray());
for(int i = 0; i < response.length(); i++)
{
try
{
tipoSiniestroAdapter.add(new TipoSiniestro(response.getJSONObject(i)));
}
catch(JSONException e)
{
e.printStackTrace();
}
}
tipoSiniestroAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinnerTipoSiniestro.setAdapter(tipoSiniestroAdapter);
}
});
}
I tried with this solution asynchttpclient gives response after activity, but I have an exception like:
FATAL EXCEPTION: AsyncTask #1
Process: com.maestria.lostperson, PID: 13433
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:309)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.IllegalArgumentException: Synchronous ResponseHandler used in AsyncHttpClient. You should create your response handler in a looper thread or use SyncHttpClient instead.
at com.loopj.android.http.AsyncHttpClient.sendRequest(AsyncHttpClient.java:1493)
at com.loopj.android.http.AsyncHttpClient.get(AsyncHttpClient.java:1095)
at com.maestria.lostperson.clients.SiniestroRESTClient.get(SiniestroRESTClient.java:24)
at com.maestria.lostperson.AddEditSinisterActivity$2.doInBackground(AddEditSinisterActivity.java:159)
at android.os.AsyncTask$2.call(AsyncTask.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
You are attempting to touch UI components from background thread. Just add the:
runOnUiThread(new Runnable() {
#Override
public void run() {
arrayTipoSiniestro = new ArrayList<TipoSiniestro>();
tipoSiniestroAdapter = new SpinnerTipoSiniestroAdapter(getApplicationContext(), android.R.layout.simple_spinner_dropdown_item, (TipoSiniestro[]) arrayTipoSiniestro.toArray());
for(int i = 0; i < response.length(); i++)
{
try
{
tipoSiniestroAdapter.add(new TipoSiniestro(response.getJSONObject(i)));
}
catch(JSONException e)
{
e.printStackTrace();
}
}
tipoSiniestroAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinnerTipoSiniestro.setAdapter(tipoSiniestroAdapter);
}
});
around your response. Or handle it with creating a Handler before you call the async method and use the Handler on your return. Whichever you prefer is fine. It's not heavy enough to have a strong preference one way or the other.
Here is my code
package com.example.akash.myapplication;
//Required import files here
public class MainActivity extends Activity implements Runnable
{
public TextView tex;
public Button button;
public EditText edi;
public static Socket client;
String serverName = "192.168.0.100";
int port = 4444;
protected void onCreate(Bundle savedValues) {
button= (Button) findViewById(R.id.button1);
tex= (TextView) findViewById(R.id.textView1);
edi= (EditText) findViewById(R.id.editText1);
Runnable r = new MainActivity();
final Thread t= new Thread(r);
t.start();
// Register the onClick listener with the implementation above
button.setOnClickListener(new OnClickListener() {
public void onClick(View v){
try {
t.wait();
/*System.out.println("Enter your name: ");
Scanner sc = new Scanner(System.in);
String name = sc.nextLine();
System.out.println("Connecting to " + serverName + " on port " + port);*/
client = new Socket(serverName, port);
//System.out.println("Just connected to " + client.getRemoteSocketAddress());
OutputStream outToServer = client.getOutputStream();
DataOutputStream out = new DataOutputStream(outToServer);
out.writeUTF("Hello from " + client.getLocalSocketAddress());
String msg = edi.getText().toString();
out.writeUTF("Client: " + msg);
t.run();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public void run()
{
while(true)
{
try
{
client = new Socket(serverName, port);
if(client.getInputStream()!=null){
InputStream inFromServer = client.getInputStream();
DataInputStream in = new DataInputStream(inFromServer);
tex.append("Server: " + in.readUTF() + "\n");}
client.close();
}catch(Exception e)
{
e.printStackTrace();
}
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
public void test(){
// Acquire a reference to the system Location Manager
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
tex.setText("inside test");
/*String locationProvider = LocationManager.GPS_PROVIDER;
Location lastKnownLocation = locationManager.getLastKnownLocation(locationProvider);
t.setText("Latitude: " + lastKnownLocation.getLatitude());*/
// Define a listener that responds to location updates
LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
// Called when a new location is found by the network location provider.
double d = location.getLatitude();
tex.setText("Latitude: " + d);
}
public void onStatusChanged(String provider, int status, Bundle extras) {}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
};
// Register the listener with the Location Manager to receive location updates
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
}
}
And here is the null pointer error, which I guess is being caused in the run() method. I've been trying to fix this bug since more than couple hours now but all in vain.
01-07 09:05:35.178 28413-28413/com.example.akash.myapplication W/dalvikvm﹕ threadid=1: thread exiting with uncaught exception (group=0x4187fc08)
01-07 09:05:35.183 28413-28413/com.example.akash.myapplication E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.akash.myapplication, PID: 28413
android.util.SuperNotCalledException: Activity {com.example.akash.myapplication/com.example.akash.myapplication.MainActivity} did not call through to super.onCreate()
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2379)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2471)
at android.app.ActivityThread.access$900(ActivityThread.java:175)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1308)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5603)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
at dalvik.system.NativeStart.main(Native Method)
I'd really appreciate your help people.
If possible, please share some references or guide me anyway using which I can solve these problems myself and also help others in this great community.
Thankyou in advance.
Updated, the error is smaller now after following #M D
You forget setContentView(R.layout.yourlayout); before initialized views in onCreate(...).
A lot of things in your example are very wrong.
Admittedly, not the reason for the first NPE, but let me be a prophet:
You access tex inside the run method of your runnable MainActivity.
However, tex is initialized in the onCreate method which is part of the android activity life cycle. When you call Runnable r = new MainActivity(); you create a new activity outside that lifecycle so
tex will never be initialized in that new MainActivity
even if it would run into onCreate tex would be a different view, than you'd probably expect and you would create a BufferOverflow or OutOfMemoryError because of infinitely recursive created MainActivities
If you would make your runnable an anonymous implementation inside MainActivity it would probably close over texas you would like it to.
Runnable r = new Runnable {
public void run() {
try {
client = new Socket(serverName, port);
if(client.getInputStream()!=null){
InputStream inFromServer = client.getInputStream();
DataInputStream in = new DataInputStream(inFromServer);
tex.append("Server: " + in.readUTF() + "\n");}
client.close();
} catch(Exception e) {
e.printStackTrace();
}
}
}
I have to do a big task while a button click in my android app so i am using runnable to do background work. My works fine without the use of runnable but big task freezes it for a while. After the use of runnable my app is getting crashed on button click.
Here is my code for button onClick function:
public void doSearch(View v)
{
EditText et1 = (EditText) findViewById(R.id.searchText);
String query = et1.getText().toString();
Toast.makeText(this, "Searching Lyrics for "+query, Toast.LENGTH_LONG).show();
final String query1 = query.replaceAll(" ", "+");
Runnable myRunnable = new Runnable() {
#Override
public void run(){
try{
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet("http://example.com/search.php?q="+query1);
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
InputStream is = entity.getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(is, "iso-8859-1"), 8);
String line = null;
int count=0,counter=0, disCount=0;
String[] name = new String[20];
String[] link = new String[20];
String[] dis = new String[20];
while ((line = reader.readLine()) != null && counter<20){
if(count == 1){
if(line.contains("href=\"")){
line = line.substring(line.indexOf('=')+2);
link[counter] = line.substring(0, line.indexOf('"'));
line = line.substring(line.indexOf('"')+2);
name[counter] = line.substring(0, line.indexOf('<'));
}
if(disCount==1){
if(line.contains("<b>")){
line = line.replaceAll("<b>", "");
}
if(line.contains("</b>")){
line = line.replaceAll("</b>", "");
}
dis[counter] = line+"...";
counter++;
disCount=0;
}
}
if(line.equals("<div class=\"sen\">")){
count = 1;
}
if(line.equals("<div>")){
disCount=1;
}
if(line.equals("</div>")){
count = 0;
}
}
is.close();
line 82: searchResult(name, link, dis);
}catch(IOException e){} catch(IllegalStateException e){}
}
};
Thread myThread = new Thread(myRunnable);
myThread.start();
}
public void searchResult(String[] name, String[] link, String[] dis)
{
line 91: setContentView(R.layout.results);
nameTemp = name;
linkTemp = link;
rowItems = new ArrayList<RowItem>();
for (int i = 0; i < name.length; i++) {
if(name[i]==null) break;
if(name[0]==null){
Toast.makeText(this, "Sorry! No results matched your query. \n Try again! ", Toast.LENGTH_LONG).show();
}
RowItem item = new RowItem(name[i], dis[i]);
rowItems.add(item);
}
listView = (ListView) findViewById(R.id.result);
CustomListViewAdapter adapter = new CustomListViewAdapter(this, R.layout.list_item, rowItems);
listView.setAdapter(adapter);
listView.setOnItemClickListener(this);
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(this, "Loading Lyrics for "+nameTemp[position]+"!", Toast.LENGTH_SHORT).show();
Intent i = new Intent(this, ShowLyricsActivity.class);
i.putExtra("link", linkTemp[position]);
startActivity(i);
}
Here is my logcat:
I/ActivityManager(15444): Starting activity: Intent { act=android.intent.action.MAIN flg=0x10100000 cmp=com.BoxscapeInc.SongLyrics/.MainActivity }
V/ActivityThread(28108): Reporting idle of ActivityRecord{4a2ccbe0 token=android.os.BinderProxy#4a2cc658 {com.BoxscapeInc.SongLyrics/com.BoxscapeInc.SongLyrics.MainActivity}} finished=false
I/WindowManager(15444): Delivering pointer 0 > Window{4a5e2508 com.BoxscapeInc.SongLyrics/com.BoxscapeInc.SongLyrics.MainActivity paused=false}
I/WindowManager(15444): Delivering pointer 1 > Window{4a5e2508 com.BoxscapeInc.SongLyrics/com.BoxscapeInc.SongLyrics.MainActivity paused=false}
I/WindowManager(15444): Dispatching key to Window{4a5e2508 com.BoxscapeInc.SongLyrics/com.BoxscapeInc.SongLyrics.MainActivity paused=false}
I/WindowManager(15444): Dispatching key to Window{4a5e2508 com.BoxscapeInc.SongLyrics/com.BoxscapeInc.SongLyrics.MainActivity paused=false}
I/WindowManager(15444): Delivering pointer 0 > Window{4a5e2508 com.BoxscapeInc.SongLyrics/com.BoxscapeInc.SongLyrics.MainActivity paused=false}
I/WindowManager(15444): Delivering pointer 1 > Window{4a5e2508 com.BoxscapeInc.SongLyrics/com.BoxscapeInc.SongLyrics.MainActivity paused=false}
E/AndroidRuntime(28108): at com.BoxscapeInc.SongLyrics.MainActivity.searchResult(MainActivity.java:92)
E/AndroidRuntime(28108): at com.BoxscapeInc.SongLyrics.MainActivity$100000000.run(MainActivity.java:82)
W/ActivityManager(15444): Force finishing activity com.BoxscapeInc.SongLyrics/.MainActivity
I/ActivityManager(15444): Process com.BoxscapeInc.SongLyrics (pid 28108) has died.
Somebody please help me with this error.
Any help or suggestions would be appreciated.
In Android you can modify UI components only from main thread. You are accessing components in searchResult method called from other thread.
You can do it that way:
et1.post(new Runnable() {
#Override
public void run() {
searchResult(...);
}
});
It will force you to make some variables final, so you can use them in anonymous object. It is OK. See post method.
Personally I would recommend you using AsyncTask class instead of raw Java thread. It composes running one method in background thread and running another method in main thread.
Instead of doing network calls like you have done , I suggest you use this library
you can have a look at here
http://loopj.com/android-async-http/
your code will become very very less , instead of declaring so may asynctask seperately writing bulk of code , you can just use 4 lines of code
AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.google.com", new AsyncHttpResponseHandler() {
#Override
public void onSuccess(String response) {
System.out.println(response);
}
});
It is very efficient in getting the response very quickly in 2 secs.
you don't need to use buffer reader or stuff to format the response. You can directly use the response recieved in string "response" of onSucces method.
I hope this will help you out. :)
Similar or the same Question has been answered here
I am creating an Android App, which sends a broadcast message to the network and prepares a list of devices responding back.
Now What I did:
I created an Activity Class DeviceManagerWindow.java which calls a thread Sender.java.
Sender.java is responsible for sending the broadcast message.
Then the DeviceManagerWindow.java calls another thread which is responsible for listening to the devices responding back. The devices responding back will be listed in the Activity as soon as the device responds back. For that I have a TableLayout named deviceList.
What code I have written:
DeviceManagerWindow.java This method is called when a button for search is pressed
public void searchDevice(View v) throws IOException, InterruptedException
{
//Log.v("TableLayout:",view.toString());
sendMulticastFlyport = new Thread(new FlyportSender(MAC));
sendMulticastFlyport.start();
new Thread()
{
public void run()
{
MulticastSocket socketComputer=null;
try
{
socketComputer = new MulticastSocket(WifiConstants.COMPUTER_RECV_PORT);
socketComputer.joinGroup(InetAddress.getByName(WifiConstants.COMPUTER_NETWORK_ADDR));
socketComputer.setSoTimeout(1*60*1000);
byte[] inBufComputer = new byte[1024];
DatagramPacket inPacketComputer = new DatagramPacket(inBufComputer, inBufComputer.length);
while(true)
{
System.out.println("Listening...");
socketComputer.receive(inPacketComputer);
System.out.println("Received");
String msg = new String(inBufComputer, 0, inPacketComputer.getLength());
DeviceInformation device = new DeviceInformation(1, msg, inPacketComputer.getAddress().toString());
addDevice(device, false, 1);
Log.v("Received:","Received Computer From :" + inPacketComputer.getAddress() + " Msg : " + msg);
//System.out.write(inPacket.getData(),0,inPacket.getLength());
System.out.println();
Thread.sleep(2000);
}
}
catch(Exception e)
{
Log.v("Exception:","During Receiving Computer: "+e.toString());
try
{
addDevice(null, true, 1);
}
catch (IOException e1)
{
Log.v("Exception:", "Computer End Error: " +e1);
}
}
finally
{
socketComputer.close();
}
}
}.start();
The following code creates a list:
public void addDevice(DeviceInformation device, boolean bool, int type) throws IOException
{
TableLayout tb = (TableLayout) findViewById(R.id.DeviceList);
Log.v("addDevice","Called");
if(bool)
{
LayoutParams layout = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
TableRow tr = new TableRow(getApplicationContext());
TextView tv = new TextView(getApplicationContext());
System.out.println(tb);
tv.setLayoutParams(layout);
tr.setLayoutParams(layout);
String message;
Log.v("addDevice","Device Timeout");
switch(type)
{
case 1:
computerEnd=true;
break;
case 2:
raspberryEnd=true;
break;
case 3:
flyportEnd=true;
break;
}
if(computerEnd && raspberryEnd && flyportEnd)
{
if(rowCounter>0)
{
message = "No More Devices";
}
else
{
message = "No Devices Found";
}
tv.setText(message);
tv.setTextColor(Color.WHITE);
if(rowCounter%2==0)
{
tr.setBackgroundColor(Color.DKGRAY);
}
else
{
tr.setBackgroundColor(Color.GRAY);
}
tv.setVisibility(1);
tr.addView(tv);
tb.addView(tr);
}
}
else
{
LayoutParams layout = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
TableRow tr = new TableRow(getApplicationContext());
TextView tv = new TextView(getApplicationContext());
tv.setLayoutParams(layout);
tr.setLayoutParams(layout);
Log.v("addDevice","Received");
String textToDisplay = device.getDeviceTypeString()+"\n"+device.getIPAddress(); //Write the text to display
tv.setText(textToDisplay);
tv.setTextColor(Color.WHITE);
Drawable img;
if(device.getDeviceType()==1)
{
img = getApplicationContext().getResources().getDrawable(R.drawable.pc);
}
else if(device.getDeviceType()==2)
{
img = getApplicationContext().getResources().getDrawable(R.drawable.raspberry);
}
else
{
img = getApplicationContext().getResources().getDrawable(R.drawable.flyport);
}
img.setBounds(0,0,70,45);
tv.setCompoundDrawables(null, null, img, null);
tv.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
}
});
if(rowCounter%2==0)
{
tr.setBackgroundColor(Color.DKGRAY);
}
else
{
tr.setBackgroundColor(Color.GRAY);
}
rowCounter++;
Log.v("Result","Device Added");
}
}
Now it is showing me an error in the logCat as:
05-11 22:01:10.165: E/AndroidRuntime(13873): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
What I have figured out from this is only the UIThread is allowed to access the Views that is created.
Previously I had tried:
new Thread()
{
public void run()
{
runOnUiThread(){
MulticastSocket socketComputer=null;
try
{
....
....
....
}
}
And that time I received an error:
Main thread cannot access Network
Before that I had tried to use synchronized methods which was called from the Receiving.java Thread File. but It also gave an error of not creating the list.
I have tried all possible ways.
Now what whould I do.?
You figured it out right. Now you can learn to either use a Handler to pass information to the UI thread (see http://www.techotopia.com/index.php/A_Basic_Overview_of_Android_Threads_and_Thread_handlers) or AsyncTask (see http://developer.android.com/reference/android/os/AsyncTask.html).
I personally prefer AsyncTask. You can paste the code which performs the search into the doInBackground() method (not need to use a separate thread, doInBackground() already does that for you) and paste the UI-related code (the list creation code) into the onPostExecute() method. Search for further examples of AsyncTask if it is not sufficiently clear how it works from the link.
EDIT: If you intend your device search code to run indefinitely, then you have to resort to Handler, as AsyncTask expects the doInBackground() method to finish before running onPostExecute(). See which option better suits your needs.
The project i am working on needs this type of behavior. The user will be presented with a UI that will give them the option to connect and disconnect to a server. I would also like this UI to show the status of the connection, 'connected or disconnected'. Whenever the user clicks connect, the application will start a thread that handles the connection to the server. The user will still be looking at the main UI. When they start that connection and while the connection remains, i would like the status of the connection to be 'connected'. If the connection is ever broken at any point i would like it to display disconnected. Listed below is what i have so far.
My question is... Am i doing the threading right? So that the phone will not be crushed by the server connection while it is connected?
Also, how do i get the main UI to reflect the connection status of the server and display when the connection is broken?
Thanks in advance! If you have any further questions, please let me know.
The server connection thread.
public class ConnectDevice implements Runnable {
private boolean connected;
private ObjectInputStream ois;
public void run() {
try {
InetAddress host = InetAddress.getByName("192.168.234.1");
Socket socket = new Socket(host.getHostName(), 7777);
connected = true;
while (connected) {
try {
ois = new ObjectInputStream(socket.getInputStream());
String message = (String) ois.readObject();
System.out.println("Message: " + message);
}
catch (Exception e) {
e.printStackTrace();
}
}
ois.close();
} catch (UnknownHostException e) {
e.printStackTrace();
connected = false;
} catch (IOException e) {
e.printStackTrace();
connected = false;
} /*catch (ClassNotFoundException e) {
e.printStackTrace();
connected = false;
}*/
}
}
The main UI and main class.
public class SmartApp extends Activity
{
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.intro);
final Button firstTimeButton = (Button) findViewById(R.id.firstTimeButton);
firstTimeButton.setOnClickListener(
new View.OnClickListener()
{
#Override
public void onClick(View v)
{
// TODO Auto-generated method stub
Intent userCreationIntent = new Intent(v.getContext(), UserCreation.class);
startActivityForResult(userCreationIntent, 0);
}
});
final Button connectDeviceButton = (Button) findViewById(R.id.connectDeviceButton);
connectDeviceButton.setOnClickListener(
new View.OnClickListener()
{
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
//Intent connectDeviceIntent = new Intent(v.getContext(), ConnectDevice.class);
//startActivityForResult(connectDeviceIntent, 0);
Thread cThread = new Thread(new ConnectDevice());
cThread.start();
}
});
}
}
Android has a UI thread, which is the only thread that is allowed to update UI elements.
You need to have a background thread doing the work, and posting back to the UI thread when its done.
AsyncTask is an Android class designed to do just that.
Once your worker thread ends its work, and will update the UI element taken by findViewById, it will automatically change on the screen without you having to do anything else.
Check out the AsyncTask, it's tailor made for this sort of thing.