Please scroll down to the "EDIT" :)
I'm trying to understand some basic android animation programming using Android Studio, and I have followed some tutorials on the internet.
I already know some basic java programming, but I have a problem with my "copy/paste app" I made.
This is my MainActivity:
public class MainActivity extends ActionBarActivity {
private Button play;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
play = (Button) findViewById(R.id.play_button);
play.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent startGame = new Intent("com.abc.test.DRAWGAME2");
startActivity(startGame);
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}}
This is DrawGame2.java:
public class DrawGame2 extends Activity implements View.OnTouchListener {
private MyView surfaceView;
private float y;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
surfaceView = new MyView(this);
surfaceView.setOnTouchListener(this);
setContentView(surfaceView);
}
#Override
protected void onPause() {
super.onPause();
surfaceView.pause();
}
#Override
protected void onResume() {
super.onResume();
surfaceView.resume();
}
#Override
public boolean onTouch(View v, MotionEvent me) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
switch (me.getAction()){
case MotionEvent.ACTION_DOWN:
y = me.getY();
break;
case MotionEvent.ACTION_UP:
y = me.getY();
break;
case MotionEvent.ACTION_MOVE:
y = me.getY();
break;
}
return true;
}
public class MyView extends SurfaceView implements Runnable {
private Thread thread = null;
private SurfaceHolder holder;
private boolean isRunning = false;
public MyView(Context context) {
super(context);
holder = getHolder();
y = 0;
}
public void run() {
while (isRunning) {
if (!holder.getSurface().isValid()) {
continue;
}
Canvas canvas = holder.lockCanvas();
canvas.drawRGB(02,02,150);
if (y != 0){
Bitmap test = BitmapFactory.decodeResource(getResources(),R.drawable.greenball);
canvas.drawBitmap(test, canvas.getWidth()/2 - test.getWidth()/2, y, null);
}
holder.unlockCanvasAndPost(canvas);
}
}
public void pause() {
isRunning = false;
while (true) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
thread = null;
}
public void resume() {
isRunning = true;
thread = new Thread(this);
thread.start();
}
}}
Logcat:
02-12 11:01:06.676 1972-1972/com.abc.test I/art﹕ Not late-enabling -Xcheck:jni (already on)
02-12 11:01:06.881 1972-1990/com.abc.test D/OpenGLRenderer﹕ Render dirty regions requested: true
02-12 11:01:06.882 1972-1972/com.abc.test D/﹕ HostConnection::get() New Host Connection established 0xa686fb60, tid 1972
02-12 11:01:06.917 1972-1972/com.abc.test D/Atlas﹕ Validating map...
02-12 11:01:07.007 1972-1990/com.abc.test D/﹕ HostConnection::get() New Host Connection established 0xa686fd90, tid 1990
02-12 11:01:07.037 1972-1990/com.abc.test I/OpenGLRenderer﹕ Initialized EGL, version 1.4
02-12 11:01:07.102 1972-1990/com.abc.test D/OpenGLRenderer﹕ Enabling debug mode 0
02-12 11:01:07.126 1972-1990/com.abc.test W/EGL_emulation﹕ eglSurfaceAttrib not implemented
02-12 11:01:07.126 1972-1990/com.abc.test W/OpenGLRenderer﹕ Failed to set EGL_SWAP_BEHAVIOR on surface 0xa6814940, error=EGL_SUCCESS
02-12 11:01:07.705 1972-1990/com.abc.test W/EGL_emulation﹕ eglSurfaceAttrib not implemented
02-12 11:01:07.705 1972-1990/com.abc.test W/OpenGLRenderer﹕ Failed to set EGL_SWAP_BEHAVIOR on surface 0xa6814940, error=EGL_SUCCESS
02-12 11:01:12.571 1972-1990/com.abc.test W/EGL_emulation﹕ eglSurfaceAttrib not implemented
02-12 11:01:12.571 1972-1990/com.abc.test W/OpenGLRenderer﹕ Failed to set EGL_SWAP_BEHAVIOR on surface 0xa5a69ba0, error=EGL_SUCCESS
02-12 11:01:16.892 1972-1972/com.abc.test I/Choreographer﹕ Skipped 263 frames! The application may be doing too much work on its main thread.
02-12 11:01:16.899 1972-2270/com.abc.test D/﹕ HostConnection::get() New Host Connection established 0xa5dfcc10, tid 2270
The problem with this app is that the animation is really laggy, and I can't figure out why!
I have tried to make the same animation with a simple rectangle, but the lag is still there.
The problem isn't the OnTouchListener, because I've tried to just increase the y value by 1 with each loop in the run method (while disabling the OnTouchListener), but it is still lagging.
I have tried with different emulators (Lollipop, Kitkat) and on my Samsung Galaxy S3 (Jelly Bean).
Are there any wise people out there that can help me with this problem? :)
Have a great day!
EDIT:
Okay, so I applied the answers I got, and now it runs smoothly, ON MY Samung Galaxy S3!
The lagging is still there on my emulator though. I've installed HAXM and the emulator runs smoothly out of the app I've created, but as soon as I launch the app and press the "PLAY" button, the animation lags when I interact with the app.
This is the properties for my emulator:
Name: Nexus_5_API_21
CPU/ABI: Intel Atom (x86)
hw.gpu.enabled: yes
Path: C:\Users\User\.android\avd\Nexus_5_API_21.avd
Target: Android 5.0.1 (API level 21)
Skin: nexus_5
SD Card: 100M
Snapshot: no
hw.lcd.density: 480
hw.dPad: no
avd.ini.encoding: UTF-8
hw.camera.back: none
disk.dataPartition.size: 200M
runtime.network.latency: none
skin.dynamic: no
hw.keyboard: yes
runtime.network.speed: full
hw.device.hash2: MD5:2fa0e16c8cceb7d385183284107c0c88
hw.ramSize: 1536
tag.id: default
tag.display: Default
hw.sdCard: yes
hw.device.manufacturer: Google
hw.mainKeys: no
hw.accelerometer: yes
hw.trackBall: no
hw.device.name: Nexus 5
hw.sensors.proximity: yes
hw.battery: yes
AvdId: Nexus_5_API_21
hw.sensors.orientation: yes
hw.audioInput: yes
hw.camera.front: none
hw.gps: yes
avd.ini.displayname: Nexus 5 API 21
snapshot.present: no
vm.heapSize: 64
runtime.scalefactor: auto
As far as I can see, your problem is in the onTouch() method, in which you have this code:
try{
Thread.sleep(50);
}catch (InterruptedException e){
e.printStackTrace();
}
Which will sleep the MAIN thread, meaning that everything will make the entire application hold up for 50 milliseconds.
So try to remove that.
Decoding resources are also not performance friendly. You should decode bitmap earlier and reuse it while drawing. Why you do not use onDraw method ?
Related
I'm creating a screen lock app, and faced notification able to drag down in the lock screen.
I've research it and found this solution to block the notification bar by using addView code below, but I cannot remove the view after user unlocked my app. Please advice how to remove the view.
I've try to use manager.removeView(view); in public void onDestroy() { but it crashed after run this code.
This is the error message
FATAL EXCEPTION: main
Process: com.mehuljoisar.lockscreen, PID: 10256
java.lang.IllegalArgumentException: View=android.view.View{42348cc0 V.ED.... ........ 0,0-0,0} not attached to window manager
at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:373)
at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:302)
at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:79)
at com.mehuljoisar.lockscreen.LockScreenActivity.disablePullNotificationTouch(LockScreenActivity.java:261)
at com.mehuljoisar.lockscreen.LockScreenActivity.access$100(LockScreenActivity.java:24)
at com.mehuljoisar.lockscreen.LockScreenActivity$2.onClick(LockScreenActivity.java:113)
at android.view.View.performClick(View.java:4469)
at android.view.View$PerformClick.run(View.java:18788)
at android.os.Handler.handleCallback(Handler.java:808)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:5347)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:835)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:651)
at dalvik.system.NativeStart.main(Native Method)
Where should I put the removeView code?
private void disablePullNotificationTouch(String gg) {
WindowManager manager = ((WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE));
WindowManager.LayoutParams localLayoutParams = new WindowManager.LayoutParams();
localLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
localLayoutParams.gravity = Gravity.TOP; //make the line top
localLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
// this is to enable the notification to recieve touch events
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
// Draws over status bar
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
localLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
localLayoutParams.height = (int) (25 * getResources().getDisplayMetrics().scaledDensity);
localLayoutParams.format = PixelFormat.RGBX_8888;
View view = new View(this);
if(gg == "on") {
manager.addView(view, localLayoutParams);
}else {
manager.removeView(view);
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
disablePullNotificationTouch("on");
}
#Override
public void onDestroy() {
super.onDestroy();
disablePullNotificationTouch("off");
}
You use
WindowManager manager = ((WindowManager) this.getSystemService(Context.WINDOW_SERVICE));
Not use
WindowManager manager = ((WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE));
Try it!
I'm trying to send an ArrayList to my Android Wear device from the mobile device.
Unfortunately I'm not getting past the mGoogleApiClient.connect() as per my sop statements.
What I've done is set up a DataLayer item and used the onDataChanged() to monitor the code and the DataItem being sent with it, but unfortunately it seems like nothing is getting across.
Console output is at the bottom of the post, if that helps pinpoint anything.
MAIN ACTIVITY - MOBILE
public class MainActivity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
Set<String> tasksSet;
ArrayList<String> actsList;
ArrayAdapter adapter;
ListView list;
GoogleApiClient mGoogleApiClient;
#Override
protected void onCreate(Bundle savedInstanceState) {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(Wearable.API)
.build();
mGoogleApiClient.connect();
if(!PreferenceManager.getDefaultSharedPreferences(this)
.getStringSet("wristaroo", new HashSet<String>()).isEmpty()) {
tasksSet = PreferenceManager.getDefaultSharedPreferences(this)
.getStringSet("wristaroo", new HashSet<String>());
actsList = new ArrayList<String>(tasksSet);
}
else {
actsList = new ArrayList<>();
Set<String> tasksSet = new HashSet<>(actsList);
PreferenceManager.getDefaultSharedPreferences(this)
.edit()
.putStringSet("wristaroo", tasksSet)
.commit();
}
xxxxxxx
other populating code
xxxxxxx
Button btnSend = (Button) findViewById(R.id.sendButton);
btnSend.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
sendCustomSchedule(actsList);
System.out.println("Button Pressed: Send");
}
});
}
private void populateListView() {
list = (ListView) findViewById(R.id.listViewAdd);
list.setAdapter(adapter);
}
public MainActivity getActivity() {
return this;
}
#Override
public void onConnected(#Nullable Bundle bundle) {
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
public void sendCustomSchedule(ArrayList<String> customSchedule) {
PutDataMapRequest putDataMapRequest = PutDataMapRequest.create("/customSched");
putDataMapRequest.getDataMap().putStringArrayList("customSched", customSchedule);
PutDataRequest request = putDataMapRequest.asPutDataRequest().setUrgent();
Wearable.DataApi.putDataItem(mGoogleApiClient, request)
.setResultCallback(new ResultCallback<DataApi.DataItemResult>() {
#Override
public void onResult(#NonNull DataApi.DataItemResult dataItemResult) {
if(!dataItemResult.getStatus().isSuccess()) {
System.out.println("Apparent Failure!");
} else {
System.out.println("Apparent Success!");
}
}
});
System.out.println("When in doubt...");
}
}
MAIN ACTIVITY - WEAR
public class byTimeActivity extends Activity implements DataApi.DataListener,GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
ArrayList<String> choicesList;
ArrayAdapter adapter;
ListView list;
ArrayList<String> data;
String dayExtra;
String howExtra;
String schedExtra;
GoogleApiClient mGoogleApiClient;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(Wearable.API)
.build();
mGoogleApiClient.connect();
setContentView(R.layout.activity_main);
final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
dayExtra = getIntent().getExtras().getString("dayExtra");
schedExtra = getIntent().getExtras().getString("schedExtra");
howExtra = getIntent().getExtras().getString("howExtra");
System.out.println("dayExtra: " + dayExtra);
System.out.println("schedExtra: " + schedExtra);
System.out.println("howExtra: " + howExtra);
switch(dayExtra) {
case "Thursday":
if(schedExtra.equals("Full Schedule")) {
setStage(thTime);
}
if(schedExtra.equals("Custom Schedule")) {
adapter = new ArrayAdapter<>(this, R.layout.da_item, data);
}
break;
case "Friday":
setStage(frTime);
break;
case "Saturday":
setStage(saTime);
break;
case "Sunday":
setStage(suTime);
break;
}
stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
#Override
public void onLayoutInflated(WatchViewStub stub) {
list = (ListView) findViewById(R.id.mainChoiceList);
list.setAdapter(adapter);
}
});
}
private void setStage(String[] dayStage) {
choicesList = new ArrayList<>(Arrays.asList(dayStage));
adapter = new ArrayAdapter<>(this, R.layout.da_item, choicesList);
adapter.notifyDataSetChanged();
}
#Override
protected void onResume() {
super.onResume();
mGoogleApiClient.connect();
}
#Override
public void onConnected(#Nullable Bundle bundle) {
Wearable.DataApi.addListener(mGoogleApiClient, this);
}
#Override
protected void onPause() {
super.onPause();
Wearable.DataApi.removeListener(mGoogleApiClient, this);
mGoogleApiClient.disconnect();
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onDataChanged(DataEventBuffer dataEvents) {
for (DataEvent event : dataEvents) {
if (event.getType() == DataEvent.TYPE_CHANGED) {
DataItem item = event.getDataItem();
if (item.getUri().getPath().compareTo("/customSched") == 0) {
DataMap dataMap = DataMapItem.fromDataItem(item).getDataMap();
data = dataMap.getStringArrayList("customSched");
System.out.println("Data: " + data);
}
} else if (event.getType() == DataEvent.TYPE_DELETED) {
//dataItem Deleted
}
}
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
}
CONSOLE OUTPUT - MOBILE
W/System: ClassLoader referenced unknown path: /data/app/com.michaeldvinci.conedmiro.schedaroo-2/lib/arm
I/GMPM: App measurement is starting up, version: 8487
I/GMPM: To enable debug logging run: adb shell setprop log.tag.GMPM VERBOSE
E/GMPM: GoogleService failed to initialize, status: 10, Missing an expected resource: 'R.string.google_app_id' for initializing Google services. Possible causes are missing google-services.json or com.google.gms.google-services gradle plugin.
E/GMPM: Scheduler not set. Not logging error/warn.
E/GMPM: Uploading is not possible. App measurement disabled
D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
I/Adreno200-EGL: <qeglDrvAPI_eglInitialize:265>: EGL 1.4 QUALCOMM build: AU_LINUX_ANDROID_JB_2.5.5.04.02.02.092.059_msm8960_JB_2.5.5_CL3896081_release_AU (CL3896081)
Build Date: 06/25/13 Tue
Local Branch:
Remote Branch: quic/jb_2.5.5
Local Patches: NONE
Reconstruct Branch: AU_LINUX_ANDROID_JB_2.5.5.04.02.02.092.059 + NOTHING
I/OpenGLRenderer: Initialized EGL, version 1.4
W/art: Before Android 4.1, method int android.support.v7.widget.ListViewCompat.lookForSelectablePosition(int, boolean) would have incorrectly overridden the package-private method in android.widget.ListView
I/System.out: When in doubt...
I/System.out: Button Pressed: Send
I/System.out: Apparent Success!
CONSOLE OUTPUT - WEAR
W/art: Suspending all threads took: 17.121ms
I/art: Background sticky concurrent mark sweep GC freed 1601(90KB) AllocSpace objects, 0(0B) LOS objects, 23% free, 508KB/663KB, paused 20.603ms total 53.990ms
W/art: Suspending all threads took: 5.855ms
I/art: Background partial concurrent mark sweep GC freed 168(48KB) AllocSpace objects, 0(0B) LOS objects, 45% free, 611KB/1123KB, paused 8.179ms total 61.166ms
I/System.out: mGoogleApiClient connected!
W/GooglePlayServicesUtil: Google Play services out of date. Requires 8487000 but found 8299574
D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
[ 04-03 23:16:13.428 15148:15148 D/ ]
HostConnection::get() New Host Connection established 0xb3edca60, tid 15148
D/Atlas: Validating map...
I/OpenGLRenderer: Initialized EGL, version 1.4
D/OpenGLRenderer: Enabling debug mode 0
W/EGL_emulation: eglSurfaceAttrib not implemented
W/OpenGLRenderer: Failed to set EGL_SWAP_BEHAVIOR on surface 0xb3f625e0, error=EGL_SUCCESS
I/System.out: mGoogleApiClient disconnected! //dis/connecting in MainActivity, before switching activities
W/EGL_emulation: eglSurfaceAttrib not implemented
W/OpenGLRenderer: Failed to set EGL_SWAP_BEHAVIOR on surface 0xb3f628a0, error=EGL_SUCCESS
W/EGL_emulation: eglSurfaceAttrib not implemented
W/OpenGLRenderer: Failed to set EGL_SWAP_BEHAVIOR on surface 0xb3f62700, error=EGL_SUCCESS
I/System.out: schedExtra: Custom Schedule
I/System.out: dayExtra: Thursday
I/System.out: howExtra: By Time
I/System.out: dayExtra: Thursday
I/System.out: schedExtra: Custom Schedule
I/System.out: howExtra: By Time
I/System.out: mGoogleApiClient connected!
D/AndroidRuntime: Shutting down VM
--------- beginning of crash
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.michaeldvinci.conedmiro.schedaroo, PID: 15148
java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference
W/GooglePlayServicesUtil: Google Play services out of date. Requires 8487000 but found 8299574
WearableListenerService is required REGARDLESS
only briefly mentioned in the documentation [which should definitely be updated]
I've been struggling with this exception and I've looked around but there's nothing to help me.
Here's the code
package com.example.surfacetest;
import android.app.Activity;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class BoardSurfaceActivity extends Activity {
/** Called when the activity is first created. */
private static final String TAG = BoardSurfaceActivity.class.getSimpleName();
private BoardSurface bS;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bS = new BoardSurface(this);
setContentView(bS);
Log.d(TAG, "View added");
}
#Override
protected void onDestroy() {
Log.d(TAG, "Destroying...");
super.onDestroy();
}
#Override
protected void onStop() {
Log.d(TAG, "Stopping...");
super.onStop();
}
#Override
protected void onRestart() {
// TODO Auto-generated method stub
super.onRestart();
}
#Override
protected void onPause() {
Log.d(TAG, "Pausing...");
super.onPause();
}
#Override
protected void onResume() {
Log.d(TAG, "Resuming...");
super.onResume();
}
public class BoardSurface extends SurfaceView implements SurfaceHolder.Callback, Runnable {
final String TAG = BoardSurface.class.getSimpleName();
private Stuff stuff;
Thread t = null;
SurfaceHolder holder;
boolean isItOk = false;
public BoardSurface(Context context) {
super(context);
holder = getHolder();
getHolder().addCallback(this);
stuff = new Stuff(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher), 50, 50);
t = new Thread(this);
setFocusable(true);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
Log.d(TAG, "Surface created");
resume();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d(TAG, "Surface Destroyed");
pause();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
// delegating event handling to the droid
stuff.handleActionDown((int) event.getX(), (int) event.getY());
// check if in the lower part of the screen we exit
if (event.getY() > getHeight() - 50) {
((Activity) getContext()).finish();
} else {
Log.d(TAG, "Coords: x=" + event.getX() + ",y=" + event.getY());
}
}
if (event.getAction() == MotionEvent.ACTION_MOVE) {
// the gestures
if (stuff.isTouched()) {
// the droid was picked up and is being dragged
stuff.setX((int) event.getX());
stuff.setY((int) event.getY());
}
}
if (event.getAction() == MotionEvent.ACTION_UP) {
// touch was released
if (stuff.isTouched()) {
stuff.setTouched(false);
}
}
return true;
}
public void draw(Canvas canvas) {
canvas.drawColor(Color.BLUE);
stuff.draw(canvas);
}
#Override
public void run() {
while (isItOk) {
holder = getHolder();
if (holder.getSurface().isValid()) {
Canvas c = null;
try {
// make sure holder is updated
c = holder.lockCanvas(null);
if (c != null) {
synchronized (holder) {
draw(c);
}
}
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (c != null) {
holder.unlockCanvasAndPost(c);
}
}
}
}
}
public void pause() {
isItOk = false;
while (true) {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
t = null;
}
public void resume() {
if (t.getState() == Thread.State.TERMINATED) {
t = new Thread(this);
isItOk = true;
t.start();
} else {
isItOk = true;
t.start();
}
}
}
}
What is super strange is that I have this trace :
10-22 08:54:41.153: D/BoardSurface(17298): Surface created
10-22 08:54:41.394: E/memalloc(17298): /dev/pmem: Failed to map buffer size:24641536 offset:23699456 fd:56 Error: Invalid argument
10-22 08:54:41.394: E/gralloc(17298): Could not mmap handle 0x89e2b8, fd=56 (Invalid argument)
10-22 08:54:41.394: E/gralloc(17298): gralloc_register_buffer: gralloc_map failed
10-22 08:54:41.394: W/GraphicBufferMapper(17298): registerBuffer(0x89e2b8) failed -22 (Invalid argument)
10-22 08:54:41.394: E/GraphicBuffer(17298): unflatten: registerBuffer failed: Invalid argument (-22)
10-22 08:54:41.394: E/memalloc(17298): /dev/pmem: Failed to map buffer size:24641536 offset:23699456 fd:56 Error: Invalid argument
10-22 08:54:41.394: E/gralloc(17298): Could not mmap handle 0x89e2b8, fd=56 (Invalid argument)
10-22 08:54:41.394: E/libgenlock(17298): perform_lock_unlock_operation: GENLOCK_IOC_DREADLOCK failed (lockType0x1,err=Bad file number fd=56)
10-22 08:54:41.394: E/gralloc(17298): gralloc_lock: genlock_lock_buffer (lockType=0x2) failed
10-22 08:54:41.394: W/GraphicBufferMapper(17298): lock(...) failed -22 (Invalid argument)
10-22 08:54:41.394: W/Surface(17298): failed locking buffer (handle = 0x89e2b8)
10-22 08:54:41.424: E/SurfaceHolder(17298): Exception locking surface
10-22 08:54:41.424: E/SurfaceHolder(17298): java.lang.IllegalArgumentException
10-22 08:54:41.424: E/SurfaceHolder(17298): at android.view.Surface.nativeLockCanvas(Native Method)
10-22 08:54:41.424: E/SurfaceHolder(17298): at android.view.Surface.lockCanvas(Surface.java:236)
10-22 08:54:41.424: E/SurfaceHolder(17298): at android.view.SurfaceView$4.internalLockCanvas(SurfaceView.java:807)
10-22 08:54:41.424: E/SurfaceHolder(17298): at android.view.SurfaceView$4.lockCanvas(SurfaceView.java:787)
10-22 08:54:41.424: E/SurfaceHolder(17298): at com.example.surfacetest.BoardSurfaceActivity$BoardSurface.run(BoardSurfaceActivity.java:137)
10-22 08:54:41.424: E/SurfaceHolder(17298): at java.lang.Thread.run(Thread.java:841)
in my running loop.
But here's the tricky part ! When I press back (not HOME) then start the app from the menu again. It just simply works.
So I really don't know what I'm missing.
Additional info : I'm running on a HTC Sensation XE, CM 10.2 (Android 4.3.1)
EDIT:
The device is not the issue here. Tried with another HTC on stock ROM.
EDIT 2 :
Even though I check :
if (holder.getSurface().isValid())
Which is specifically saying that lockcanvas() will succeed if it is true, I get this exception
10-22 10:11:27.688: E/SurfaceHolder(22195): Exception locking surface
10-22 10:11:27.688: E/SurfaceHolder(22195): java.lang.IllegalArgumentException
10-22 10:11:27.688: E/SurfaceHolder(22195): at android.view.Surface.nativeLockCanvas(Native Method)
10-22 10:11:27.688: E/SurfaceHolder(22195): at android.view.Surface.lockCanvas(Surface.java:236)
10-22 10:11:27.688: E/SurfaceHolder(22195): at android.view.SurfaceView$4.internalLockCanvas(SurfaceView.java:807)
10-22 10:11:27.688: E/SurfaceHolder(22195): at android.view.SurfaceView$4.lockCanvas(SurfaceView.java:787)
10-22 10:11:27.688: E/SurfaceHolder(22195): at com.example.surfacetest.BoardSurfaceActivity$BoardSurface.run(BoardSurfaceActivity.java:144)
10-22 10:11:27.688: E/SurfaceHolder(22195): at java.lang.Thread.run(Thread.java:841)
EDIT 3 :
Works on Galaxy S4 Stock ROM and Emulator Intelx86 4.2.2
#CinetiK: Post the rest of your stacktrace.
HTC devices are notorious when it comes to rotation and surface tests. Have you tried this:
Restart your phone.
Go to Safe mode (i.e. restart the phone and when you see the HTC logo, long press Volume down button). The phone will restart again and go into Safe mode.
Once phone is in Safe mode, go to Settings | Display & Gestures | G-Sensor Calibration. Then, calibrate your phone while ensuring your phone rests on a flat surface. Once calibration is successfully completed, restart the phone in normal mode.
If the above steps still do not fix the error, and since you're using CM 10.2, I would recommend testing your Android app on stock ROMs first. While I have nothing against custom Android ROMs (I used them myself), from experience I have had more unexplained errors on custom ROMs than stock ROMs. Try a stock ROM first and see if you still get the same error.
When testing several games with a standard game thread in Android 4.0 it works well until the Activity is shut down (pressing the home button etc), leaving the activity the application crashes with a nullPointer.
This even happens in the sample LunarLander that Google has programmed.
The problem is that Canvas becomes null when leaving the activity and that makes the application crash.
The error message from the LogCat is just below.
02-27 18:07:58.974: V/MainThread(2667): CANVAS android.view.Surface$CompatibleCanvas#4102bcf0
02-27 18:07:59.164: V/MainThread(2667): CANVAS null
02-27 18:07:59.164: W/dalvikvm(2667): threadid=14: thread exiting with uncaught exception (group=0x409c01f8)
02-27 18:07:59.174: E/AndroidRuntime(2667): FATAL EXCEPTION: Thread-108
02-27 18:07:59.174: E/AndroidRuntime(2667): java.lang.NullPointerException
02-27 18:07:59.174: E/AndroidRuntime(2667): at com.joakimengstrom.pong.MainThread.run(MainThread.java:49)
This is the code when starting a thread, with the Log.v you see above.
while(this.running){
canvas = null;
try {
canvas = this.surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
Log.v(TAG, "CANVAS " + canvas);
canvas.drawColor(Color.BLACK);
...
And below is when creating the thread and shutting it down when the surface is destroyed.
#Override
public void surfaceCreated(SurfaceHolder holder) {
thread = new MainThread(getHolder());
thread.setRunning(true);
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
thread.setRunning(false);
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
How do I exit the thread in a safe way without making canvas null?
In Android 4.0, SurfaceHolder.lockCanvas can return null when the surface is destroyed. So here:
try {
canvas = this.surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
Log.v(TAG, "CANVAS " + canvas);
canvas.drawColor(Color.BLACK);
Just surround your synchronized (surfaceHolder) block with if (canvas != null). This should not cause any issues with the behaviour of your application as it occurs when drawing is not needed.
I keep getting this black screen when ever I open my app, the only way to get rid of it is to press the back button, then again go to the app. I was told by my friend that it is going into deadlock! but I do not think because when I checked the logcat it shows the below log messages.
View
private boolean mGameIsRunning;
public void surfaceCreated(SurfaceHolder holder) {
// Your own start method.
start();
}
public void start() {
if (!mGameIsRunning) {
thread.initLevel();
thread.setRunning(true);
thread.start();
mGameIsRunning = true;
} else {
thread.onResume();
thread.initLevel();
thread.setRunning(true);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d(TAG, "Surface is being destroyed");
// tell the thread to shut down and wait for it to finish
// this is a clean shutdown
boolean retry = true;
thread.setRunning(false);
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Log.d(TAG, "Thread was shut down cleanly");
}
Thread
private Object mPauseLock = new Object();
private boolean mPaused;
#Override
public void run() {
Canvas canvas;
Log.d(TAG, "Starting game loop");
while (running) {
canvas = null;
// try locking the canvas for exclusive pixel editing
// in the surface
try {
canvas = this.mSurfaceHolder.lockCanvas();
synchronized (mSurfaceHolder) {
mStartTime = System.currentTimeMillis();
mElapsedTime = System.currentTimeMillis() - mStartTime;
this.updateGame();
this.onDraw(canvas);
}
synchronized(mPauseLock){
while (mPaused) {
try {
mPauseLock.wait();
} catch (InterruptedException e) {
}
}
}
} finally {
// in case of an exception the surface is not left in
// an inconsistent state
if (canvas != null) {
mSurfaceHolder.unlockCanvasAndPost(canvas);
}
} // end finally
}
}
public void onPause() {
synchronized (mPauseLock) {
mPaused = true;
}
}
public void onResume() {
synchronized (mPauseLock) {
mPaused = false;
mPauseLock.notifyAll();
}
}
Log
07-08 17:24:41.735: DEBUG/Hitman(3221): View added
07-08 17:24:41.895: DEBUG/(3221): Enemies Spawed
07-08 17:24:41.934: DEBUG/(3221): Starting game loop
07-08 17:24:42.165: INFO/ActivityManager(66): Displayed activity com.android.hitmanassault/.Hitman: 1384 ms (total 1384 ms)
07-08 17:24:46.164: DEBUG/(3221): Enemies Spawed
07-08 17:24:48.914: INFO/ActivityManager(66): Start proc com.android.settings for broadcast com.android.settings/.widget.SettingsAppWidgetProvider: pid=3228 uid=1000 gids={3002, 3001, 3003}
07-08 17:24:48.914: INFO/ActivityManager(66): Starting activity: Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10200000 cmp=com.android.launcher/.Launcher }
07-08 17:24:48.924: DEBUG/PhoneWindow(3221): couldn't save which view has focus because the focused view com.android.hitmanassault.HitmanView#44d99528 has no id.
07-08 17:24:48.954: INFO/WindowManager(66): Setting rotation to 0, animFlags=0
07-08 17:24:49.014: INFO/ActivityManager(66): Config changed: { scale=1.0 imsi=310/260 loc=en_US touch=3 keys=2/1/2 nav=3/1 orien=1 layout=34}
07-08 17:24:49.275: DEBUG/(3221): Surface is being destroyed
07-08 17:24:49.285: DEBUG/(3221): Thread was shut down cleanly
07-08 17:24:49.694: DEBUG/ddm-heap(3228): Got feature list request
07-08 17:24:49.754: WARN/IInputConnectionWrapper(3221): showStatusIcon on inactive InputConnection
07-08 17:24:51.315: DEBUG/dalvikvm(66): GC freed 2325 objects / 114696 bytes in 122ms
07-08 17:24:58.234: INFO/ActivityManager(66): Starting activity: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.android.hitmanassault/.HitmanTitle }
07-08 17:24:58.284: INFO/WindowManager(66): Setting rotation to 1, animFlags=0
07-08 17:24:58.354: INFO/ActivityManager(66): Config changed: { scale=1.0 imsi=310/260 loc=en_US touch=3 keys=2/1/2 nav=3/1 orien=2 layout=34}
07-08 17:24:58.554: DEBUG/(3221): Enemies Spawed
07-08 17:24:58.945: WARN/IInputConnectionWrapper(144): showStatusIcon on inactive InputConnection
07-08 17:25:00.604: DEBUG/dalvikvm(66): GC freed 1403 objects / 71832 bytes in 103ms
Activity Class:
#Override
public boolean onCreateOptionsMenu(Menu menu){
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.game_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item){
switch(item.getItemId()){
case R.id.menu_restart:
startActivity(new Intent(this, Hitman.class));
return true;
case R.id.menu_scores:
startActivity(new Intent(this, HitmanScores.class));
return true;
case R.id.menu_help:
startActivity(new Intent(this, HitmanHelp.class));
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new CanvasSurfaceView(this));
Log.d(TAG, "View added");
}
Does rotating the display cause it to refresh (in emulator: CTRL+F12)? If so then you have to override onResume() in your activity and have it restart whatever it is you set up that might not be being called. It could be that you just need to call view.invalidate() from the activity onResume()? You don't show code from your activity so I'm unsure.
In the code I saw, you should use this.postInvalidate() (same as invalidate() but for from a different thread) instead of this.onDraw(canvas) and have it call this.onDraw() on its own in the UI thread, as opposed to in your thread.
Where do you initialize your thread? Try doing so in surfaceCreated( ) instead of the surfaceView consturctor (which is where I think you did it..)
public void surfaceCreated(SurfaceHolder holder) {
// Restart draw thread
Thread.State state = thread.getState();
if(state == Thread.State.TERMINATED)
thread = new MyThread(getHolder(), getContext());
thread.setRunning(true);
thread.start();
}