postInvalidate() not working with non-ui Thread - java

I am using a custom view to draw a game content and i use a button from xml layout to enable or disable the drawing of a specific content(rectangle) using separate thread.I managed to have the thread running but postInvalidate() method that i use is being ignored.I tried using setWillNotDraw(false) too.It isn't working.I've condensed my code,to be specific on which part of the code i have this problem.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/frm"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.temp.Cview
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="#+id/bMineDetector"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:text="Lock" />
</RelativeLayout>
</FrameLayout>
And this is my MainActivity.java
package com.example.temp;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity implements OnClickListener{
Button b;
Boolean lock=false;
Cview v;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
v=new Cview(this,null);
setContentView(R.layout.activity_main);
initialize();
}
private void initialize() {
// TODO Auto-generated method stub
b=(Button) findViewById(R.id.bMineDetector);
lock=false;
b.setOnClickListener(this);
}
public void updateViewStart(){
v.onStart();
}
public void updateViewStop(){
v.onPause();
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
if(v.isRunning==true)
v.onPause();
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch(v.getId()){
case R.id.bMineDetector:
if(lock==false){
lock=true;
updateViewStart();
b.setText("UnLock");
}else{
lock=false;
updateViewStop();
b.setText("lock");
}
break;
}
}
}
In the above class i set a onClickListener that helps to start or stop a separate thread based on the state of the button.Here is my custom view where i handle touch events and also create this thread.
Cview.java
package com.example.temp;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
public class Cview extends View implements OnTouchListener,Runnable{
Boolean isRunning=false,isLockMode=false;
Context gameContext;
Thread myThread=null;
public Cview(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
gameContext=context;
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
Log.d("INVALIDATE", "Invalidating");
isLockMode=((MainActivity)gameContext).lock;
if(isLockMode==true){
canvas.drawRect(100, 100, 300, 300, null);
//invalidate();
}
}
#Override
public void run() {
// TODO Auto-generated method stub
while(isRunning){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
isLockMode=((MainActivity)gameContext).lock;
this.postInvalidate();
Log.d("THREAD", "isRunning="+isRunning+";;isLockMode="+isLockMode);
}
}
void onStart(){
isRunning=true;
myThread=new Thread(this);
myThread.start();
//Log.d("INVALIDATE", "onStart");
//postInvalidate();
}
void onPause(){
isRunning=false;
while(true){
try {
myThread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
myThread=null;
}
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
return true;
}
}
Please anyone help me with this.I need the canvas to be redrawn once the run method is being executed.Ive been thinking about this for months and I'm new to programming too.So please guide me and suggest me if there is any other better method to do what i need.Thank you.

As explained in What is the difference between Android's invalidate() and postInvalidate() methods?, there might be some problems when postInvalidate is used from other threads.
I haven't tested this and it's not really nice, but it could help you (instead of this.postInvalidate();)
((MainActivity) gameContext).runOnUiThread(new Runnable() {
#Override
public void run() {
Cview.this.invalidate();
}
});

I just ran into the exact same issue.
The fix for me was to assign the custom view using
findViewById() in onCreate(), instead of calling the constructor.
Add
android:id="#+id/custom_view"
to your XML, and
v = (Cview) findViewById(R.id.custom_view);
to your onCreate() function (and remove the constructor call).
Do this after calling setContentView().
Android has gazillions of silent failure modes like this.

Related

android activity work with intent

i made three activities for a game i want to go from 1st to 2nd to 3rd and then go 1st 2nd 3rd again but i got confused with the whole intent thing tried all kind of combinations but for some reason i stuck always with a problem currently it goes from 1st to 2nd to 3rd to 1st and when it supposed to lunch 2nd it exits from the whole app
//1st activity
Intent discoverintent = new Intent(getBaseContext(), discoverstring.class);
//discoverintent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(discoverintent);
//2nd activity
Intent MainIntent = new Intent(getBaseContext(), learningword.class);
//MainIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainIntent.putExtra("text", text);
MainIntent.putExtra("speakeronoff", Integer.toString(speakeronoff));
MainIntent.putExtra("previous", Integer.toString(previous));
startActivity(MainIntent);
and the 3rd activity just uses finish
package self.yanfaingold.talkgame;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.Window;
import android.view.WindowManager;
#SuppressLint("NewApi") public class savewords extends Activity implements OnTouchListener {
OurView v;
//Intent secondintent;
Canvas c;
int cheight,cwidth,loop=0;
Bitmap notalk,notalkscaled,bittalk;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
v=new OurView(this);
v.setOnTouchListener(this);
//Remove title bar
requestWindowFeature(Window.FEATURE_NO_TITLE);
//Remove notification bar
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(v);
notalk=BitmapFactory.decodeResource(getResources(), R.drawable.nottalk);
// bittalk=BitmapFactory.decodeResource(getResources(), R.drawable.talkmid);
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
v.pause();
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
v.resume();
}
public class OurView extends SurfaceView implements Runnable {
Thread t=null;
SurfaceHolder holder;
boolean isItOK=false;
public OurView(Context context) {
super(context);
// TODO Auto-generated constructor stub
holder=getHolder();
}
public void run(){
while(isItOK){
if(!holder.getSurface().isValid()){
continue;
}
c=holder.lockCanvas();
cheight=c.getHeight();
cwidth=c.getWidth();
scale();
drawing(c);
holder.unlockCanvasAndPost(c);
}
}
private void scale() {
// TODO Auto-generated method stub
if(loop==0)
notalkscaled=Bitmap.createScaledBitmap(notalk,(int)(cwidth),(int)(cheight), false);
}
protected void drawing(Canvas canvas){
//canvas.drawARGB(255, 255, 255, 255);
canvas.drawBitmap(notalkscaled,0,0, null);
if(loop>500){
loop=0;
wannalearnaword();
}
loop++;
}
private void wannalearnaword() {
// TODO Auto-generated method stub
//1st activity
Intent secondintent = new Intent(getApplicationContext(), discoverstring.class);
secondintent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(secondintent);
}
public void pause(){
isItOK=false;
while(true){
try {
t.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
t=null;
}
public void resume(){
isItOK=true;
t=new Thread(this);
t.start();
}
}
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
switch(event.getAction())
{
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_MOVE:
break;
}
return true;
}
}

