I know this error is pretty common and I also know that I should just add the empty constructor like
public MainActivity(){
super("MainActivity");
but in my case it won't accept a string as an argument, so I don't really know what to pass... I'll show you my code which is taken from a Reto Meier example in Professional Android Development.
package com.virtualflyer.compass;
import...
public class MainActivity extends View {
public MainActivity(Context context){
super(context);
initCompassView();
}
public MainActivity(Context context, AttributeSet attrs){
super (context, attrs);
initCompassView();
}
public MainActivity(Context context,AttributeSet attrs,int defaultstyle){
super (context, attrs,defaultstyle);
initCompassView();
}
private Paint markerPaint;
private Paint textPaint;
private Paint circlePaint;
private String northString;
private String southString;
private String westString;
private String eastString;
private int textHeight;
protected void initCompassView(){
setFocusable(true);
Resources r=this.getResources();
circlePaint=new Paint (Paint.ANTI_ALIAS_FLAG);
circlePaint.setColor(r.getColor(R.color.background_color));
circlePaint.setStrokeWidth(1);
circlePaint.setStyle(Paint.Style.FILL_AND_STROKE);
northString=r.getString(R.string.cardinal_north);
southString=r.getString(R.string.cardinal_south);
eastString=r.getString(R.string.cardinal_east);
westString=r.getString(R.string.cardinal_west);
textPaint= new Paint (Paint.ANTI_ALIAS_FLAG);
textPaint.setColor(r.getColor(R.color.text_color));
textHeight=(int)textPaint.measureText("yY");
markerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
markerPaint.setColor(r.getColor(R.color.marker_color));
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
int measuredWidth=measure(widthMeasureSpec);
int measuredHeight=measure(heightMeasureSpec);
int d =Math.min(measuredWidth,measuredHeight);
setMeasuredDimension(d,d);
}
private int measure(int measureSpec){
int result=0;
int specMode=MeasureSpec.getMode(measureSpec);
int specSize=MeasureSpec.getSize(measureSpec);
if (specMode==MeasureSpec.UNSPECIFIED){
result=200;
} else {
result=specSize;
}
return result;
}
private float bearing;
public void setBearing (float _bearing){
bearing=_bearing;
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
}
public float getBearing(){
return bearing;
}
#Override
public boolean dispatchPopulateAccessibilityEvent(final AccessibilityEvent event){
super.dispatchPopulateAccessibilityEvent(event);
if (isShown()){
String bearingStr= String.valueOf(bearing);
if (bearingStr.length()>AccessibilityEvent.MAX_TEXT_LENGTH)
bearingStr=bearingStr.substring(0,AccessibilityEvent.MAX_TEXT_LENGTH);
event.getText().add(bearingStr);
return true;
}
else{
return false;
}
}
#Override
protected void onDraw(Canvas canvas){
int mMeasuredHeight=getMeasuredHeight();
int mMeasuredWidth=getMeasuredWidth();
int px= mMeasuredWidth/2;
int py=mMeasuredHeight/2;
int radius=Math.min(px,py);
canvas.drawCircle(px,py,radius,circlePaint);
canvas.save();
canvas.rotate(-bearing,px,py);
int textWidth=(int)textPaint.measureText("W");
int cardinalX=px-textWidth/2;
int cardinalY=py-radius+textHeight;
for (int i=0; i<24; i++){
canvas.drawLine(px,py-radius,px,py-radius+10,markerPaint);
canvas.save();
canvas.translate(0,textHeight);
if (i%6==0){
String dirString ="";
switch (i){
case(0) :{
dirString=northString;
int arrowY=2*textHeight;
canvas.drawLine(px,arrowY,px-5,3*textHeight,markerPaint);
break;
}
case(6) :dirString=eastString;break;
case(12) :dirString=southString;break;
case(18) :dirString=westString;break;
}
canvas.drawText(dirString, cardinalX,cardinalY,textPaint);
}
else if (i%3==0){
String angle =String.valueOf(i*15);
float angleTextWidth=textPaint.measureText(angle);
int angleTextX=(int) (px-angleTextWidth/2);
int angleTextY=(int) py-radius+textHeight;
canvas.drawText(angle,angleTextX,angleTextY,textPaint);
}
canvas.restore();
canvas.rotate(15,px,py);
}
canvas.restore();
}
}
I don't know what you are doing, but this might be the problem:
Why are you naming your class extended from View an Activity? If you have a MainActivity, you generally want to extend that from Activity class.
The problem might be there, that you declare in your manifest file that you have an Activity as MainActivity, but you don't because you extended that from View.
Here's what you do:
public class MainActivity extends Activity{ ... }
public class MyView extends View { /*insert your View code from above*/ }
and in MainActivity you might try
setContentView(new MyView(this));
And in the AndroidManifest you declare (I guess you had the same here or like it)
<activity
android:name=".MainActivity"
android:label="MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Related
I've been trying to find solution of this issue, but I haven't. The question is to return to Activity from View.
As soon as if statement become false, it should return me to SplashActivity
Here some Activities and View class, that perform all logic of application.
public class MainActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
GameEngine gameEngine = new GameEngine(this);
setContentView(gameEngine);
}
}
Then goes my SplashActivity with one ImageButton which call MainActivity as soon as it's pressed.
public class SplashActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
}
//this method mentioned (onClick) in XML file I've not included.
public void startGame(View view)
{
Intent mainIntent = new Intent(SplashActivity.this, MainActivity.class);
startActivity(mainIntent);
finish();
}
}
My View Class:
public class GameEngine extends View
{
boolean inGame;
//Here some code...
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
if(inGame)
{
canvas.drawBitmap(someImage, positionX, positionY, null);
if(positionX > 100)
{
inGame = false;
//Here I want to return to SplashActivity, where my ImageButton is!
}
}
}
}
I don't know how to implement idea of returning to Activity and begin using my app from innitial point.
Thanks in advance!
EDIT
This information is beside the point!
Innitialy I changed code for better readability to touch on the main point.
This is inner class where it's updating:
public static class Drawable
{
private int x;
private int y;
Drawable(int x, int y)
{
this.x = x;
this.y = y;
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
void update() {
x -= 3;
}
}
This is how myobjects actually draw
for (Drawable drawable : drawables)
{
//Draw upper pipe
canvas.drawBitmap(pipeUp, drawable.getX(), drawable.getY(), null);
//Draw lower pipe
canvas.drawBitmap(pipeBot, drawable.getX(), drawable.getY() +
pipeUp.getHeight() + GAP, null);
}
This is how it updates
private void animation()
{
for(Drawable drawable : new ArrayList<>(drawables))
{
drawable.update();
if(drawable.getX() == dWidth/3 + dWidth/3)
{
drawables.add(new Drawable(pipeX, (int)(Math.random() *
(pipeUp.getHeight() -((pipeUp.getHeight() * 0.25))) - (pipeUp.getHeight() - (pipeUp.getHeight() * 0.25)))));
}
if(drawable.getX() <= 0 - pipeBot.getWidth())
{
drawables.remove(drawable);
}
}
}
Then I call animation() in onDraw method.
You can try:
Intent mainIntent = new Intent(getContext(), SplashActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
getContext().startActivity(mainIntent);
or you can save reference of MainActivity in GameEngine's constructor and use it to open splash:
GameEngine gameEngine = new GameEngine(this);
or you can implement a livedata with a basic repository pattern:
public class DataRepository {
public static MutableLiveData<Boolean> openSplash = new MutableLiveData<>();
}
On MainActivity:
DataRepository.openSplash.observe(this, aBoolean -> {
if(aBoolean){
//open splash
}else{
//
}
});
On GameEngine:
DataRepository.openSplash.postValue(true);
This may be a very stupid question (which it's got like 99% chance it is) but I can't figure this out for the life of me. I've got a seekbar in one activity, we'll call it Activity 1, and I need to use it's constantly changing value (progress) in another activity, we'll call it Activity 2, for calculations (or maybe I can do the calculations in the first activity and then just send the value over to the second one, IDK which would be better).
So here's my Activity 1 code:
public class Painting extends Activity
{
SeekBar curveBar;
SampleView sampleView;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_painting);
curveBar = (SeekBar)findViewById(R.id.curveBar);
sampleView = new SampleView(this);
curveBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
int progressChangedValue = 0;
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (progress >= 50) //prints out 50, 60, 70, 80, 90, 100
{
progressChangedValue = progress;
}
else if (progress < 50) //prints out -40, -30, -20, -10, 0
{
progressChangedValue = (-1) * (progress);
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
Toast.makeText(Painting.this, "Value: " + progressChangedValue, Toast.LENGTH_SHORT).show();
}
});
}
}
and here's my RELEVANT Activity 2 code:
public class SampleView extends View
{
private Paint mPaint;
private float mX;
private float[] mPos;
private Path mPath;
private Paint mPathPaint;
private static final int DY = 30;
private static final String TEXTONPATH = "Along a path";
public SampleView(Context context, AttributeSet attrs)
{
super(context, attrs);
setFocusable(true);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setTextSize(90);
mPaint.setTypeface(Typeface.SERIF);
mPath = new Path();
makePath(mPath);
mPathPaint = new Paint();
mPathPaint.setAntiAlias(true);
mPathPaint.setColor(Color.rgb(255,0,0));
mPathPaint.setStyle(Paint.Style.STROKE);
}
public SampleView(Context context)
{
super(context);
setFocusable(true);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setTextSize(90);
mPaint.setTypeface(Typeface.SERIF);
mPath = new Path();
makePath(mPath);
mPathPaint = new Paint();
mPathPaint.setAntiAlias(true);
mPathPaint.setColor(Color.rgb(255,0,0));
mPathPaint.setStyle(Paint.Style.STROKE);
}
public void makePath(Path p) //<----- this is where i need the seekbar's value
//so that i can make this take more variables so that the seekbar
//adjusts the values in the p.cubicTo's below
{
// p.moveTo(250, -300);
p.moveTo(0,0);
// p.cubicTo(-250, -550, 750, -550, 250, -300);
p.cubicTo(0,-400,600,-400,600,0); //semi-circle?
// p.cubicTo(-600, -400, 600, -400, 0, 0); //as far as the curve probably should allow
// p.cubicTo(0, 0, 0, 0, 620,0); //flat line
}
I have tried to use curvebar.getProgress() on both the first activity and the second activity but I can't get it unless I'm within the OnSekbarChangeListener. I've tried setting public variables to the value but it only changes if i set the value within the listener, otherwise it doesn't (which makes perfect sense). I've tried setting the seekbar to be static (although I probably didn't do it right) and that didn't work either. I just can't figure out how i can get that value out and use it in the second file.
I would really appreciate some help
Thank you
Just create a public method in your SampleView class that can take the seekbar's progress as a parameter.
public class SampleView extends View {
...
public void updatePath(int seekBarProgress) {
// Do whatever you need to with the passed in value here.
}
...
}
Then in your Activity you can call this method to update the SampleView with the latest progress value.
public class Painting extends Activity {
...
curveBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
...
sampleView.updatePath(progress);
...
}
...
}
}
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 5 years ago.
I have been trying for some time now to get a variable from MySurfaceView to use in my Player class. I cant seem to make it work... I tried getting the touch information from my MainActivity class but it wasn't really where I wanted it and also couldn't seem to make it work. Any help is appreciated!
MySurfaceView.java
package com.Frenchie.SurfaceView;
import ...
public class MySurfaceView extends SurfaceView implements Runnable {
Bitmap bitmap;
SurfaceHolder surfaceHolder;
int LastTouchx;
Player player;
public MySurfaceView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
player = new Player(context);
surfaceHolder = getHolder();
//Starts the run()
Thread TestThread = new Thread(this);
TestThread.start();
}
#Override
public void run() {
//TODO movement here when display is working
while (true){
Update();
DrawPlayer();
}
}
public void Update(){
player.Update();
}
public void DrawPlayer(){
Canvas canvas = surfaceHolder.lockCanvas();
if (surfaceHolder.getSurface().isValid()) {
canvas.drawColor(Color.BLUE);
canvas.drawBitmap(player.getBitmap(), player.getX(), player.getY(), null);
surfaceHolder.unlockCanvasAndPost(canvas);
}
else{
Log.d("DrawPlayer", "Surface Not Valid");
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
LastTouchx = (int)event.getX();
//LastTouchy= (int)event.getY();
Log.d("Touch Value ",LastTouchx+"");
return false;
}
public int getLastTouchx() {
return LastTouchx;
}
}
Player.java
package com.Frenchie.SurfaceView;
import ...
public class Player {
//Bitmap to get character from image
private Bitmap bitmap;
//coordinates
private int x;
private int y;
//motion speed of the character
private int speed = 0;
MySurfaceView mySurfaceView;
//constructor
public Player(Context context) {
x = 75;
y = 500;
//Getting bitmap from drawable resource
bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.player);
}
//Method to update coordinate of character
public void Update(){
//updating x coordinate
if (x > mySurfaceView.getLastTouchx()){
x++;
}
else if (x < mySurfaceView.getLastTouchx()){
x--;
}
else{
Log.d("Update","Else triggered");
}
}
public Bitmap getBitmap() {
return bitmap;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
Messages
E/AndroidRuntime: FATAL EXCEPTION: Thread-4
Process: com.Frenchie.SurfaceView, PID: 26348
java.lang.NullPointerException: Attempt to invoke virtual method 'int com.Frenchie.SurfaceView.MySurfaceView.getLastTouchx()' on a null object reference
at com.Frenchie.SurfaceView.Player.Update(Player.java:36)
at com.Frenchie.SurfaceView.MySurfaceView.Update(MySurfaceView.java:68)
at com.Frenchie.SurfaceView.MySurfaceView.run(MySurfaceView.java:62)
at java.lang.Thread.run(Thread.java:762)
This was not a duplicate of the post suggested.
Override another constructor in your MySurfaceView:
public class MySurfaceView extends SurfaceView
...
public MySurfaceView(Context context) {
this(context, (AttributeSet)null)
}
public MySurfaceView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
player = new Player(context, this);
bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.player);
surfaceHolder = getHolder();
//Starts the run()
Thread TestThread = new Thread(this);
TestThread.start();
}
...
In your player in constructor you can pass a surfaceView: so no need to initialize:
MySurfaceView mySurfaceView;
//constructor
public Player(Context context, MySurfaceView surfaceView) {
this.mySurfaceView = surfaceView;
x = 75;
...
Try:
MySurfaceView mySurfaceView = new MySurfaceView();
I've followed the instructions in this tutorial: http://code.tutsplus.com/tutorials/create-a-live-wallpaper-on-android-using-an-animated-gif--cms-23088
But I have had a few errors and am unable to run my project.
This is all my code:
My manifest:
<service
android:name=".GIFWallpaperService"
android:enabled="true"
android:label="Raindrops In Paris"
android:permission="android.permission.BIND_WALLPAPER" >
<intent-filter>
<action android:name="android.service.wallpaper.WallpaperService"/>
</intent-filter>
<meta-data
android:name="android.service.wallpaper"
android:resource="#xml/wallpaper" >
</meta-data>
</service>
<uses-feature
android:name="android.software.live_wallpaper"
android:required="true" >
</uses-feature>
My Java class:
package com.gacafw.gina.raindropsinparis;
import android.graphics.Canvas;
import android.graphics.Movie;
import android.os.Handler;
import android.service.wallpaper.WallpaperService;
import android.util.Log;
import android.view.SurfaceHolder;
import java.io.IOException;
public class GIFWallpaperService extends WallpaperService {
#Override
public WallpaperService.Engine onCreateEngine() {
try {
Movie movie = Movie.decodeStream(
getResources().getAssets().open("rainDropAna.gif"));
return new GIFWallpaperEngine(movie);
}catch(IOException e){
Log.d("GIF", "Could not load asset");
return null;
}
}
private Runnable drawGIF = new Runnable() {
public void run() {
draw();
}
};
private void draw() {
if (visible) {
Canvas canvas = holder.lockCanvas();
canvas.save();
// Adjust size and position so that
// the image looks good on your screen
canvas.scale(3f, 3f);
movie.draw(canvas, -100, 0);
canvas.restore();
holder.unlockCanvasAndPost(canvas);
movie.setTime((int) (System.currentTimeMillis() % movie.duration()));
handler.removeCallbacks(drawGIF);
handler.postDelayed(drawGIF, frameDuration);
}
}
#Override
public void onVisibilityChanged(boolean visible) {
this.visible = visible;
if (visible) {
handler.post(drawGIF);
} else {
handler.removeCallbacks(drawGIF);
}
}
private class GIFWallpaperEngine extends WallpaperService.Engine {
private final int frameDuration = 20;
private SurfaceHolder holder;
private Movie movie;
private boolean visible;
private Handler handler;
public GIFWallpaperEngine(Movie movie) {
this.movie = movie;
handler = new Handler();
}
#Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
this.holder = surfaceHolder;
}
#Override
public void onDestroy() {
super.onDestroy();
handler.removeCallbacks(drawGIF);
}
}
}
My wallpaper.xml
<?xml version="1.0" encoding="UTF-8"?>
<wallpaper
xmlns:android="http://schemas.android.com/apk/res/android"
android:label="Raindrops In Paris"
android:thumbnail="#drawable/ic_launcher">
</wallpaper>
My errors currently:
The variables visible, holder, movie, handler in the draw() and onVisibilityChanged() are giving the error Cannot Resolve Symbol. I assume this is because they are out of scope in these methods?
I think I interpreted the instructions wrong but I can't figure out where I went wrong.
The tut contains an error - where it says "Add the following code to the GIFWallpaperService class:" it should say add it to the GIFWallpaperEngine class.
I had the same problem.I created an An Activity and passed an intent to run the wallpaper.here is your answer
public class SetWallpaperActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
Intent intent = new Intent(
WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
intent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT,
new ComponentName(this, GIFWallpaperService.class));
startActivity(intent);
}
}
I'm trying to port some Java code in to C#. where CW is a class which extends a view. OnSelectedListener is a interface with Cselected as method which takes an int argument.
setListener is a method within the class. the problem is with instantiate a interface like in Java.
private View selectedView = new View( context );
CW.setListener( new OnSelectedListener() {
#Override
public void cSelected(Integer color) {
selectedColor = color;
selectedView.setBackgroundColor( color );
}
});
Another Implementation in same method
VS.setListener( new OnSelectedListener() {
public void cSelected(Integer color) {
VS.setColor( color, true );
}
} );
Can anyone please help me port the above code to C#? Any help is appreciated. I'm using Xamarin to develop Android apps.
EDIT:
Here is the full CW class
public class HSVColorWheel : View
{
private const float SCALE = 2f;
private const float FADE_OUT_FRACTION = 0.03f;
private const int POINTER_LINE_WIDTH_DP = 2;
private const int POINTER_LENGTH_DP = 10;
private Context _context;
public HSVColorWheel(Context context, IAttributeSet attrs, int defStyle)
: base(context, attrs, defStyle)
{
this._context = context;
Init();
}
public HSVColorWheel(Context context, IAttributeSet attrs) : base(context, attrs)
{
this._context = context;
Init();
}
public HSVColorWheel(Context context) : base(context)
{
this._context = context;
Init();
}
private int scale;
private int pointerLength;
private int innerPadding;
private Paint pointerPaint = new Paint();
private void Init()
{
float density = _context.Resources.DisplayMetrics.Density;
scale = (int) (density*SCALE);
pointerLength = (int) (density*POINTER_LENGTH_DP);
pointerPaint.StrokeWidth = (int) (density*POINTER_LINE_WIDTH_DP);
innerPadding = pointerLength/2;
}
public void setListener(OnSelectedListener listener)
{
_listener = listener;
}
private float[] colorHsv = {0f, 0f, 1f};
public void setColor(Color color)
{
Color.ColorToHSV(color, colorHsv);
Invalidate();
}
}
Interface:
public interface OnSelectedListener {
void cSelected( Integer color );
}
As mentioned in the comments, since C# has language-level support for events, it provides a much cleaner approach than java's "even listener" approach.
Therefore, all listener-based java code should be converted into proper events in C#.
In this case, you're seemingly raising an event that has an int parameter. This is declared in C# like so:
//In the CW class:
public event EventHandler<int> SelectionChanged;
and then raised via an "event invocator", like so:
//In the CW class:
public void OnSelectionChanged()
{
var handler = SelectionChanged;
if (handler != null)
handler(this, //[ some int value here ]);
}
from the "consumer", or "listener" side, you simply handle the event:
//In an Activity
var CW = new CW(this);
CW.SelectionChanged += CW_SelectionChanged;
where CW_SelectionChanged can either be a an anonymous method, an actual named method, or even a lambda expression:
CW.SelectionChanged += (sender, intValue) => //[here you do something with intValue]
// -- OR --
CW.SelectionChanged += this.CW_SelectionChanged;
// then
private void CW_SelectionChanged(object sender, int intValue)
{
//[here you do something with intValue]
}
This way, you don't need to declare additional, unneeded 1-method interfaces.