Right now I have one thread which populates the view of my activity. But I want another thread to add some textviews and imageviews in the same activity. I am using SurfaceView inside which I created this thread and I don't know how to add another thread so that it can contribute to the view of the current activity.
Help me out..
MyView view;
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
view = new MyView(this);
setContentView(view);
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
view.pause();
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
view.resume();
}
public class MyView extends SurfaceView implements Runnable {
Thread threadstill = null;
boolean isitok = false;
SurfaceHolder holder;
public MyView(Context context) {
super(context);
// TODO Auto-generated constructor stub
holder = getHolder();
}
#Override
public void run() {
// TODO Auto-generated method stub
while (isitok == true) {
if (!holder.getSurface().isValid()) {
continue;
}
canvas = holder.lockCanvas();
canvas.drawARGB(255, 255, 255, 255);
canvas.drawBitmap(<bitmapimage>, x, y, null);
holder.unlockCanvasAndPost(canvas);
}
}
public void pause() {
isitok = false;
while (true) {
try {
threadstill.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
threadstill = null;
}
public void resume() {
isitok = true;
threadstill = new Thread(this);
threadstill.start();
}
}
You cannot directly manipulate the user interface from another thread.
The main thread is responsible for all UI changes.
However, if you want to perform some expensive work in the background (e.g. loading pictures) you can send the results to the UI thread.
Hava a look at the official documentation: https://developer.android.com/training/multiple-threads/communicate-ui.html
Or at a similiar question: How can I manipulate main thread UI elements from another thread in Android?
I don't exactly know what is your issue but regarding to I don't know how to add another thread so that it can contribute to the view of the current activity. you can create a new thread easily with a nested class...simply call:
Thread myNewThread = new Thread(new Runnable() {
public void run() {
//do code here
}
}).start();
But be Aware you can only change views from the UIThread so i would recommend you the AsyncTask:
public void myAsyncTask exstends Asynctask<Void,Void,Void> {
....
}
AsyncTask Comes with several methods the most important is the doInBackground where you can do the heavy things like Network Connections or other stuff which would freeze the UI or is simply not allowed on the UIThread(Network stuff).
After doInBackground is finished onPostExecute is called which runs on the UiThread and where you can process changes on your views.
To get more Information look at this link:
http://developer.android.com/reference/android/os/AsyncTask.html
Hope it helps and it is what you asked for. ;)
Do it with AsyncTask class. In doInBackground method download image, and in onPostExecute method apply image to ImageView.
I did it here already https://github.com/bajicdusko/AndroidJsonProvider/tree/master/app/src/main/java/com/bajicdusko/ajp/tools.
You can use my class or make your own .
Related
I am trying to do an app in which there is a splash screen in the beginning. During loading, i need to show "Loading images...Loading modules....Now you are ready to go",etc. This is similar to the way in which facebook app loads showing the splash screen. I don't know how to do this. This is my current code :
public class Splash extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
Thread logoTimer = new Thread(){
public void run(){
try{
int logoTimer = 0;
while (logoTimer<5000){
sleep(100);
logoTimer=logoTimer+100;
}
startActivity(new Intent("com.package.MAIN"));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally{
finish();
}
}
};
logoTimer.start();
}
}
I would also like to keep a ProgressBar along with this. Can anyone help me out with a sample code or a reference. Thanks in advance.
You could use Handler to communicate from background thread to UI thread. Handler should send messages to UI when loading of one module is finished.
I have an event in the main thread that creates another thread. This new thread must sleep for 60 seconds and then it must check the main thread state. My code is this:
public class Act extends Activity {
Object lock=new Object();
public class MainT implements LocationListener {
public String str="";
public void onLocationChanged(Location location) {
synchronized(lock) {
str=String.valueOf(location.getLatitude())+" "+String.valueOf(location.getLongitude());
new SecondT(str).start();
}
}
class SecondT extends Thread {
public String st;
SecondT(String s) {
st=s;
}
public void run() {
waitSeconds();
}
public void waitSeconds() {
try {
Thread.sleep(60000);
synchronized(lock) {
if (str.equals(st))
Log.d("SecondT", "Same string.");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public void onProviderDisabled(String arg0) {
// TODO Auto-generated method stub
}
#Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LocationManager locMan = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
MainT mt = new MainT();
locMan.requestLocationUpdates(LocationManager.GPS_PROVIDER, 60000, 50, mt);
}
}
The problem is that if a start that thread, it's the MainT that sleeps (the GPS event isn't called even if i pass new coordinates through the debug tool).
The problem is that if a start that thread, it's the MainT that sleeps (the GPS event isn't called even if i pass new coordinates through the debug tool).
As #Joni mentions, it's hard to see where main would sleep unless the synchronized section of code that updates the string value is doing some complex operations that could take a long time. Could it be that main is trying to fork 2 threads and the 2nd one is waiting for the lock? If you provide more code we may be able to see your problem.
In terms of sharing the st value between the forked-thread and the main thread, you might consider something like an AtomicReference<String>. This will allow you to set(...) the value in the forked thread and get() the value in main without locking.
I have followed this tutorial to launch a url on android through jni call. It runs successfully.
In the same way I want to display a toast message from my cocos2dx layer like this:
public static void openURL(String url) {
Toast.makeText(me,url,Toast.LENGTH_LONG).show();
}
But its crashing with error: Can't create handler with thread. Do you know how can I display it correctly?
Try below code this will definately work for you.
First Create one Runnable interface in your class file like this,
Runnable runnable = new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, "Your url string...",Toast.LENGTH_SHORT).show();
}};
Then create one Handler object and call that runnable interface like below,
Create Handler object like,
Handler handler;
initialize it like,
onCreate(){
.................
handler = new Handler();
.................
}
then call runnable whenever you want like,
handler.post(runnable);
You can't run UI stuffs on a background thread.
You should use an AsyncTask and put that code in the on pre/post execute or if your just displaying a toast you can run it on the UI thread
runOnUiThread(new Runnable() {
}
So this was from 2012.
I guess not a lot people use cocos2d-x.
Ok this how you do this on cocos2d-x.
Edit the AppActivity.java
public class AppActivity extends Cocos2dxActivity
{
private Activity activity;
#Override
protected void onCreate(Bundle savedInstanceState)
{
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
this.activity = this;
showToast();
}
public void showToast()
{
activity.runOnUiThread(new Runnable()
{
#Override
public void run()
{
// TODO Auto-generated method stub
Toast.makeText(activity, "Hello :D", 10).show();
}
});
}
}
This works very nice in cocos2d-x version 3.x
I test it. Of course JNI just will call the method and this must work.
I wrote this app that in the first screen it has an included Thread on it. So it has I timed it like 7 seconds then it will proceed to the next activity.
The problem is whenever I hit the home button the music will stop and it will go to android homescreen but after my timed is done which is the 7 seconds, the app will reappear and will show the next activity.
I tried putting finish(); in the onpause(); but it's still showing the next activity.
here's the actual code.
public class HelloWorldActivity extends Activity {
MediaPlayer mp;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
mp = MediaPlayer.create(this, R.raw.otj);
mp.start();
Thread LogoTimer = new Thread(){
public void run(){
try{
int LogoTimer = 0;
while(LogoTimer < 7000){
sleep(100);
LogoTimer = LogoTimer + 100;
}
startActivity(new Intent("com.example.HelloWorld.CLEARSCREEN"));
} catch (InterruptedException e) {
e.printStackTrace();
}
finally{
finish();
}
}
};
LogoTimer.start();
}
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
mp.release();
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
mp.pause();
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
}
#Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
}
}
First, that's a really inefficient way to run a timer. Try this way instead:
new Handler().postDelayed(new Runnable() {
public void run() {
// Do some work.
}
}, delayTimeInMs);
Second, your starting a new activity when that timer eventually fires. It doesn't matter that the originating activity is finished. Your startActivity() is running on it's own thread and will execute regardless.
It's possible the postDelayed() method will function like you expect. If not you'll need to have it check when it runs whether it should really start the activity. However, I think the Handler is attached to the default Looper which means it will stop (or rather, the message won't be posted) if the main activity finishes.
The application is still in the background and the thread is not destroyed so it will fire the startActivity.
I would not really setup a splash screen this way, or use a thread unless I wanted it off the UI for some reason, even then there are better options.
For educational purposes to take care of this you need to be able to abort the thread safely in onPause() one way to do so is below
Modifed Thread
Thread LogoTimer = new Thread() {
private volatile boolean abortThread = false;
public void run(){
long stopAt = System.currentTimeMillis() + 7000;
while (!abortThread && stopAt > System.currentTimeMillis())
yield();
if (!abortThread)
startActivity ...
}
public synchronized void stopThread() {
abortThread = true;
}
};
I have an android app I am just experimenting things on and I cannot seem to figure out why my app force closes when I update a TextView via a while loop. When I comment out the updateText method it runs fine.
public class GameThread extends Thread {
Thread t;
private int i;
private boolean running;
private long sleepTime;
GameView gv;
public GameThread() {
t = new Thread(this);
t.start();
i = 0;
sleepTime = 1000;
}
public void initView(GameView v) {
this.gv = v;
}
public void setRunning(boolean b) {
this.running = b;
}
public boolean getRunning() {
return running;
}
public void run() {
while(running) {
i++;
update();
try {
t.sleep(sleepTime);
} catch(InterruptedException e) {
}
}
}
public void update() {
gv.setText(i); // when this is uncommented, it causes force close
Log.v("Semajhan", "i = " + i);
}
public class GameView extends LinearLayout {
public TextView tv;
public GameView(Context c) {
super(c);
this.setBackgroundColor(Color.WHITE);
tv = new TextView(c);
tv.setTextColor(Color.BLACK);
tv.setTextSize(20);
this.addView(tv);
}
public void setText(int i) {
tv.setText("i count: " + i);
}
public class Exp extends Activity {
GameThread t;
GameView v;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
v = new GameView(this);
setContentView(v);
t = new GameThread();
t.setRunning(true);
t.initView(v);
}
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (t.getRunning() == true) {
t.setRunning(false);
Log.v("Semajhan", "STOPPED");
} else {
t.setRunning(true);
Log.v("Semajhan", "RESTART");
}
}
return true;
}
protected void onDestroy() {
Log.v("Semajhan", "DESTROYING");
super.onDestroy();
}
protected void onStop() {
Log.v("Semajhan", "Stopping");
super.onStop();
}
I though i'd post the whole app since it is relatively small and so that I could get some help without confusion.
First, when you get a Force Close dialog, use adb logcat, DDMS, or the DDMS perspective in Eclipse to examine LogCat and look at the stack trace associated with your crash.
In this case, your exception will be something to the effect of "Cannot modify the user interface from a non-UI thread". You are attempting to call setText() from a background thread, which is not supported.
Using a GameThread makes sense if you are using 2D/3D graphics. It is not an appropriate pattern for widget-based applications. There are many, many, many, many examples that demonstrate how to create widget-based applications without the use of a GameThread.
You have to call it from the UI thread.
For more info check: Painless Threading .
If you decide to use a Handler, the easiest solution for you will be to:
Extend a View, override it's onDraw , in it draw the game objects, after you have calculated the game data for them first of course
The Handler: (in your Activity)
private Handler playHandler = new Handler() {
public void handleMessage(Message msg) {
gameView.postInvalidate(); // gameView is the View that you extended
}
};
The game thread has a simple
Message.obtain(playHandler).sendToTarget();
In 2 words, the View is responsible for the drawing (you can move the calculations in a separate class, and call it before the onDraw), the thread is responsible only for scheduled calls to the Handler, and the Handler is responsible only to tell the View to redraw itself.
You cannot update the UI of your app outside of the UI Thread, which is the 'main' thread you start in. In onCreate(Context) of you app, you are creating the game thread object, which is what is doing the updating of your UI.
You should use a Handler:
http://developer.android.com/reference/android/os/Handler.html