I read other questions on this, but I feel like my architecture is a bit different, so I'm posting.
I have a game with one MainActivity and multiple views. Basically, there is one LinearLayout that fills MainActivity, and different views are set on the layout depending on the state. For example, menuState (menuView), gameState (gameView), gameOverState (gameOverView).
In my BattleView (which extends SurfaceView), I tried to implement a game loop. However, my BattleView cannot implement a Callback due to the fact getHolder() returns null.
How would I go on about fixing this?
public class MainActivity extends AppCompatActivity {
GameScreen gs;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.init();
}
private void init(){
this.gs = new GameScreen(this);
this.hideSystemUI(this.gs);
setContentView(this.gs);
}
Then my GameScreen class contains BattleView class, which is called when appropriate.
public GameScreen(Context context){
super(context);
this.init();
}
private void init(){
this.ms = new MapScreen(this.getContext(), this);
((MainActivity)this.getContext()).hideSystemUI(this.ms);
this.addView(this.ms);
}
private void newMapScreen(){
this.ms = new MapScreen(this.getContext(), this);
}
public void addBattleScreen(BattleScreen bs){
//this.bs = new BattleScreen(this.getContext(), ms);
this.removeView(this.ms);
this.bs = bs;
((MainActivity)this.getContext()).hideSystemUI(this.bs);
this.addView(this.bs);
}
Well.. BattleScreen contains BattleView class and is initialized there. Then, BattleView class
public BattleView(Context context, int monsterNumber, Hero hero){
super(context);
this.gameLoopInit();
this.setBackgroundImage();
}//end
private void gameLoopInit(){
holder = getHolder(); <------------- ERROR (null)
System.out.println(holder);
holder.addCallback(this);
}
Related
I'm doing a project in android studio. I just want to do a flashing light point using onDraw() and invalidate() but something is wrong.
This is the first class
public class flashingPoint extends View {
private ShapeDrawable mParteDibujable;
public flashingPoint(Context context){
super(context);
final Handler bridge = new Handler();
Thread time = new Thread() {
public void run() {
bridge.postDelayed(this, 1000);
invalidate();
}
};
time.start();
}
#Override
protected void onDraw(Canvas canvas) {
mParteDibujable = new ShapeDrawable(new OvalShape());
mParteDibujable.getPaint().setColor(0xff74AC23);
mParteDibujable.setBounds(10, 20, 80, 80);
mParteDibujable.draw(canvas);
//invalidate();
}
And then the main class:
public class MainActivity extends AppCompatActivity {
private ShapeDrawable mParteDibujable;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout mLinearLayout = new LinearLayout(this);
flashingPoint myView = new flashingpoint(this);
mLinearLayout.addView(myView);
setContentView(mLinearLayout);
}
}
If you have the timer, you neither need nor want the invalidate in onDraw. Invalidating in onDraw is both logically weird and will lead to poor results- it would either be ignored, or it would cause an immediate redraw. Neither is desired.
Also, you can't invalidate on a Thread, you'd need to use postInvalidate. And your thread is wrong- either don't use a thread, use a Runnable and post it to the Handler, or the thread should infinitely loop, not return. Preferably the first, there's no reason to have a thread here at all.
I have created an volley list in this i have problem to get data from adapter to activity and this activity to another activity. I have received error cannot cast activity.java to anotherActivity.java below is my code. Please help me anyone thanks.
My Interface itemclick in Adapter class
private OnItemClickGetPlaylist mListener;
public interface OnItemClickGetPlaylist{
public void OnPlaylistItemClick(String playlistName,int numOfItems,String imageViewForPlaylist);
}
public void setOnClickListenerOnPlaylist(OnItemClickGetPlaylist listener)
{
mListener = listener;
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String id = playlist.getId_playlist_identify();
String PlaylistName = playlist.getTitile_of_playlist();
String imageOfPlaylist = playlist.getImage_of_playlist();
int numOfPlaylistSongs = getItemCount();
SendIdToDatabase(id);
if (mListener != null)
{
mListener.OnPlaylistItemClick(PlaylistName,numOfPlaylistSongs,imageOfPlaylist);
}
else {
Toast.makeText(context, "mListeren is null" + mListener, Toast.LENGTH_SHORT).show();
}
}
});
After get data handle OnPlaylistItemClick click in Activity below Codes
public void OnItemClickHandleInPlaylistActivity(String playlistName,int numOfItems,String imageViewForPlaylist)
{
//here is the adapter item click in activity now i want to send that data to another activity without any intent please help me.
// i have implement below code but it give me cannot cast activity to another activity error.
((anotherActivity) getApplicationContext()).OnItemClickInMusicActivity(playlistName,numOfItems,imageViewForPlaylist);
}
See the solution at https://stackoverflow.com/a/47637313/2413303
public class MyApplication extends Application {
private static MyApplication INSTANCE;
DataRepository dataRepository; // this is YOUR class
#Override
public void onCreate() {
super.onCreate();
INSTANCE = this;
dataRepository = new DataRepository();
}
public static MyApplication get() {
return INSTANCE;
}
}
The DataRepository should expose LiveData:
public class DataRepository {
private final MutableLiveData<MyData> data = new MutableLiveData<>();
public LiveData<MyData> getMyData() {
return data;
}
public void updateText(String text) {
MyData newData = data.getValue()
.toBuilder() // immutable new copy
.setText(text)
.build();
data.setValue(newData);
}
}
Where the Activity subscribes to this:
public class MyActivity extends AppCompatActivity {
DataRepository dataRepository;
TextView textView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyApplication app = (MyApplication)getApplicationContext();
dataRepository = app.getDataRepository();
setContentView(R.layout.main_activity);
textView = findViewById(R.id.textview);
dataRepository.getMyData().observe(this, new Observer() {
#Override
public void onChange(MyObject myObject) {
textView.setText(myObject.getText());
}
}
}
So to update this text, you need to get the DataRepository class, and call updateText on it:
DataRepository dataRepository = MyApplication.get().dataRepository();
dataRepository.updateText("my new text");
Make sure that the data in DataRepository is properly persisted somewhere, or at least can be obtained again after process death. You might want to use a database for example (but not shared preferences).
If you don't want to use Intents, maybe you can use a publish/subscribe architecture. There is a library called eventbus (org.greenrobot:eventbus) very easy to use which could achieve what you want.
Use an Application Class instead.
public class MyApplicationClass extends Application{
#Override
public void onCreate() {
super.onCreate();
///do something on create
}
getterMethods(){...}
setterMethods(){...}
}
then add android:name=".MyApplicationClass" to manifest file
Now you can access the methods in class by
MyApplicationClass applicationClass = (MyApplicationClass)getApplicationContext();
int id = applicationClass .getterMethod().getID;
String playListName = applicationClass .getterMethod().getPlayListName();
and vice versa for Setter();
after that you can use it for data getting and setting Data throughout the application.
Hope it helps :)
References:
https://guides.codepath.com/android/Understanding-the-Android-Application-Class
I find the best to use callbacks.
in ClassA:
Create interface
MyCallback callback;
viod setCallback(MyCallback callback){
this.callback = callback;
}
viod onStop(){
callback = null;
}
interface MyCallback{
void doSomething(Params params);
}
in ClassB:
implement MyCallback
public class ClassB **implements ClassA.MyCallback**
set reference in onCreate
ClassA classA = new ClassA();
classA.setCallback(this);
// override method doSomething
#override
void doSomething(Params params){
//do your thing with the params…
}
when the job is done inside class A call:
callback.doSomething(params);
destroy reference inside class B in onStop()
classA.onStop();
public class MainActivity extends AppCompatActivity {
public ShareData SD = new ShareData();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SD.set_numb(5);
}
// when button clicked
public void noviEkran(View view){
Intent i = new Intent(this,klasaB.class);
startActivity(i);
}
}
public class ShareData {
private int number;
public ShareData(){
this.number=0;
}
public void set_numb(int num){
number = num;
}
public int get_numb(){
return number;
}
}
public class klasaB extends Activity{
ShareData sd;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int i =sd.get_numb();
System.out.println("Saved numb:" + i);
}
}
My question is, if i declare object in 1st class, and set its parameter number to 5, how to acces this number from other class because now my apk crashes when reading " int i =sd.get_numb(); " in class "klasaB".
Any suggestion how to make this work?
ps: i dont want to use static variables, or putExtra with Intents.
If data is simple/primitive then use Intent to pass data from one activity to another. That is what Intent is for.
If it is not (some sort of complex data structure or object), I would extend Application, by making a custom sub class. Application class (as the name implies) is accessible to all Activities, even when app transitions from one to another. Below is a very simple example, just to show you the idea. You can modify/adjust that to your needs.
public class MyApplication extends Application {
private X x;
public static void setX(X x) { ... }
public static X getX() { ... }
}
public class ActivityA extends Activity {
...
MyApplication.setX(x);
}
public class ActivityB extends Activity {
...
X x = MyApplication.getX();
}
You may have mixed up Activity/MainActivity/AppCombatActivity inheritance... I suspect that the reason you are seeing the error -- by the way, please look into "how to ask" and include a bit more information next time -- is that sd in klasaB is never initialized.
MainActivity.SD will hold that 5 after its onCreate(), whereas klasaB.sd is never set to anything.
You never reference or instantiate SD in class B. To get the data to ClassB you will need to set the data as an extra in the intent. Most classes cannot be sent in the intent, so for your case you should pass the primitive types of the object, then create the object.
// when button clicked
public void noviEkran(View view){
Intent i = new Intent(this,klasaB.class);
i.putExtra("TAG", SD.get_num());
startActivity(i);
And then in Class B
ShareData SD = new ShareData();
SD.set_num(getIntent.getIntExtra("TAG", 0);
You can access your class object either using implements Serializable or Parcelable
1.Implement serializable into your ShareData class
public class ShareData implements Serializable{
private int number;
public ShareData(){
this.number=0;
}
public void set_numb(int num){
number = num;
}
public int get_numb(){
return number;
}
}
2.create object of SharedData and share with intent to classB
public class MainActivity extends AppCompatActivity {
public ShareData SD = new ShareData();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SD.set_numb(5);
}
// when button clicked
public void noviEkran(View view){
Intent i = new Intent(this,klasaB.class);
i.putExtras("key", SD)
startActivity(i);
}
}
3.Access in classB
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ShareData sd = (ShareData)getIntent().getSerializableExtra("key").
System.out.println("Saved numb:" + sd.get_num());
}
Use a singleton class
Declare an instance in ShareData class:
public class ShareData {
private static ShareData sdInstance = null;
...}
add this method in ShareData class:
public static ShareData getInstance(){
if(sdInstance == null){
sdInstance = new ShareData();
}
return sdInstance;
}
To get same object in other classes , use this
ShareData sd = ShareData.getInstance();
now you will receive same sd.get_numb()
I want to run a gameloop code inside my GameLoop class constructor in my activity, but it seems that it got no respond.
I've tried to put the code inside the OnCreate method instead of a new class and that worked.
My Activiy Class:
public class GameActivity extends Activity {
private Button btnHertz;
private TextView textView1;
private GameLoop gameloop;
private int hertz = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
gameloop = new GameLoop();
btnHertz = (Button) findViewById(R.id.btnHertz);
textView1 = (TextView) findViewById(R.id.testTextView1);
}
public void testUpdate(){
hertz++;
textView1.setText(Integer.toString(hertz));
}
GameLoop Class:
public class GameLoop {
private GameActivity gui;
public GameLoop() {
gui = new GameActivity();
ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
exec.scheduleAtFixedRate(new Runnable() {
public void run() {
gui.testUpdate();
}
}, 0, 10, TimeUnit.MILLISECONDS);
}
gui = new GameActivity();
The activity object you're passing updates to is different from the one that displays your UI.
Never instantiate activities yourself with new. Their lifecycle methods won't be invoked and they won't be good for anything. In this case you'd get an NPE at textView1.setText() since onCreate() has not been run.
Instead, pass a GameActivity reference as an argument to GameLoop, e.g.
... new GameLoop(this)
...
public GameLoop(GameActivity gui) {
I am having trouble sending info from a surfaceView class to its parent class
the overlay activity sets its view as a drawing panel:
public class Overlay extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_Overlay);
drawingPanel dPanel = new drawingPanel(this);
setContentView(dPanel);
}
}
then in the drawing panel:
public class drawingPanel extends SurfaceView implements SurfaceHolder.Callback {
Context context = context;
public Player(Context context, int num) throws ClassNotFoundException, IOException {
super(context);
this.context = context;
SurfaceHolder holder = getHolder();
holder.addCallback(this);
}
public boolean onTouchEvent(MotionEvent e){
if(e.getAction()==MotionEvent.ACTION_DOWN){
//send info to Overlay that drawingPanel was touched
}
}
}
When surfaceView is touched, I want to send that info to Overlay. I can't simply use onTouchEvent in the Overlay activity because I need to draw stuff with drawingPanel. My main goal is to hide/show the action bar when the screen is touched while using a surfaceView. if there is another way to achieve that, please state so below.
Try adding this line to onCreate method of your Overlay class
dPanel.setActivity(this);
And implementing setActivity() in the drawingPanel class like this:
public void setActivity(Activity overlayActivity) {
mActivity = overlayActivity;
}
This way, you can use mActivity to reference your Activity and call public methods to "hide/show the action bar", like:
mActivity.getActionBar().hide();
and,
mActivity.getActionBar().show();