Android handler question
I created a separate thread file
Refer to the thread in another activity.
There is a problem when trying to change UI with handler.
This part is nullpoint.
Message hdmsg= handler.obtainMessage();
I do not know which part is the problem.
ClientThread.java
public class ClientThread extends Thread{
public ClientThread() {
}
public void run(){
try{
Thread currThread = Thread.currentThread();
while (currThread == thisThread) {
String recvData = ct_in.readUTF();
StringTokenizer st = new StringTokenizer(recvData, SEPARATOR);
int command = Integer.parseInt(st.nextToken());
switch (command) {
case MDY_WAITINFO: {
StringTokenizer st1 = new StringTokenizer(st.nextToken(), DELIMETER);
StringTokenizer st2 = new StringTokenizer(st.nextToken(), DELIMETER);
/*
code~
*/
Message hdmsg= handler.obtainMessage();
hdmsg.obj=st;
handler.sendMessage(hdmsg);
break;
}
}
}
} catch (IOException e) {
System.out.println(e);
release();
}
}
}
RoomList.java
public class HostRoomListActivity extends AppCompatActivity {
public static Handler handler;
protected void onCreate(Bundle savedInstanceState) {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SocketHostRoom client = new SocketHostRoom();
client.start();
handler = new Handler(){
public void handleMessage(Message msg){
String txtmsg = msg.obj.toString();
}
};
}
class SocketHostRoom extends Thread{
public void run(){
ClientThread thread = new ClientThread();
thread.start();
thread.requestHostRoomList();
}
}
}
}
Try calling HostRoomListActivity.handler.obtainMessage(); instead of justhandler.obtainMessage();
Sorry for the confusion it still needs to be called this way but also you are calling SocketHostRoom client = new SocketHostRoom(); before you are setting the handler
handler = new Handler(){
public void handleMessage(Message msg){
String txtmsg = msg.obj.toString();
}
};
Try setting the handler first the reason this is the issue is because when you call public static Handler handler; it will set it as null
Related
I'm trying to replace deprecated AsyncTask without using Kotlin Coroutines or others libraries, so I have
MyTask objects with following structure
public abstract class MyTask<R> implements MyCallable<R> {
#Override
public void setUiForLoading() {
//runs on ui
}
#Override
public void setDataAfterLoading(R result) {
//runs on ui
}
#Override
public R call() throws Exception {
//runs in background
return null;
}
}
MyCallable is just a simple interface
public interface MyCallable<R> extends Callable<R>{
void setDataAfterLoading(R result);
void setUiForLoading();
}
And use this MyTaskRunner to execute them
public class MyTaskRunner {
private final Handler handler = new Handler(Looper.getMainLooper());
private final Executor executor = Executors.newCachedThreadPool();
public <R> void executeAsync(MyCallable<R> callable) {
try {
callable.setUiForLoading();
executor.execute(new RunnableTask<R>(handler, callable));
} catch (Exception e) {
}
}
public static class RunnableTask<R> implements Runnable{
private final Handler handler;
private final MyCallable<R> callable;
public RunnableTask(Handler handler, MyCallable<R> callable) {
this.handler = handler;
this.callable = callable;
}
#Override
public void run() {
try {
final R result = callable.call();
handler.post(new RunnableTaskForHandler(callable, result));
} catch (Exception e) {
}
}
}
public static class RunnableTaskForHandler<R> implements Runnable{
private MyCallable<R> callable;
private R result;
public RunnableTaskForHandler(MyCallable<R> callable, R result) {
this.callable = callable;
this.result = result;
}
#Override
public void run() {
callable.setDataAfterLoading(result);
}
}
}
it works, but I cannot figure how I could replicate correctly the behaviour of publishProgress() and onProgressUpdate() of AsyncTask useful to show actual progress rather that just indeterminate
I cannot give the same code as yours but hopefully you get the idea.
Everything is self explain in code itself.
import android.app.*;
import android.graphics.*;
import android.os.*;
import android.widget.*;
import java.lang.ref.*;
public class MainActivity extends Activity
{
private static final class HeavyJob implements Runnable
{
private final WeakReference<Handler> handler;
private final Thread thread;
private boolean isAlive;
private boolean state;
private int progress;
public final HeavyJob(final Handler handler)
{
this.handler = new WeakReference<Handler>(handler);
thread = new Thread(this);
isAlive = true;
thread.setPriority(Thread.NORM_PRIORITY);
thread.start();
}
#Override
public final void run()
{
while(isAlive) {
try {
synchronized(this) {
while(!state) this.wait();
}
Thread.sleep(200L); //Let say this a heavy job which takes 200 m/s each round.
progress += 10;
final Handler hanRef = handler.get();
if(hanRef == null) {
isAlive = false;
handler.clear();
break;
}
final Message msg = Message.obtain();
msg.what = 0;
msg.arg1 = progress;
hanRef.sendMessageAtTime(msg, SystemClock.uptimeMillis()); //Update its progress each round.
} catch(final InterruptedException e) {}
}
//Finished ???
final Handler hanRef = handler.get();
if(hanRef != null) {
final Message msg = Message.obtain();
msg.what = 1;
msg.arg1 = progress; //Make your progress is 100% completed and updated.
//msg.obj = bitmap;
hanRef.sendMessageAtTime(msg, SystemClock.uptimeMillis());
}
}
public final synchronized void resume()
{
if(isAlive) {
state = true;
this.notify();
}
}
public final void suspend()
{
state = false;
thread.interrupt();
}
public final void stop()
{
isAlive = false; // In case interrupt() does nothing (Thread was not in sleep nor wait mode).
thread.interrupt();
handler.clear();
}
}
private static final class UIHandler extends Handler
{
private final WeakReference<MainActivity> activity;
public final UIHandler(final MainActivity activity)
{
super(Looper.getMainLooper());
this.activity = new WeakReference<MainActivity>(activity);
}
#Override
public final void handleMessage(final Message msg)
{
final MainActivity referent = activity.get();
if(referent != null) {
switch(msg.what) {
case 0: referent.onProgress(msg.arg1); break;
case 1: referent.onPostExecute(msg.arg1, (Bitmap)msg.obj); break;
}
}
}
}
private ProgressBar pb;
private ImageView iv;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
pb = findViewById(R.id.pb);
iv = findViewById(R.id.next);
UIHandler handler = new UIHandler(this);
//Initilize the object but will not run yet.
HeavyJob hj = new HeavyJob(handler);
//Run the job
hj.resume();
//Pause the job
hj.suspend();
//Resume the job
hj.resume();
//Stop the job
hj.stop();
//Multiple jobs
for(int i=0; i<10; i++) {
new HeavyJob(handler);
}
}
public final void onProgress(final int progress) {
pb.setProgress(progress);
}
public final void onPostExecute(final int progress, Bitmap bitmap)
{
pb.setProgress(progress);
if(bitmap != null) iv.setImageBitmap(bitmap);
}
}
The best I founded to do it is:
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MainActivity extends AppCompatActivity {
Button btn_start;
TextView text;
ProgressBar progressBar1, progressBar2;
int num = 0;
ExecutorService service;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = findViewById(R.id.textHello);
btn_start = findViewById(R.id.btn_start);
progressBar1 = findViewById(R.id.progressbar1);
progressBar2 = findViewById(R.id.progressBar2);
btn_start.setOnClickListener(v -> toDo());
}
private void toDo() {
service = Executors.newSingleThreadExecutor();
service.execute(() -> {
runOnUiThread(() -> {
// onPreExecute method of AsyncTask
progressBar1.setVisibility(View.VISIBLE);
progressBar2.setVisibility(View.VISIBLE);
});
// doInBackground of AsyncTask
for (int i = 1; i <= 10000; i++) {
num = i;
runOnUiThread(() -> {
// onProgressUpdate method of AsyncTask
progressUpdate(num);
});
}
runOnUiThread(() -> {
// onPostExecute method of AsyncTask
progressBar1.setVisibility(View.GONE);
progressBar2.setVisibility(View.GONE);
});
});
}
public void progressUpdate(Integer i) {
text.setText(String.valueOf(i));
progressBar2.setProgress(i);
}
}
I'm doing an application and I need to receive an udp array from java to android and put it in a Spinner. Does anyone know how to do it?
Now, this is the code that I'm working with but I only receive a string.
Does anyone have an idea of how I can receive the array working from this code?
UDPClientSocketActivity
public class UDPClientSocketActivity extends AppCompatActivity implements View.OnClickListener {
private TextView mTextViewReplyFromServer;
private EditText mEditTextSendMessage;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button buttonSend = (Button) findViewById(R.id.btn_send);
mEditTextSendMessage = (EditText) findViewById(R.id.edt_send_message);
mTextViewReplyFromServer = (TextView) findViewById(R.id.tv_reply_from_server);
buttonSend.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_send:
sendMessage(mEditTextSendMessage.getText().toString());
break;
}
}
private void sendMessage(final String message) {
final Handler handler = new Handler();
Thread thread = new Thread(new Runnable() {
String stringData;
#Override
public void run() {
DatagramSocket ds = null;
try {
ds = new DatagramSocket();
// IP Address below is the IP address of that Device where server socket is opened.
InetAddress serverAddr = InetAddress.getByName("xxx.xxx.xxx.xxx");
DatagramPacket dp;
dp = new DatagramPacket(message.getBytes(), message.length(), serverAddr, 9001);
ds.send(dp);
byte[] lMsg = new byte[1000];
dp = new DatagramPacket(lMsg, lMsg.length);
ds.receive(dp);
stringData = new String(lMsg, 0, dp.getLength());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ds != null) {
ds.close();
}
}
handler.post(new Runnable() {
#Override
public void run() {
String s = mTextViewReplyFromServer.getText().toString();
if (stringData.trim().length() != 0)
mTextViewReplyFromServer.setText(s + "\nFrom Server : " + stringData);
}
});
}
});
thread.start();
}
}
If you want to put data into Spinner there is a link: https://developer.android.com/guide/topics/ui/controls/spinner
I have a Server in Java and a Client in Android. In Android I have an AsyncTask for the receive of the video continuous by the server and a Thread that read the video with the MediaPlayer.
I launch the MediaPlayer after 5s but only the receipt packets are read at the moment when the MediaPlayer is launched.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handler = new Handler();
vidSurface = (SurfaceView) findViewById(R.id.surfView);
ConcurrentLinkedDeque<OutputStream[]> list = new ConcurrentLinkedDeque<>();
Connexion connexion = new Connexion(list);
connexion.execute();
new Thread(new Task2(list)).start();
}
private class Connexion extends AsyncTask<Void, Void, Void> {
private ConcurrentLinkedDeque<OutputStream[]> list;
public Connexion(ConcurrentLinkedDeque<OutputStream[]> list) {
this.list = list;
}
#Override
protected Void doInBackground(Void... params) {
ConcurrentLinkedDeque<OutputStream[]> list = new ConcurrentLinkedDeque<>();
DownloadVideo dv = new DownloadVideo(list);
dv.connexion();
return null;
}
}
public void launchVideo() {
Thread.sleep(5000);
vidHolder = vidSurface.getHolder();
vidHolder.addCallback(this);
}
class Task2 implements Runnable {
#Override
public void run() {
handler.post(new Runnable() {
#Override
public void run() {
Log.d("1", "Thread2");
launchVideo();
}
});
}
Thanks a lot.
Download Video :
public void connexion() {
try {
client = new Socket(IP_SERVER, 9003); // Creating the server socket.
if (client != null) {
// Receive video
InputStream in = client.getInputStream();
OutputStream out[] = new OutputStream[1];
// Store on device
out[0] = new FileOutputStream(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Movies/chrono2.mp4");
byte buf[] = new byte[1024];
int n;
while ((n = in.read(buf)) != -1) {
out[0].write(buf, 0, n);
//Adding last in the queue
list.addLast(out);
Log.d("byte" , "" + out);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I have two class:
MainActivity.java
ClientThread.java
ClientThread.java looks like this:
//
// client thread class
//
public class ClientThread implements Runnable
{
View _V;
public ClientThread(Context ctx)
{
Log.d("", "Step 1...");
LayoutInflater inflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Log.d("", "Step 2...");
_V = inflater.inflate(R.layout.activity_main, null);
Log.d("", "Step 3...");
}
#Override
public void run()
{
// validate server ip
if (MainActivity.SERVER_IP != "")
{
try
{
/* do socket stuff here... */
}
/*
catch exceptions here...
*/
else
{
setStatus("Wrong IP!!");
}
}
//
// message handler
//
public void setStatus(String msg)
{
// do status stuff here e.g. setting textview
}
//
// message handler for status edit box
//
Handler h = new Handler()
{
//EditText et = (EditText)findViewById(R.id.status_text);
TextView tv = (TextView)_V.findViewById(R.id.status_text);
#Override
public void handleMessage(Message msg_obj) {
String s = (String)msg_obj.obj;
tv.setText(s);
}
};
}
Then from MainActivity.java I am doing this:
public Context ctx;
TextView status;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ctx = this;
... other stuff
}
// on connect
// we create a new thread to connect to server
//
public void onConnect(View view)
{
try
{
new Thread(new ClientThread(ctx)).start(); <== creating new object is issue!
}
catch (IllegalStateException is)
{
is.printStackTrace();
}
}
Here is the error printed:
03-12 22:00:55.826: E/AndroidRuntime(1897): Caused by: java.lang.NullPointerException
03-12 22:00:55.826: E/AndroidRuntime(1897): at com.example.helloapp.ClientThread$1.<init>(ClientThread.java:101)
What I tried:
when I put the ClientThread class inside the MainActivity class things are good. But I want to separate the class in its own file. Why can't I call it the way I am doing and what is the right way?
The NPE is clearly because ctx was null, but ctx = this; etc. doesn't make much sense. If ctx is a self-valued instance variable, it doesn't even need to exist at all. Just remove it and use this, or MainActivity.this throughout, as appropriate.
I have a global variable in my main activity called "pinNumberConverted". I need to get the value of this variable in another class of type runnable (inside there is a server socket). How can i do it?
This is the main activity:
public class AndroidServer2 extends Activity {
Random pin_generator = new Random();
public int pin_number = pin_generator.nextInt(9000-1000 +1) +1000; //generate a random code for the first connection with the kiosk
public String pinNumberConverted = String.valueOf(pin_number);
Thread fst = new Thread(new MyServer()); //declaration of a new thread
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_android_server2);
initialize();
}
#Override
protected void onResume(){
super.onResume();
Utilities utilities = new Utilities();
utilities.connectionInfo(this, wiFi, wifiInfo, ipAddress, wirelessName, pin, ipAddressConversion, serverIp, pin_number);
if (fst.isAlive() == false){
fst.start();
}
}
}
This is the runnable class:
public class MyServer implements Runnable{
//Need to pass the information taken from connection info method in Utilities.java
public Handler handler = new Handler();
public ServerSocket serverSocket;
MyServerMethods myServerMethods = new MyServerMethods();
AndroidServer2 androidServer2 = new AndroidServer2(); //this doesn't work and give error in runtime
#Override
public void run() {
try{
ServerSocket parent = new ServerSocket(); //create a new socket
parent.setReuseAddress(true);
parent.bind(new InetSocketAddress(serverPort)); //bind the server port and reuse it if necessary
if ( serverIp != null){
Log.i("Status","READY");
while (true){
Socket client = parent.accept(); //accept the incoming connection
//Here i need to take the value of the global variable from the main activity
} catch (Exception e) {
e.printStackTrace();
}
}
}
Thanks