I want to display a progressdialog when a client sends request to the server..the request should be done in background...but i am getting a force close when i use the AsyncTask..Please help ..Thank you
package com.example.client;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
public static ProgressDialog Dialog;
String s1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button1).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// sendreq();
new SendUserTask().execute();
}
});
}
public String sendreq() {
try {
// TODO Auto-generated method stub
SocketAddress sockaddr = new InetSocketAddress("192.168.7.116",
9011);
Socket serversocket = new Socket();
serversocket.connect(sockaddr, 10000);
serversocket.setSoTimeout(10000);
DataOutputStream out = new DataOutputStream(
serversocket.getOutputStream());
out.flush();
DataInputStream in = new DataInputStream(
serversocket.getInputStream());
out.flush();
String msg = "";
msg = "hi";
out.writeBytes(msg);
out.flush();
byte[] message = new byte[100];
in.read(message);
s1 = new String(message);
Toast.makeText(getApplicationContext(), s1, Toast.LENGTH_LONG)
.show();
((TextView) findViewById(R.id.textView1)).setText(s1);
in.close();
out.close();
serversocket.close();
} catch (Exception e) {
Toast.makeText(getApplicationContext(), String.valueOf(e),
Toast.LENGTH_LONG).show();
}
return null;
}
private class SendUserTask extends AsyncTask<Void, Void, String> {
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
Dialog = ProgressDialog.show(MainActivity.this, "",
"Logging In....", true);
super.onPreExecute();
}
protected void onPostExecute(String s) {
if (Dialog.isShowing())
Dialog.dismiss();
}
#Override
protected String doInBackground(Void... params) {
// TODO Auto-generated method stub
try {
return sendreq();
} catch (Exception e) {
Toast.makeText(getApplicationContext(), String.valueOf(e),
Toast.LENGTH_SHORT).show();
}
return null;
}
}
}
this ((TextView) findViewById(R.id.textView1)).setText(s1); is executed from the background thread. you cannot access UI elements outside the UI thread.
You need to move that part to either onProgressUpdate or onPostExecute, or to run it in a runOnUiThread Runnable.
doInBackgorund() is a non-UI thread and you cannot access UI elements inside it. The code inside doInBackground() runs on a separate non-ui thread which does not have access to the UI elements defined in your layout. Also, since you are calling another Activity via intents, you should always keep in mind that an Activity runs on the UI thread and hence you should never start another Activity from inside a non-ui thread.
So, remove the code " ((TextView) findViewById(R.id.textView1)).setText(s1); " accessing the UI elements from inside of doInBackground() and instead put it inside onPostExecute(), which is a UI thread and is called after doInBackground() finishes the background processing.
Ok.... After googling a lot i finally came to understand that you cant access UI elements from main thread into a new non-UI thread....So you cant use elements like textview or even getApplicationContext mtd tht v use for toast in the dobackground mtd or even in anyother mts that the dobackground is calling....This also applies for the new Thread() using runnable..Thank you njzk2 for your help :)
Related
This question already has answers here:
How can I fix 'android.os.NetworkOnMainThreadException'?
(66 answers)
Closed 9 years ago.
I am new to android. My project is related to networking. I am getting this error
FATAL EXCEPTION: main
android.os.NetworkOnMainThreadException
at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java1133)
...
...
My code is :
package com.example.simpleclientactivity;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class SimpleClientActivity extends Activity {
private Socket client;
private PrintWriter printwriter;
private EditText textField1;
private Button button;
private String messsage;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textField1 = (EditText) findViewById(R.id.editText1); //reference to the text field
button = (Button) findViewById(R.id.button1); //reference to the send button
//Button press event listener
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Context context = getApplicationContext();
CharSequence text = "Hello toast!";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
messsage = textField1.getText().toString(); //get the text message on the text field
textField1.setText(""); //Reset the text field to blank
try {
client = new Socket("10.0.2.2", 4444); //connect to server
printwriter = new PrintWriter(client.getOutputStream(),true);
printwriter.write(messsage); //write the message to output stream
printwriter.flush();
printwriter.close();
client.close(); //closing the connection
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
Here is main.xml code
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<EditText
android:id="#+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"`enter code here`
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="83dp"
android:ems="10"
android:text="Client" >
<requestFocus />
</EditText>
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/editText1"
android:layout_centerHorizontal="true"
android:layout_marginTop="53dp"
android:text="Send" />
</RelativeLayout>
It's not even displaying the toast message after clicking the button. However it's showing error in android.os.NetworkOnMainThreadException.
Try this..
This exception is thrown when an application attempts to perform a networking operation on its main thread
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Context context = getApplicationContext();
CharSequence text = "Hello toast!";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
messsage = textField1.getText().toString(); //get the text message on the text field
textField1.setText(""); //Reset the text field to blank
new MyClass().execute(messsage);
}
});
MyClass.class AsyncTask
class MyClass extends AsyncTask<String, Void, String> {
private Exception exception;
protected String doInBackground(String... messsage) {
try {
client = new Socket("10.0.2.2", 4444); //connect to server
printwriter = new PrintWriter(client.getOutputStream(),true);
printwriter.write(messsage); //write the message to output stream
printwriter.flush();
printwriter.close();
client.close(); //closing the connection
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
protected void onPostExecute(String result) {
// TODO: check this.exception
// TODO: do something with the feed
}
}
You cannot perform network IO on the UI thread on Honeycomb. Technically it is possible on earlier versions of Android, but is a really bad idea as it will cause your app to stop responding, and can result in the OS killing your app for being badly behaved. You'll need to run a background process or use AsyncTask to perform your network transaction on a background thread.
There is an article about Painless Threading on the Android developer site which is a good introduction to this, and will provide you with much better depth of answer than can be realistically provided here.
You have to put your code that access the internet on a thread
new Thread(new Runnable(){
#Override
public void run(){
//your code that access internet here
}
}).start();
try this code
package com.example.simpleclientactivity;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class SimpleClientActivity extends Activity {
private Socket client;
private PrintWriter printwriter;
private EditText textField1;
private Button button;
private String messsage;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textField1 = (EditText) findViewById(R.id.editText1); //reference to the text field
button = (Button) findViewById(R.id.button1); //reference to the send button
//Button press event listener
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Context context = getApplicationContext();
CharSequence text = "Hello toast!";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
messsage = textField1.getText().toString(); //get the text message on the text field
textField1.setText(""); //Reset the text field to blank
new GetCategory().execute(message);
}
});
}
//add inner class
class GetCategory extends AsyncTask<Void, Void, ArrayList<AbstractDetail>>{
protected ArrayList<AbstractDetail> doInBackground(String... messsage) {
try {
client = new Socket("10.0.2.2", 4444); //connect to server
printwriter = new PrintWriter(client.getOutputStream(),true);
printwriter.write(messsage); //write the message to output stream
printwriter.flush();
printwriter.close();
client.close(); //closing the connection
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(ArrayList<AbstractDetail> result)
{
}
}
}
}
Problem
You can not access network over UI thread. You are accessing Network through UI thread that's why you are getting NetworkOnMainThreadException.
Solution
Create new thread and access Network over that Thread.
OR
Use AsyncTask to do network related work on doInBackgroung() and for updating UI onPostExecute().
i make this code in single application working, but if join with other application , show this dialog "android os network on main thread exception"
package com.kelompok2.bissmilahpulsa;
import java.util.ArrayList;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioGroup;
import android.widget.TextView;
public class coba extends Activity {
EditText nm,nmr;
RadioGroup prov,nom,pem;
TextView error;
Button ok;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mulaitransaksi);
nm=(EditText)findViewById(R.id.et_nama);
nmr=(EditText)findViewById(R.id.et_nomor);
prov=(RadioGroup)findViewById(R.id.provider);
nom=(RadioGroup)findViewById(R.id.nominal);
error=(TextView)findViewById(R.id.error);
pem=(RadioGroup)findViewById(R.id.pembayaran);
ok=(Button)findViewById(R.id.btn_ok);
ok.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
String type=null;
String type1=null;
String type2=null;
switch (prov.getCheckedRadioButtonId())
{
case R.id.rb_as:
type="As";
break;
case R.id.rb_axis:
type="Axis";
break;
case R.id.rb_im3:
type="Im3";
break;
case R.id.rb_telkomsel:
type="Telokmsel";
break;
case R.id.rb_xl:
type="Xl";
break;
}
switch (nom.getCheckedRadioButtonId())
{
case R.id.rb_5:
type1="5";
break;
case R.id.rb_10:
type1="10";
break;
case R.id.rb_20:
type1="20";
break;
case R.id.rb_50:
type1="50";
break;
}
switch (pem.getCheckedRadioButtonId())
{
case R.id.rb_cash:
type2="Cash";
break;
case R.id.rb_hutang:
type2="Hutang";
break;
}
ArrayList<NameValuePair> postParameters = new ArrayList<NameValuePair>();
postParameters.add(new BasicNameValuePair("nama", nm.getText().toString()));
postParameters.add(new BasicNameValuePair("nomor", nmr.getText().toString()));
postParameters.add(new BasicNameValuePair("provider", type));
postParameters.add(new BasicNameValuePair("nominal", type1));
postParameters.add(new BasicNameValuePair("jenis_pembayaran", type2));
String response = null;
try {
response = CustomHttpClient.executeHttpPost("http://appmob.pusku.com/save.php", postParameters);
String res = response.toString();
res = res.trim();
res = res.replaceAll("\\s+","");
error.setText(res);
if (res.equals("1")) error.setText("Data Tersimpan");
else error.setText("Data Tersimpan Ke server");
}
catch (Exception e) {
error.setText(e.toString());
}
String nama1 = nm.getText().toString();
String nama2 = nmr.getText().toString();
String nama3 = type;
String nama4 = type1;
String nama5 = type2;
String sms = nama1+"#"+nama2+"#"+nama3+"#"+nama4+"#"+nama5;
Intent i = new Intent (Intent.ACTION_SENDTO,Uri.parse("sms:5556"));
i.putExtra("sms_body", sms);
startActivity(i);
nm.setText(null);
nmr.setText(null);
}
});
}
}
in permission i active that <uses-permission android:name="android.permission.INTERNET"/>
and still not working
You need to run internet activities on a thread separate from main (UI) thread, you can do that by wrapping your code in the following block:
new Thread() {
#Override
public void run() {
//your code here
}
}.start();
Execute your Network related operation in AsyncTask
You can also refer here Android AsyncTask
public class ExcuteNetworkOperation extends AsyncTask<Void, Void, String>{
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
/**
* show dialog
*/
super.onPreExecute();
}
#Override
protected String doInBackground(Void... params) {
// TODO Auto-generated method stub
/**
* Do network related stuff
* return string response.
*/
return null;
}
#Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
/**
* update ui thread and remove dialog
*/
super.onPostExecute(result);
}
}
first method
you can create an AsynTask .. Your code should run in background in order to be responsive.. otherwise it will show Not Responding ..
Second Method
You can create a seperate thread for it .. using multitasking.
Third
Right the code in the onCreate after setContentView
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
While all of the answers posted in this thread is correct, asynctasks are not really considering to be a good tool to user for network transactions anymore. The main reasons for this is that the asynctasks are very closely tied to activities so alot issues arise like..."what happens if the activity is destroyed before the network call returns?".
If you really want to implement android best practices (and not to mention impress your fellow Android devs) then why not perform a network task in a service?
I would suggest looking at the Path FOSS project android-prioriy-queue. They make it ridiculously easy to perform task in a service.
I am using the following code to make the android device a ftp server (Android Internal storage). I am getting the exception of os.android.NetworkOnMainThread. I have tried to put the onStart code in the AsyncTask but app never executes and crashes on launch. Any help regarding the ftp server on Android will be great as i have no idea how to get it working.
Here is the MainActivity Code
package com.googlecode.simpleftp;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;
public class FTPServer extends Activity {
private static int COMMAND_PORT = 2121;
static final int DIALOG_ALERT_ID = 0;
private static ExecutorService executor = Executors.newCachedThreadPool();
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.my_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.new_game:
System.out.println("New game button is pressed!");
//newGame();
return true;
case R.id.quit:
System.out.println("Quit button is pressed!");
showDialog(DIALOG_ALERT_ID);
return true;
default:
return super.onOptionsItemSelected(item); }
}
#Override
protected Dialog onCreateDialog(int id){
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Are you sure you want to exit?")
.setCancelable(false).setPositiveButton("yes", new DialogInterface.OnClickListener(){
#Override
public void onClick(DialogInterface dialog, int id){
FTPServer.this.finish();
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog alert = builder.create();
return alert;
}
HEre is the ServerPI Code
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class ServerPI implements Runnable{
private Socket clientSocket;
private BufferedReader in;
private PrintWriter out;
private String baseDir;
private String relativeDir;
private String absoluteDir;
private String fileName;
private String filePath;
public ServerPI(Socket incoming) throws IOException{
this.clientSocket = incoming;
in = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
out = new PrintWriter(this.clientSocket.getOutputStream(), true);
baseDir = new File("").getAbsolutePath();
relativeDir = "/";
absoluteDir = baseDir + relativeDir;
fileName = "";
filePath = absoluteDir + "/" + fileName;
}
private void readCommandLoop() throws IOException {
String line = null;
reply(220, "Welcome to the SimpleFTP server!");
while((line = in.readLine()) != null){
int replyCode = executeCommand(line.trim());
if(replyCode == 221){
return;
}
}
}
private int executeCommand(String trim) {
// TODO Auto-generated method stub
return 0;
}
public int reply(int statusCode, String statusMessage){
out.println(statusCode + " " + statusMessage);
return statusCode;
}
#Override
public void run(){
try{
this.readCommandLoop();
} catch (IOException e){
e.printStackTrace();
}
finally {
try {
if(in != null){
in.close();
in = null;
}
if(out != null){
out.close();
out = null;
}
if (clientSocket != null){
clientSocket.close();
clientSocket = null;
}
}
catch (IOException e){
e.printStackTrace();
}
}
}
}
I have put the code in the AsyncTask, here it is
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
ServerSocket s = null;
Socket incoming = null;
try{
s = new ServerSocket(COMMAND_PORT);
String ip = (s.getInetAddress()).getHostAddress();
Context context = this.getApplicationContext();
CharSequence text = ip;
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, text, duration);
Thread.sleep(1000);
toast.show();
while(true){
incoming = s.accept();
executor.execute(new ServerPI(incoming));
}
}
catch(Exception e){
System.out.println(e.toString());
e.printStackTrace();
}
finally{
try
{
if(incoming != null)incoming.close();
}
catch(IOException ignore)
{
//ignore
}
try
{
if (s!= null)
{
s.close();
}
}
catch(IOException ignore)
{
//ignore
}
}
return "Executed";
}
#Override
protected void onPostExecute(String result) {
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Void... values) {
}
}
Iam calling the longOpertation in onCreate method. What is the problem that the app crashes on launch.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fullscreen);
new LongOperation().execute();
}
Maybe because you didn't set up the permissions in the manifest? You've to set permission for internet usage.
If this doesn't work, please tell us which line is it throwing the exception.
while(true){ incoming = s.accept(); ...} You cannot put that in OnStart(). That should be done in a thread. So ServerSocket s = null; should be a variable of you activity.
So I went with Swiftp application (open source) as a service in my application which helped me to achieve my task. Thanks everyone who stepped forward to help. Here is the link if someone wants to follow
Please post your code here.
NetworkOnMainthreadException occurs because you maybe running Network related operation on the Main UI Thread. You should use asynctask for this purpose
This is only thrown for applications targeting the Honeycomb SDK or higher. Applications targeting earlier SDK versions are allowed to do networking on their main event loop threads, but it's heavily discouraged.
http://developer.android.com/reference/android/os/NetworkOnMainThreadException.html
class TheTask extends AsyncTask<Void,Void,Void>
{
protected void onPreExecute()
{ super.onPreExecute();
//display progressdialog.
}
protected void doInBackground(Void ...params)//return result here
{
//http request. do not update ui here
//call webservice
//return result here
return null;
}
protected void onPostExecute(Void result)//result of doInBackground is passed a parameter
{
super.onPostExecute(result);
//dismiss progressdialog.
//update ui using the result returned form doInbackground()
}
}
http://developer.android.com/reference/android/os/AsyncTask.html. Check the topic under the heading The 4 Steps.
A working example of asynctask # To use the tutorial in android 4.0.3 if had to work with AsynxTasc but i still dont work?.
The above makes a webserive call in doInBakckground(). Returns result and updates the ui by setting the result in textview in onPostExecute().
You can not do network operation in main thread in android 3.0 higher. Use AsyncTask for this network operation. See this for further explanation
I'm trying to establish a simple UDP connection between a client program running on an android emulator and a server, on two different systems. The server side is fine, but the client side keeps crashing. Is it a problem with the emulator? Should i redirect the port to make it work?
CLIENT SIDE (on android emulator):
package com.example.clientrecv;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends Activity
{
public String text;
public int serverport=1234;
public byte[] message=new byte[1000];
public Button b;
public DatagramPacket p;
public DatagramSocket s;
public Toast t;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
b=(Button) findViewById(R.id.button1);
try {
p = new DatagramPacket(message,message.length);
s = new DatagramSocket(serverport);
try {
s.receive(p);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
text= new String(message,0,p.getLength());
Log.d("hello","the message:"+text);
s.close();
// TODO Auto-generated method stub
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void showmsg()
{
t=Toast.makeText(getApplicationContext(), text, Toast.LENGTH_LONG);
t.show();
}
}
SERVER SIDE: (on pc)
import java.io.*;
import java.net.*;
class serversend
{
public static void main(String args[]) throws Exception
{
String strmsg="Server says hello";
int serverport=1234;
int len=strmsg.length();
System.out.println("starting");
byte[] message=strmsg.getBytes();
try{
InetAddress local=InetAddress.getByName("localhost");
DatagramSocket s=new DatagramSocket();
DatagramPacket p=new DatagramPacket(message,len,local,serverport);
System.out.println("Running");
s.send(p);
System.out.println("Sent");
}catch(Exception e)
{
System.out.println("caught");
}
}
}
There are many example available that can help you to communicate between server and client using UDP
to communicate between these two should add the client port on server side
InetAddress local = InetAddress.getByName("192.168.1.102");
here are the Following Link For Client Server Communication Using UDP
LINK UDP1
Link UDP2
Android after 3.0 version doesn't allow you to implement networking operations within the main UI Thread. You must define a new Thread for that... Here is how you can do it:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//here you Set up you parameters and launch the thread (e.g):
this.newThread = new Thread(new mThread());
this.newThread.start();
/* Next you define your newThread's run method in wich all networking
operations must take place*/
class mThread implements Runnable {
public void run() {
// Do all networking tasks you need
}
}
In my application i want to do bluetooth chat. I'm facing a problem in threading. In my application my android phone will work as server which has a blocking statement
socket=mServerSocket.accept();
for this purpose i've created a child thread so that it will run separately. But before finishing this child thread main thread goes down giving Force Close and if i use the .join() method it hangs up my UI.
What is the solution to run both threads parallel?
this is my code
main Activity
package com.my.bluechat_2_1;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class BlueChat extends Activity {
/** Called when the activity is first created. */
private BlueHandler btHandler=null;
private BluetoothAdapter btAdapter = null;
private Context context=this;
TextView chatWindow=null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
chatWindow=(TextView)findViewById(R.id.textView1);
doStart();
}
private void doStart(){
Button btnStart=(Button)findViewById(R.id.button1);
btnStart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
// Get local Bluetooth adapter
btAdapter = BluetoothAdapter.getDefaultAdapter();
// If the adapter is null, then Bluetooth is not supported
if(btAdapter == null)
{
Toast.makeText(context, "Device does not support Bluetooth", Toast.LENGTH_LONG).show();
}
if (!btAdapter.isEnabled()) {
Intent discoverableIntent = new
Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
}
chatWindow.append("Waiting for connection...\n");
btHandler=new BlueHandler(context,chatWindow,btAdapter);
Thread acceptThread=new Thread(btHandler);
acceptThread.start();
}
});
}
}
BlueHandler
package com.my.bluechat_2_1;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.widget.TextView;
import android.widget.Toast;
public class BlueHandler implements Runnable{
// Name for the SDP record when creating server socket
private static final String SMARTCAM_BT_SERVICE_NAME = "SmartCam";
// Unique UUID for this application
private static final UUID SMARTCAM_BT_SERVICE_UUID = UUID.fromString("95b82690-4c94-11e1-b86c-0800200c9a66");
private BluetoothAdapter btAdapter = null;
private BluetoothServerSocket btServerSocket = null;
private BluetoothSocket btSocket = null;
private InputStream btInputStream=null;
private Context contextObj=null;
private TextView textView;
public BlueHandler(Context contextObj,TextView textView,BluetoothAdapter btAdapter){
this.contextObj=contextObj;
this.btAdapter=btAdapter;
this.textView=textView;
try {
btServerSocket=this.btAdapter.listenUsingRfcommWithServiceRecord(SMARTCAM_BT_SERVICE_NAME, SMARTCAM_BT_SERVICE_UUID);
} catch (IOException e) {
// TODO Auto-generated catch block
Toast.makeText(this.contextObj, "Service not created", Toast.LENGTH_LONG);
}
}
#Override
public void run() {
// TODO Auto-generated method stub
textView.append("Inside child thread.\n");
textView.append(btServerSocket+"\n");
while (true) {
try {
btSocket = btServerSocket.accept();
} catch (IOException e) {
break;
}
// If a connection was accepted
if (btSocket != null) {
// Do work to manage the connection (in a separate thread)
try {
btServerSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
}
textView.append("Connected.\n");
try {
btInputStream=btSocket.getInputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] buffer = new byte[1024]; // buffer store for the stream
String s;
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes=btInputStream.read(buffer);
s= new String(buffer);
// Send the obtained bytes to the UI Activity
textView.append("received ::" +s+"\n");
} catch (IOException e) {
break;
}
}
}
}
You're probably getting a crash because you're accessing a textView on the worker thread. You'll need to use TextView.post(Runnable) to make that not happen.
In reality you should be using a bindable Service to do this kind of work. You can post back to the UI via broadcast intents or callback methods, That way you don't have to worry about rotation bugs.
Are you performing a long operation in the constructor of your children thread? Each long operation must be done in the run() method.