first activity view does not appear

I am new to android. I have two activities Splash and MainActivity. When I launch my application the Splash activity starts(as its supposed to be), it plays the sound but the background image does not appear and some seconds later my MainActivity starts. Thanks in advance!
code for MainActivity class
Package com.example.button;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
int counter;
Button add;
Button sub;
TextView display;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
counter=0;
add=(Button)findViewById(R.id.button1);
sub=(Button)findViewById(R.id.button2);
display=(TextView)findViewById(R.id.textView1);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void add(View view)
{
counter=counter+1;
display.setText("your total is"+counter);
}
public void sub(View view)
{
counter--;
display.setText("your total is"+counter);
}
}
code for Splash class
package com.example.button;
import android.app.Activity;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Bundle;
public class Splash extends Activity{
MediaPlayer ourSong;
Thread timer;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
ourSong=MediaPlayer.create(Splash.this,R.raw.addicted);
ourSong.start();
timer=new Thread();
timer.start();
run();
//{
//};
}
public void run()
{
try {
timer.sleep(5000);
}catch(InterruptedException e){
e.printStackTrace();
}finally {
Intent openStartingPoint=new Intent("com.example.button.MAINACTIVITY");
startActivity(openStartingPoint);
}
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
ourSong.release();
}
}
code for splash.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#drawable/feather">
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
</LinearLayout>
I think you have not correctly used Thread. change these three lines of your code
timer=new Thread();
timer.start();
run();
to
timer=new Thread(new Runnable(){
public void run() {
try {
sleep(5000);
}catch(InterruptedException e){
e.printStackTrace();
}finally {
Intent openStartingPoint=new Intent("com.example.button.MAINACTIVITY");
startActivity(openStartingPoint);
}
}
});
timer.start();
and remove run method from your activity.
by this way you let the splash activity to appear for 5 seconds on screen.
in your splash.xml take a imageview and put your image file there.
e.g android:src="file.gif"
hope this helps you`
use this code as your splash activity:
public class SplashActivity extends Activity {
int SPLASH_DISPLAY_LENGHT = 1000;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.splash_form);
InitilizeUi();
}
private void InitilizeUi() {
// play your sound
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Intent mainIntent = new Intent(SplashActivity.this, AboutActivity.class);
SplashActivity.this.startActivity(mainIntent);
SplashActivity.this.finish();
}
}, SPLASH_DISPLAY_LENGHT);
}
}

Android programming on text views [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
can anybody help me ? I want to embed this block of code in my program but I dont know where to place it and I think it is an error for working with textViews in android
final TextView img1 = (TextView)findViewById(R.id.img1);
final TextView img2 = (TextView)findViewById(R.id.img2);
btnV.setOnClickListener( new OnClickListener(){
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
img1.setText(btnV.getText());
}
img1.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
img1.setText("");
}
});
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView img1 = (TextView)findViewById(R.id.img1);
TextView img2 = (TextView)findViewById(R.id.img2);
final Button btnV = (Button)findViewById(R.id.btn1);
btnV.setOnClickListener( new OnClickListener(){
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
img1.setText(btnV.getText());
}
});
img1.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
img1.setText("");
}
});
}
}
<TextView
android:id="#+id/img1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="img1" />
<TextView
android:id="#+id/img2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="img2" />
<Button
android:id="#+id/btn1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="btn1" />
use OnFocusChangeListener:
img1.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
img2.setText("");
}
});

App Crashing on intent start with google maps

Java code for map activity
package com.schweigert.drinkingbuddy;
import android.app.Activity;
import android.os.Bundle;
public class BarMaps extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.barmaps);
}
}
XML Code
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.google.android.gms.maps.MapFragment" >
</fragment>
Java code that starts intent
maps.setOnClickListener(new Button.OnClickListener(){
#Override
public void onClick(View v) {
Intent openMap = new Intent("com.schweigert.drinkingbuddy.BarMaps");
startActivity(openMap);
}
});
When i am running this code on my emulator i have set up on my computer it brings up the "This app wont run unless you update Google Play services. But when i run it on a physical device it just times out and says that the app has stopped working.Why am i getting such a difference in errors between my emulator and physical device?
Edit:
package com.schweigert.drinkingbuddy;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.EditText;
public class StartingPoint extends Activity {
double numDrinks;
int counter;
EditText standardDrinks;
Button bacIntent, maps, drinks;
TextView display;
Bundle testBundle;
#Override
protected void onCreate(Bundle testBundle) {
super.onCreate(testBundle);
setContentView(R.layout.activity_starting_point);
counter = 0;
bacIntent = (Button) findViewById(R.id.bacIntent);
maps = (Button) findViewById(R.id.Maps);
drinks = (Button) findViewById(R.id.drinks);
bacIntent.setOnClickListener(new Button.OnClickListener(){
#Override
public void onClick(View v){
try{
Intent openBac = new Intent("com.schweigert.drinkingbuddy.BloodAlcoholContent");
startActivity(openBac);
}
catch(Exception e)
{
display.setText("my d" + e);
}
}
});
maps.setOnClickListener(new Button.OnClickListener(){
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
try{
Intent openMap = new Intent("com.schweigert.drinkingbuddy.MainActivity");
startActivity(openMap);
}
catch(Exception e){
display.setText("my d"+ e);
}
}
});
drinks.setOnClickListener(new Button.OnClickListener(){
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
try{
Intent openDrinkMenu = new Intent("com.schweigert.drinkingbuddy.DrinkType");
startActivity(openDrinkMenu);
}
catch(Exception e){
display.setText("my d:" + e);
}
}
});
}
}
So i had a try catch that was interacting with a textview that didn't exist anymore and then i had my manifest set up incorrectly. Thanks for the help Shivan.

how to link the class shown below with main activity

here is the code of the class which i created which extends MainActivity and how can i call this from MainActivity?
I'm trying to figure out where I went wrong on referencing my surface view class, not my view. I only did the view as an example. Here is my main class:
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnTouchListener;
public class SurfaceViewExample extends Activity implements OnTouchListener{
OurView v;
Bitmap ball;
float x,y;
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
v=new OurView(this);
v.setOnTouchListener(this);
ball=BitmapFactory.decodeResource(getResources(),R.drawable.tennis_ball);
x = y = 0;
setContentView(v);
}
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
v.resume();
}
public class OurView extends SurfaceView implements Runnable{
Thread t;
SurfaceHolder holder;
boolean isItOk=false;
public OurView(Context context) {
super(context);
// TODO Auto-generated constructor stub
holder=getHolder();
}
public void run() {
// TODO Auto-generated method stub
while( isItOk ==true)
{
//drawing
if(holder.getSurface().isValid()) {
continue;
}
Canvas c=holder.lockCanvas();
c.drawARGB(255,150,150,10);
c.drawBitmap(ball, x+(ball.getWidth()/4), y+(ball.getHeight()), null);
holder.unlockCanvasAndPost(c);
}
}
public void pause()
{
isItOk=false;
while(true) {
try {
t.join();
}catch(InterruptedException e) {
e.printStackTrace();
}
break;
}
}
public void resume()
{
isItOk=true;
t=new Thread(this);
t.start();
}
}
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
return false;
}
}
The much i got is that you want to go SurfaceViewExample from your main activity for that you need to use intent on button click like
Intent i = new Intent(this, SurfaceViewExample.class);
startActivity(i) ;
and you have to add a permission in menifest to got to that activity like
<activity android:enabled="true" android:name="SurfaceViewExample" />
and you can see these links also
Calling one Activity from another in Android
http://developer.android.com/reference/android/content/Intent.html

Categories