I have two classes, both of which extend Activity.
MainActivity.java
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout activityLayout = new LinearLayout(this);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
activityLayout.setLayoutParams(lp);
activityLayout.setOrientation(LinearLayout.VERTICAL);
activityLayout.setPadding(16, 16, 16, 16);
activityLayout.addView(new Button(this));
setContentView(activityLayout);
new Permissions() {
#Override
public void onPermissionRefused() {
Toast.makeText(getBaseContext(), "Refused", Toast.LENGTH_SHORT).show();
}
}.requestPermissions(this);
}
}
Permissions.java
public class Permissions extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(R.style.AppTheme_Dialog); // Custom theme to make Activity like a Dialog
super.onCreate(savedInstanceState);
onPermissionRefused();
}
public void requestPermissions(Activity activity, String... permissions) {
startActivity(new Intent(activity, Permissions.class));
}
public void onPermissionRefused() {
}
}
What I want to do is start the Permissions Activity while overriding it's onPermissionRefused() method. However, neither of the two ways I've tried work.
new Permissions() {
#Override
public void onPermissionRefused() {
Toast.makeText(getBaseContext(), "Refused", Toast.LENGTH_SHORT).show();
}
}.requestPermissions(this);
Doesn't pass the override and swapping that code out with: startActivity(new Intent(this, Permissions.class)); doesn't even allow me to override the method. How can I achieve this?
Step 1. Create a subclass of Permissions
class MyPermissionsActivity extends Permissions {
#Override
public void onPermissionRefused() {
Toast.makeText(getBaseContext(), "Refused", Toast.LENGTH_SHORT).show();
}
}
Step 2. Declare that subclass in your application manifest
Step 3. Launch the activity as follows:
Intent i = new Intent(context, MyPermissionsActivity.class);
currentActivity.startActivity(i);
You can't. Activities have to be declared in the manifest, you can't declare an anonymous inner class that way (and even if you could, it wouldn't have the right constructor because of the implicit reference to parent). If you need that, make a real subclass, and pass any necessary variables via intent.
Related
I am working on an Android application which requires constant listener of Internet connectivity. I am using Broadcast listener and successfully applied it. But my code only shows the Toast message.
I want to stop the current activity and show a default XML file which says "No Internet Connection". and whenever it connect the Internet, previous activity resumes.
ExampleBradcastReceiver.java
public class ExampleBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
boolean noConnectivity = intent.getBooleanExtra(
ConnectivityManager.EXTRA_NO_CONNECTIVITY, false
);
if (noConnectivity) {
Toast.makeText(context, "Disconnected", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "Connected", Toast.LENGTH_SHORT).show();
}
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
ExampleBroadcastReceiver exampleBroadcastReceiver = new ExampleBroadcastReceiver();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onStart() {
super.onStart();
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(exampleBroadcastReceiver, filter);
}
#Override
protected void onStop() {
super.onStop();
unregisterReceiver(exampleBroadcastReceiver);
}
}
In the place of Toast Message, I want to show a default XML file whenever disconnected and resume activity whenever connected.
You can move ExampleBroadcastReceiver to MainActivity as an inner class. And since in Java inner classes have access to their parent classes' methods and fields, you can in onReceive method consider showing/hiding the Internet disconnected view.
public class MainActivity extends AppCompatActivity {
ExampleBroadcastReceiver exampleBroadcastReceiver = new ExampleBroadcastReceiver();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onStart() {
super.onStart();
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(exampleBroadcastReceiver, filter);
}
#Override
protected void onStop() {
super.onStop();
unregisterReceiver(exampleBroadcastReceiver);
}
private void showInternetDisconnectedView(boolean disconnected){
// show or hide based on 'disconnected'
}
private class ExampleBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
boolean noConnectivity = intent.getBooleanExtra(
ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
showInternetDisconnectedView(noConnectivity);
}
}
}
}
You need to move Broadcast receiver code into Activity and on receiving internet connection events you can stop current in progress activity and make internet failure layout visible there only as it is part of Activity class. If it is required through out the Application, then create Base activity and handle this there to avoid duplicating code on every screen.
I'm making an Android whack a mole game. I have the main activity which is basically the launcher, when you press the Play button the game activity starts. This works fine as it shows the background image and all molehills but I don't know how to call the method to start the game.
I've tried to call it from inside onCreate() but this ends up "playing the game" itself.
I've tried to call it right after the startActivity(intent) but the app crashes. And also I've tried to create an instance of the game class and call the play() method after the start activity but it doesn't work aswell. I don't know how to start the game method once the game activity is loaded.
I hope I explained well, thank you.
public class MainActivity extends AppCompatActivity {
ImageButton btnStart;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Hide TitleBar
try { this.getSupportActionBar().hide();}
catch (NullPointerException e){}
setContentView(R.layout.activity_main);
btnStart = (ImageButton)findViewById(R.id.btnStart);
btnStart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(), GameView.class);
startActivity(intent);
}
});
}
And this is the code for the game_activity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Hide TitleBar
try { this.getSupportActionBar().hide();}
catch (NullPointerException e){}
setContentView(R.layout.activity_game_view);
game();
}
The game() method is a typical game loop.
public void game() {
Random random = new Random();
int index;
/*
* Casting array to store all ImageView on the game
*/
imgViewArray[0] = (ImageView)findViewById(R.id.img1);
imgViewArray[1] = (ImageView)findViewById(R.id.img2);
imgViewArray[2] = (ImageView)findViewById(R.id.img3);
imgViewArray[3] = (ImageView)findViewById(R.id.img4);
imgViewArray[4] = (ImageView)findViewById(R.id.img5);
imgViewArray[5] = (ImageView)findViewById(R.id.img6);
imgViewArray[6] = (ImageView)findViewById(R.id.img7);
imgViewArray[7] = (ImageView)findViewById(R.id.img8);
imgViewArray[8] = (ImageView)findViewById(R.id.img9);
imgViewArray[9] = (ImageView)findViewById(R.id.img10);
int j=0;
while (j < 10) {
// Get a random image to animate
index = random.nextInt(10);
switch(index) {
case 0: imgViewArray[0].setImageResource(images[6]);
new java.util.Timer().schedule(
new java.util.TimerTask() {
#Override
public void run() {
imgViewArray[0].setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
imgViewArray[0].setImageResource(images[0]);
}
});
}
},
300 // The code executes after 300ms
);
break;
I think you should put the game() call inside onResume().
There are many ways to solve the problem:
Using EventBus
Send the start game Event from Main Activity and register for the Event in the Game activity.
This is my favorite way to handle the problem. It's because the simplicity and prevent us from tightly coupled code. The major problem with using EventBus is we will lost in the sea of Event if there are too much Event in the the app.
How to do:
First, create the Event. This is just a simple class:
public class StartGameEvent {
}
Second, register for the event in the game activity:
public class GameActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
EventBus.getDefault().register(this);
}
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
}
Third, subscribe for the event:
public class GameActivity extends Activity {
...
#Subscribe
public void onMessageEvent(StartGameEvent event) {
game();
}
}
Last, send the event from Main activity:
EventBus.getDefault().post(new StartGameEvent());
Using LocalBroadcastManager
You need to create the message and broadcast it in from your Main activity:
Intent intent = new Intent("playEvent");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
Then, in the game activity, you need to register as receiver:
#Override
public void onCreate(Bundle savedInstanceState) {
// register for the event
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver,
new IntentFilter("playEvent"));
}
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
game();
}
};
#Override
protected void onDestroy() {
// Unregister here
LocalBroadcastManager.getInstance(this)
.unregisterReceiver(mReceiver);
super.onDestroy();
}
I slightly modifying the code from How to use LocalBroadcastManager? for your case.
Using a static method in Game activity
This is the simplest way but highly discouraged. Because we can't ensure the state of the activity. Do not use this in production code. This is for learning sake only.
You can make the game() method as a static method like this:
public class GameActivity extends Activity {
...
public static void game() {
// game logic.
}
}
Then call the method when you want with:
GameActivity.game();
When I need a callback from Activity B back to Activity A I usually make the reference variable in Activity B 'static'. I realize that if the user rotates the device the Life Cycle methods will remove my reference.
Is this the only drawback and is there a better way to register without a static reference. Is it better to simply put all data in the Application class ? - Thank you.
public class MainActivity extends Activity implements InterfaceMainActivityTwo {
static Main2Activity main2Activity;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
main2Activity = new Main2Activity();
main2Activity.setDataListener(this);
}
#Override
public void getDataMainActivityTwo(String string) {
tvTextData.setText(string);
}
}
public class Main2Activity extends Activity {
static InterfaceMainActivityTwo mGetDataInterface;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
}
public void getDataSaveBtn(View v) {
if (mGetDataInterface != null)
mGetDataInterface.getDataMainActivityTwo(fullName);
else
Toast.makeText(this, "IS NULL.INTERFACE NOT INITIALIZED !!!!", Toast.LENGTH_SHORT).show();
}
/////////// interface setup
interface InterfaceMainActivityTwo {
void getDataMainActivityTwo(String string);
}
public void setDataListener(InterfaceMainActivityTwo listener) {
this.mGetDataInterface = listener;
}
}
You should never need a callback between two activities. You're doing something wrong if you do. If you need to pass data from A to B, pass it in the bundle. If you need to pass it back from B to A, use startActivityForResult and pass it in the result. If you need to share data between many activities, it should be held in some globally accessible data structure, either in memory or on disk.
There are two Activities..
1. Open SecondActivity from MainActivity
2. When event comes into MainActivity, call testMethod of SecondActivity
But how to do call this testMethod?
public class MainActivity extends Activity implements someListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Launch SecondActivity here!!
Intent intent = new Intent();
intent.setClass(MainActivity.this, SecondActivity.class);
startActivityForResult(intent, ID_PlayerActivity);
}
//trigger by JNI, it's in the other thread, not main thread.
void onEventCome() {
//How to call testMethod() in SecondActivity?
}
}
public class SecondActivity extends Activity {
void testMethod() {
//execute something...
}
}
If you open the SecondActivity, your MainActivity becomes inactive. I don't believe it is a good idea to call some activity method from other inactive/stopped activity.
I suggest to use observer pattern. Create a global long-lived object like EventProducer and register all activities as observer. So your EventProducer can inform all Activities about new event.
Example:
public class SecondActivity extends Activity implements MyEventListener {
#Override
public void onResume(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EventProducer.instance().register(this);
}
#Override
public void onPause(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EventProducer.instance().unregister(this);
}
void testMethod(){
//just doit
}
#Override
void onMyEventCome() {
testMethod();
}
}
First you need an event aware listener that will capture such an event happening. Your class seems ill equipped to do so.
Since you have a valid question, here goes:
void onEventCome() {
SecondActivity secondActivity = new SecondActivity();
secondActivity.testMethod();
}
There are many ways.
For eg:
Create the method as static and use class name and call it.
public static void onEventCome() {
}
In MainActivity:
MainActivity.onEventCome();
This is one method. Another method is create an object for MainActivity.
public void onEventCome() {
}
MainActivity main;
main = new MainActivity();
main.onEventCome();
You don't have a content view for your second activity. If you don't need to see the operation happen, you could remove your
Intent intent = new Intent();
intent.setClass(MainActivity.this, SecondActivity.class);
startActivityForResult(intent, ID_PlayerActivity);
remove extends Activity in SecondActivity and add a constructor public SecondActivity(Context context) and invoke the test method from your first activity like #Dragan example:
void onEventCome() {
SecondActivity secondActivity = new SecondActivity(MainActivity.this);
secondActivity.testMethod();
}
I have a menu and 5 activities. To avoid repeating the menu code, I have created a public class and call it in every activity:
Testclass testclass = new Testclass(Main.this);
...but unfortunately I can't use startActivity() in the class. This is my class code:
public class Testclass extends Activity {
public Testclass(Activity cc) {
Intent intent = new Intent(cc,Next.class);
startActivity(intent);
}
}
Try this and tell me if it helped you.
public class Testclass extends Activity {
public Testclass(Activity cc) {
final Context context = Testclass.this.getContext();
Intent intent = new Intent(context , Next.class);
context.startActivity(intent);
}
}
You misunderstood the concept of an Activity and its life cycle. You DON'T instantiate the Activity, the Activity has callback mechanisms (onCreate, onResume, etc.) that tell you exactly what to do. You never ever have to call new Activity().
The fact that you're doing
Testclass testclass = new Testclass(Main.this); shows that you have a misunderstanding of this concept: http://developer.android.com/training/basics/activity-lifecycle/index.html
To fix your error, read the docs and then it will be clear what is wrong with your approach.
Hint: Your Testclass already IS an Activity, because you inherit from Activity.
And next time please provide the whole error log to your problem, so it can give the whole picture of what can be wrong with your code.
Why not use this code?
startActivity(new Intent(Main.this, Next.class));
// "Main" is your current Activity
// "Next" is your next Activity to be opened.
I think, it's very simple to use without create a new public class. Please compare your codes with my code above, only one line.
I think you don't use the correct Context to start the Intent.
Instead try
{
public Testclass() {
Intent intent = new Intent(this,Next.class);
startActivity(intent);
}
}
if the this doesn't work either, try getApplicationContext() instead.
#you can used Weak Reference Objects to store Context of Activity class#
##in activity class##
public class Activity extends AppCompatActivity implements View.OnClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view);
findViewById(R.id.toNext).setOnClickListener(this);
}
#Override
public void onClick(View v) {
Testclass thread = new Testclass(Activity.this,v);
new Thread(thread).start();
}
}
}
// in sub class
public class Testclass extends Activity implements Runnable {
View landingPage;
private Activity activity;
public Testclass (Activity activity, View landingPage){
WeakReference<Activity> ActivityWeakReference = new WeakReference<>(Activity);
this.landingPage = landingPage;
this.activity = activityWeakReference.get();
}
#Override
public void run() {
Intent activityIntent = new Intent(activity, Next.class);
activityIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
runOnUiThread(new Runnable() {
#Override
public void run() {
switch (landingPage.getId())
{
case R.id.Next.class:
activity.finish();
activity.startActivity(activityIntent);
break;
}
}
});
}
}