I see a black screen between switching activities in my android app. To my knowledge Black is the default plot color for Android, so this is the placeholder until the app completes it's layout operation. There are a number of things that can cause an app to have a delay:
1. Performing a network call(s).
2. Loading data from disk.
3. Garbage collection from other tasks.
4. Restoring a complex drawing.
I have seen this question and links it had and I have tried various techniques to optimize the application such as multi threading etc. I KNOW now that my issue is with network calls and that there is a delay in the functions when there are latency issues i.e. when there is slow internet the function that I use to "check for internet" and "fetch and parse data" work slowly as it is dependent on the internet speed. Changing the application flow and activity life cycle is not possible as they are strictly set as per the functional requirements. Is there a way to solve or a workaround to this issue that can be done? These are snippets of code that I have implemented in my splash screen and there are similar codes inside other activities. This is a code that checks for internet connection in the onCreate.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
chkStatus(this);
}
public boolean chkStatus(Context context) {
final ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
final android.net.NetworkInfo wifi = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
final android.net.NetworkInfo mobile = connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if (wifi.isConnectedOrConnecting() && isOnline()) {
Log.e("connectedto", "Wifi");
session.StoreMode("online");
return true;
} else if (mobile.isConnectedOrConnecting() && isOnline()) {
Log.e("connectedto", "Mobile 3G");
session.StoreMode("online");
return true;
} else {
session.StoreMode("offline");
Log.e("connectedto", "No Network ");
return false;
}
}
public Boolean isOnline() {
try {
Process p1 = java.lang.Runtime.getRuntime().exec("ping -c 1 www.google.com");
int returnVal = p1.waitFor();
boolean reachable = (returnVal == 0);
return reachable;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return false;
}
You are not setting the contentView in your onCreateMethod:
Add this line after
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout);
Hope this helps.
I found what was happening. Somehow the function "isOnline" was being called before the splash screen. So when ever there was low internet network speed, the function was stuck and there was a black screen before the splash screen as the time of the splash screen got over before ack of the ping came back.So I removed the function from the splash screen and put it inside other activities.
In an application I am developing I have some code that attempts to submit information to the internet. If the connection can not be made, I pop up a toast message instructing the user to check the network connection.
Toast.makeText(getApplicationContext(), "Check network connection.", Toast.LENGTH_SHORT).show();
The problem I have is the toast message comes up no matter what the user is looking at! Even if the user is in a different app and my app is running in the background! This is not the desired behavior as I send a notification to the user if network activity fails. I only want the toast message to appear if the user is in the activity that is generating the network activity. Is there a way to do this?
If this is not possible my idea was to just put some kind of visual element in my activity - rather than display a toast message.
Thank You!
You can use a boolean class member in order to keep track of activity state changes.
public class YourClass extends Activity {
private boolean mIsResumed = false;
#Override
public void onResume() {
super.onResume();
mIsResumed = true;
}
#Override
public void onPause() {
super.onPause();
mIsResumed = false;
}
public boolean isResumed() {
return mIsResumed;
}
}
Then you can use something like this:
if (isResumed()) {
//show Toast
}
Use a dynamic BroadcastReceiver. Your background service will broadcast an Intent when something happens. All of your app's activities will register a dynamic BroadcastReceiver which will listen for these events. When such event occurs it will show a toast. When none of your activities are running nothing will happen.
Inside your service
public static final ACTION_SOMETHING = BuildConfig.APPLICATION_ID + ".ACTION_SOMETHING";
public void doSomething() {
// ...
// Show toast if app is running. Or let the app react however you please.
LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(ACTION_SOMETHING));
// ...
}
Of course you can put additional information in the Intent as extras and access them in the BroadcastReceiver.
Inside your activities
private final IntentFilter onSomethingIntentFilter = new IntentFilter(MyService.ACTION_SOMETHING);
private final BroadcastReceiver onSomething = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// This check seems redundant but it's not. Google it.
if (MyService.ACTION_SOMETHING.equals(intent.getAction()) {
// Show toast here.
}
}
};
public void onResume() {
super.onResume();
// Start listening for events when activity is in foreground.
LocalBroadcastManager.getInstance(this).registerReceiver(onSomething, onSomethingIntentFilter);
}
public void onPause() {
super.onPause();
// Stop listening as soon as activity leaves foreground.
try {
LocalBroadcastManager.getInstance(this).unregisterReceiver(onSomething);
} catch (IllegalArgumentException ex) {}
}
You may want to pull this code to a common activity parent, a BaseActivity, so you don't repeat yourself.
This is a common case of Provider-Subscriber pattern. Another implementation would be an EventBus.
Keeping it simple, try adding a boolean flag in Activity and set its value as true in onResume & false in onPause. Then display the toast if the boolean flag is true.
I'm trying to make custom lock screen. So, there I need not to allow user to press Home Button. In the beginning I write
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.lock_screen);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
|WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
Then I override OnKeyDown
#Override
public boolean onKeyDown(int keyCode, android.view.KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)||(keyCode == KeyEvent.KEYCODE_POWER)||(keyCode == KeyEvent.KEYCODE_VOLUME_UP)||(keyCode == KeyEvent.KEYCODE_CAMERA)) {
//this is where I can do my stuff
return true; //because I handled the event
}
if((keyCode == KeyEvent.KEYCODE_HOME)){
return true;
}
return false;
}
Here I override onAttacheToWindow
#Override
public void onAttachedToWindow() {
this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
super.onAttachedToWindow();
}
But it's giving me error IllegalArgumentException: Window type can not be changed after the window is added. Where is my mistake?
How can I handle Home Button?
There is no "good" way to handle the home button to "do nothing". You really only have two options which may or may not be good enough for you:
Create your own home launcher. Users must select your app as their home launcher.
You could also create a Service where you add a view to your window and it gets plastered on top of everything else. See my previous answer here with "displaying" a webview in a Service: Android: Using WebView outside an Activity context. You will need to modify params to fill the screen and also fix WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE to use the right flags to allow clicks. This won't actually block the home button but it will basically disable it's functionality. Lastly, this might not work on Android 5.0+ as the Status bar's dropdown may overlay your window.
I have an android app which is already handling changes for orientation, i.e. there is a android:configChanges="orientation" in the manifest and an onConfigurationChange() handler in the activity that switches to the appropriate layout and preps it. I have a landscape / portrait version of the layout.
The problem I face is that the activity has a dialog which could be open when the user rotates the device orientation. I also have a landscape / portrait version of the dialog.
Should I go about changing the layout of the dialog on the fly or perhaps locking the activity's rotation until the user dismisses the dialog.
The latter option of locking the app appeals to me since it saves having to do anything special in the dialog. I am supposing that I might disable the orientation when a dialog opens, such as
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
and then when it dismisses
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
Would that be a sensible thing to do? If the screen orientation did change while it was locked, would it immediately sense the orientation change when it was unlocked?
Are there alternatives?
I would recommend not turning off the screen rotation, instead of this handle the configuration changes for the Dialog. You could use one of these two approach for this:
The first one is using a flag variable in onSaveInstanceState(outState) method, and restore the dialog onCreate(bundle) method:
in this example my flag variable is called 'isShowing Dialog', when the onCreate method is called by the android System for first time, the bundle argument will be null and nothing happens. However when the activity it's recreated by a configuration change (screen rotation), the bundle will have the boolean value isShowing Dialog, previously saved by the inSaveInstanceState(...) method, so if the variable gets true the dialog is created again, the trick here is set the flag in true when the dialog get showing, and false when it's not, is a little but simple trick.
Class MyClass extends Activity {
Boolean isShowingDialog = false;
AlertDialog myDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
if(savedInstanceState!=null){
isShowingDialog = savedInstanceState.getBoolean("IS_SHOWING_DIALOG", false);
if(isShowingDialog){
createDialog();
}
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putBoolean("IS_SHOWING_DIALOG", isShowingDialog);
super.onSaveInstanceState(outState);
}
#Override
protected void onPause() {
if(myDialog!=null && myDialog.isShowing()) {
myDialog.dismiss();
}
}
private void createDialog() {
AlertDialog.Builder dialog_builder = new AlertDialog.Builder(this);
dialog_builder.setTitle("Some Title"):
... more dialog settings ...
myDialog = dialog_builder.create();
myDialog.show();
isShowingDialog = true;
}
private void hideDialog(){
myDialog.dismiss();
isShowingDialog = false;
}
}
The second approach is to use the ability of the fragments components to retain its states, the main idea is create the dialog inside a fragment, there is the problem about detach and reattach the fragment during the configuration changes (because you need dismiss and show the dialog correctly), but the solution is very similar to the first approach. The advantage of this approach is that if you have an AlertDialog with a couple of configurations, when the fragment is recreated there is not needed to create and setting up the dialog again, only make it show() and the AlertDialog state is maintained by the fragment.
I hope this helps.
I suggest your Dialog should override onSaveInstanceState() and onRestoreInstanceState(Bundle) to save its state into a Bundle.
You then override those methods in your Activity, checking if the Dialog is shown and if so - calling the dialog's methods to save and restore it's state.
If you are displaying this dialog from a fragment, you will want to override OnActivityCreated(Bundle) instead of OnRestoreInstanceState.
For a source example see the built-in clock app provided with Android, where the SetAlarm Activity handles the TimePickerDialog this way.
If you are handling orientation changes yourself, then here is an approach.
I won't claim that this is an elegant solution, but it works:
You can keep track of whether the dialog has an active instance inside the dialog class itself, by using a static variable activeInstance, and overriding onStart() to set activeInstance = this and onCancel() to set activeInstance = null.
Provide a static method updateConfigurationForAnyCurrentInstance() that tests that activeInstance variable and, if non-null, invokes a method activeInstance.reInitializeDialog(), which is a method that you will write to contain the setContentView() call plus the code that wires the handlers for the dialog controls (button onClick handlers, etc. - this is code that would normally appear in onCreate()). Following that, you would restore any displayed data to those controls (from member variables in your dialog object). So, for example, if you had a list of items to be viewed, and the user were viewing item three of that list before the orientation change, you would re-display that same item three at the end of updateConfigurationForAnyCurrentInstance(), right after re-loading the controls from the dialog resource and re-wiring the control handlers.
You would then call that same reInitializeDialog() method from onCreate(), right after super.onCreate(), and place your onCreate()-specific initialization code (e.g., setting up the list of items from which the user could choose, as described above) after that call.
This will cause the appropriate resource (portrait or landscape) for the dialog's new orientation to be loaded (provided that you have two resources defined having the same name, one in the layout folder and the other in the layout-land folder, as usual).
Here's some code that would be in a class called YourDialog:
ArrayList<String> listOfPossibleChoices = null;
int currentUserChoice = 0;
static private YourDialog activeInstance = null;
#Override
protected void onStart() {
super.onStart();
activeInstance = this;
}
#Override
public void cancel() {
super.cancel();
activeInstance = null;
}
static public void updateConfigurationForAnyCurrentInstance() {
if(activeInstance != null) {
activeInstance.reInitializeDialog();
displayCurrentUserChoice();
}
}
private void reInitializeDialog() {
setContentView(R.layout.your_dialog);
btnClose = (Button) findViewById(R.id.btnClose);
btnClose.setOnClickListener(this);
btnNextChoice = (Button) findViewById(R.id.btnNextChoice);
btnNextChoice.setOnClickListener(this);
btnPriorChoice = (Button) findViewById(R.id.btnPriorChoice);
btnPriorChoice.setOnClickListener(this);
tvCurrentChoice = (TextView) findViewById(R.id.tvCurrentChoice);
}
private void displayCurrentUserChoice() {
tvCurrentChoice.setText(listOfPossibleChoices.get(currentUserChoice));
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
reInitializeDialog();
listOfPossibleChoices = new ArrayList<String>();
listOfPossibleChoices.add("One");
listOfPossibleChoices.add("Two");
listOfPossibleChoices.add("Three");
currentUserChoice = 0;
displayCurrentUserChoice();
}
#Override
public void onClick(View v) {
int viewID = v.getId();
if(viewID == R.id.btnNextChoice) {
if(currentUserChoice < (listOfPossibleChoices.size() - 1))
currentUserChoice++;
displayCurrentUserChoice();
}
}
else if(viewID == R.id.btnPriorChoice) {
if(currentUserChoice > 0) {
currentUserChoice--;
displayCurrentUserChoice();
}
}
Etc.
Then, in your main activity's onConfigurationChanged() method, you would just invoke YourDialog.updateConfigurationForAnyCurrentInstance() whenever onConfigurationChanged() is called by the OS.
Doesn't seem the title was ever resolved (Google Necro Direct).
Here is the solution, matching the request.
When your activity is created, log the screen orientation value.
when onConfiguration change is called on your activity, compare the orientation values. if the values don't match, fire off all of your orientation change listeners, THEN record the new orientation value.
Here is some constructive code to put in your activity (or any object that can handle configuration change events)
int orientation; // TODO: record orientation here in your on create using Activity.this.getRequestedOrientation() to initialize!
public int getOrientation(){return orientation;}
public interface OrientationChangeListener {
void onOrientationChange();
}
Stack<OrientationChangeListener> orientationChangeListeners = new Stack<>();
public void addOrientationChangeListener(OrientationChangeListener ocl){ ... }
public void removeOrientationChangeListener(OrientationChangeListener ocl){ ... }
That's the basic environment. Here's your executive:
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (orientation != newConfig.orientation)
for (OrientationChangeListener ocl:orientationChangeListeners) ocl.onOrientationChange();
orientation = newConfig.orientation;
}
In YOUR code model, you may need to send the new configuration, with the event, or the two orientation values with the event. However, Activity.this.getOrientation() != Activity.this.getRequestedOrientation() during event handling (because we are in a logical state of change between two logical values).
In review of my post, i have determined that there could be some synchronization issues, with multiple events! This is not a fault of this code, but a fault of "Android Platform" for not having defacto orientation sense handlers on every window, thusly trashing the polymorphic benefits of using java in the first place..
See the answer from Viktor Valencia above. That will work perfectly with the slight adjustment that you move the createDialog() to onResume.
#Override
protected void onResume() {
super.onResume();
if(isShowingDialog){
createDialog();
}
}
Fetch the boolean isShowingDialog value at onCreate, as suggested, but wait for onResume to display the dialog.
I want to write an android app that would be a background service that would listen for either a specific gesture or key press in the and then trigger an action. Is it even possible to do such a thing with a service? If so could someone guide me the right direction. I have search high and low can could seem to find an answer.
not hard to read where they touch, but the touches in this way provide only location, not time, not on ups or downs.
in your service
#Override
public void onDestroy() {
super.onDestroy();
if (layout != null) {
((WindowManager) getSystemService(WINDOW_SERVICE)).removeView(layout);
layout = null;
}
}
#Override
public void onCreate() {
super.onCreate();
layout = new RelativeLayout(this);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
params.setTitle("test");
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.addView(layout, params);
}
and for your touch handler, it will have to be as
public boolean gestureHandler(MotionEvent event, boolean eat) {
if(event.getAction() == MotionEvent.ACTION_OUTSIDE)
Doing this (except on top of apps that cooperate by sending you their input) would be a huge security hole of the kind that the android architecture is designed to prohibit. To do it you would need to modify the platform and have the watching done by something running with access to the raw touch and button input, possibly as part of the driver for that.
In other words you can with difficulty do it on your own rooted phone or on devices you manufacture, but it's not usable for most people.