I have 2 layouts, and 2 activities, each one corresponding to a layout, one of them is SplashActivity, and the other is MainActivity. I want the application to open the splashActivity(splash XML shows the logo), wait for 5 seconds and open the main activity, but because of the thread, the setContentView doesn't work properly.
P.S. Also any relative documentation links would be very useful, thanks in advance
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash_screen);
Thread timer = new Thread() {
public void run() {
try {
sleep(5000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
try {
Class mainMenu = Class.forName("com.carmine.project.MenuActivity");
Intent openMainMenu = new Intent(SplashActivity.this, mainMenu);
startActivity(openMainMenu);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
};
timer.run();
}
your problem is that you are calling timer.run(); instead of timer.start();
timer.run(); calls the run method on the same context of the thread that executed that line (making the UI Thread, in your case, wait for 5s, and blocking every other operation). timer.start() spawns a new thread
Related
I have a ListView that I want to update with messages coming from a Bluetooth socket. The ListView is in a fragment, this does not matter too much.
The problem comes when I want to listen to incoming messages from the socket (which is a locking mechanism on a separate thread) and update the ListView with the received message.FChat.java
public class FChat extends Fragment {
ArrayList<String> listItems=new ArrayList<String>();
ArrayAdapter<String> itemsAdapter;
....
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//setup list view
ListView messageContainer = (ListView) thisView.findViewById(R.id.btMessagesContainer);
itemsAdapter = new ArrayAdapter<String>(thisView.getContext(), android.R.layout.simple_list_item_1, listItems);
currentAct = getActivity();
Thread test = new Thread() {
public void run() {
try {
currentAct.runOnUiThread(new Runnable() {
#Override
public void run() {
listItems.add("other:" + String.valueOf(times));
try {
String reply = bluetoothConnector.readSingleMessage();
listItems.add("other:" + reply);
itemsAdapter.notifyDataSetChanged();
}
catch (IOException e) {
e.printStackTrace();
}
}
});
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
test.start();
}
}
So, this feels like it's blocking the UI thread completely, so I guess that runOnUiThread it's blocking the UI thread.
If I take out the blocking part
String reply = bluetoothConnector.readSingleMessage(); and replace it with String reply = "test" it works fine, the UI is updated and seems to work great.
So, my question is, how can I read data from a socket and update the ListView with its contents?
Thank you
Obviously it blocks UI thread.
How your code looks like in pseudo:
Thread {
//there is separate thread
UiThread{
//there is UI thread
blockingOperation()
}
}
In other words your current thread is almost useless since you do blocking operation in UI thread.
And for sure it works with
String reply = "test"
Because that is not blocking operation.
So to solute problem just move
String reply = bluetoothConnector.readSingleMessage();
inside separate thread:
Thread test = new Thread() {
public void run() {
try {
final String reply = bluetoothConnector.readSingleMessage();
currentAct.runOnUiThread(new Runnable() {
#Override
public void run() {
listItems.add("other:" + String.valueOf(times));
listItems.add("other:" + reply);
itemsAdapter.notifyDataSetChanged();
}
});
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
I have the below code:
new Thread(new Runnable(){
public void run(){
try {
pos = Calculo.Calcular();
mostrarFrases(pos);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
where mostrarFrases is:
void mostrarFrases(int pos){
Mostrar = (TextView) findViewById(R.id.Texto);
Mostrar.setText(Frases[pos*2+1], 0, Frases[pos*2+1].length);
}
It works if i haven't any thread but without it does not work. I need thread because i need to wait until Calculo.Calcular() finish its work.
Rule: You cannot manipulate UI elements outside the UI thread.
Here is the proper way to do things:
//Asuming that your activiy is named MainActivity
new Thread(new Runnable() {
public void run() {
try {
pos = Calculo.Calcular();
//Manipulate your UI elements as following
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
mostrarFrases(pos);
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
You're not allowed to touch Views on any thread other than the UI thread.
To solve this, try the following:
void mostrarFrases(final int pos){
runOnUiThread(new Runnable() {
public void run() {
Mostrar = (TextView) findViewById(R.id.Texto);
Mostrar.setText(Frases[pos*2+1], 0, Frases[pos*2+1].length);
}});
}
You should not manipulate UI elements on any thread except the main UI thread.
So, in your case you got two choices: either use runOnUIThread(Runnable), or use AsyncTask and do UI manipulations in onPostExecute().
I'd go with AsyncTask - it is intended for this kind of scenarios.
UI manipulation must be done in main/ui thread. You have two options for this case:
You have a reference to your Activity object.
myActivity.runOnUiThread(...);
Bind a handler to the main thread and:
// Main thread
Handler handler = new Handler();
// Another thread
handler.post(new Runnable(){...});
I am trying to build an app that works as an alarm clock. I implemented everything with help of the AlarmManager and it works fine. But I have one problem, when the alarm rings it starts an Activity which shows a screen with a button and plays a sound. But it shows only a black screen and vibrates + plays the sound and then after that it shows the alarm screen.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.wecker);
laufen = true;
mp = MediaPlayer.create(getApplicationContext(), R.raw.ton);
verstanden =(Button)findViewById(R.id.button1);
verstanden.setOnClickListener(new View.OnClickListener() {public void onClick(View view)
{
finish();
}
});
for (int i=0; i<10;i++)
{
mp.start();
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
v.vibrate(1000);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
What can I do to show the activity and play the sound simultaneously?
Thread.sleep(1000); Blocks your UI Thread hence, the black screen shows up.
Use this :
new Thread( new Runnable() {
public void run() {
try {
// Add loop to play music and vibrate here
} catch (InterruptedException ie) {}
}
) }.start();
You have put Thread.sleep(1000); in your onCreate() method which is on your UI Thread. Your activity's UI only shows up at onResume() which is after onCreate() so it doesn't get there until your sleep commands are finished. You need to create a new Thread and run the vibrator/sleep cycle on that Thread. Usage is shown in Shivam Verma's answer.
I have a Splash Screen (Logo Activity) to show the company name for 3 seconds before app starts. I start Main Activity from a thread, here is the code:
public class Logo extends Activity {
Thread t;
public boolean dead = false;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.logo);
t = new Thread() {
public void run() {
try {
Intent i = new Intent(Logo.this, Main.class);
Thread.sleep(3000);
if (!dead) {
startActivity(i);
}
finish();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t.start();
}
The Main Activity is called from a worked thread, is this correct? What are the differents with this code (using runOnUiThread)?
...
if (!dead) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Intent i = new Intent(Logo.this, Main.class);
startActivity(i);
}
});
}
...
I see no difference with this code in debug mode (The same threads, the same operation, etc.). Which is correct?
Starting an intent I think is not an UI operation. runOnUI thread runs UI operation on UI thread. So you can use either of thread (runOnUI or normal). May be normal thread will be good in this situation. But I would like to suggest you use timer instead.
To be honest, I don't like the Thread.sleep. PLease take a look at my solution:
new Timer().schedule(new TimerTask() {
#Override
public void run() {
// Do your work here like... startActivity...
}
}, SPLASH_DURATION); // SPLASH_DURATION IS IN MILLISECONDS LIKE 3000
Also you can block the user to prevent the back key like this:
#Override
public void onBackPressed() {
// do nothing! disable user interaction!
}
You should use AsyncTask in "doInBackground" background thread and than sleep your thread(this thread not UIThread) "PostExecute" run on UI Thread than start your new activity
private class mSplashViewer extends AsyncTask<Void,Void,Void>{
protected void doInBackground(Void params){
Thread.currentThread().sleep(3000);
return null;
}
protected void onPostExecute(){
startActivity(...);
}
}
that code will help me explain my problem:
public class TestHandlerActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new Thread(){
public void run(){
for (int i=0;i<20;i++){
handler.post(run);
}
}
}.start();
}
Handler handler=new Handler(){
};
Runnable run = new Runnable(){
public void run(){
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.d("TAG", "Message processed");
}
};
}
That way the new thread makes the petitions which are served by the handler in the main thread.
What i need to do is exactly the opposite. The UI thread launches petitions wich are served sequentially by another thread (the order is important), and the UI thread don't need to be notified when each petition end.
Some points are important for this: The petitions have 3 parameters (int, int, boolean), they make changes in the database and are generated by the interaction of the user with the UI, so they aren't launched simultaneously
Thanks in advance
One option is to use this for making your thread: http://developer.android.com/reference/android/os/HandlerThread.html
This will create a thread with its own message queue and loop. You can create a Handler to run work on the thread like so:
HandlerThread handlerThread = new HandlerThread("My Handler");
handlerThread.start();
Handle myHandler = new Handler(handlerThread.getLooper());
This does require that all work done by thread be done so by sending messages and scheduling Runnables on it through Handlers.