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.
Related
I'm running a simple application that on load shows a list of items, when clicked opens up a video player playing the media.
I'm having an issue that when destroying the player and returning to the list view, that there is a long delay before any events are being registered. This is due to the tear down of the player taking a few seconds.
I had asked the support crew and they recommended the best way to go about it was to simply hide the player and show again when new media was clicked but I've been reading into threads and it seems like this might be the best approach to use instead? I'm not exactly sure how they work though.
If I kill the player service in onDestroy will initiating a new one still be held up?
public class DemoPlayer extends Activity {
private Player player;
private SeekBarScrubber scrubber;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.player);
// Set the media url holder
String mediaUrl = "";
player = new Player(
// inject player container view into ADK Player
(ViewGroup) this.findViewById(R.id.tpPlayer)
);
// Build application UI
scrubber = (SeekBarScrubber) findViewById(R.id.scrubber);
scrubber.setMediaPlayerControl(player.asMediaPlayerControl());
final Activity activity = this;
try {
URI mediaUri = new URI(mediaUrl);
player.playReleaseUrl(mediaUri);
} catch (URISyntaxException e) {
AlertDialog alertDialog = new AlertDialog.Builder(activity).create();
alertDialog.setTitle("Invalid URL");
alertDialog.setMessage("Issue loading media");
alertDialog.setCancelable(true);
alertDialog.show();
}
}
#Override
protected void onDestroy() {
new Thread(new Runnable() {
public void run() {
if (player != null)
player.getLifecycle().destroy();
player = null;
}
}).start();
ViewGroup viewGroup = (ViewGroup) this.findViewById(R.id.tpPlayer);
viewGroup.removeView(scrubber);
scrubber = null;
super.onDestroy();
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
finish();// call finish() on click of back button
}
return super.onKeyDown(keyCode, event);
}
}
TL;DR: How to kill player without holding up the UI thread since it takes a few seconds to destroy the player. Also will loading a new player quickly cause issues?
Currently get the error below
failed access media controller because player thread is shutdown
Skipped 374 frames! The application may be doing too much work on its main thread.
The player is attached to the view when the view is created not the other way around. Therefore i think that your best option is to move the player to a singleton and start/stop him regardless of the activity lifecycle. of course u can do the shutdown on back thread (i suggest u read about threadpools and executers because i rarely see Thread.start() on android.
also:
ViewGroup viewGroup = (ViewGroup) this.findViewById(R.id.tpPlayer);
viewGroup.removeView(scrubber);
scrubber = null;
this is unnecessary.
SITUATION:
An application with resources for portait and landscape, has a simulator that I keep after configuration changes (the user can switch orientation while the simulation is running).
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Installer.installApkData(this);
simulator = new Simulator(this);
MainActivity prevActivity = (MainActivity)getLastCustomNonConfigurationInstance();
if(prevActivity!= null) {
// So the orientation did change
// Restore some field for example
this.simulator = prevActivity.simulator;
//this.mNavigationDrawerFragment = prevActivity.mNavigationDrawerFragment;
//this.mTitle = prevActivity.mTitle;
Log.d("APP","Activity restarted: simulator recreated");
}
requestWindowFeature(Window.FEATURE_PROGRESS);
setContentView(R.layout.activity_main);
setProgressBarVisibility(true);
mNavigationDrawerFragment = (NavigationDrawerFragment) getSupportFragmentManager()
.findFragmentById(R.id.navigation_drawer);
mTitle = getTitle();
// Set up the drawer.
mNavigationDrawerFragment.setUp(R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout));
}
#Override
public Object onRetainCustomNonConfigurationInstance() {
//restore all your data here
return this;
}
...
There is a method in the activity that changes the selected section in the NavigationDrawer, in the UI thread because if not it crashes.
public void showHud() {
// TODO Auto-generated method stub
runOnUiThread( new Runnable() {
public void run() {
mNavigationDrawerFragment.select(1);
onSectionAttached(2);
restoreActionBar();
}
});
}
This method is used to go directly to display the simulation once the simulator has been connected.
PROBLEM:
All this system works except for when I connect the simulator after switching the orientation. It executes the runOnUiThread but it does nothing. I think the reason for that is that it loses the UI thread that created that view when the activity is restarted.
As you can see there are two lines commented in the reloading of the simulator where I also tried to save the NavigationDrawer object without success in the test: same behavior.
I also tried to save the prevActivity and in the method showHUD(), first asking if its null and if not, execute the method inside the prevActivity. Expecting that it will access the original UI Thread, but I was mistaken.
Is there any solution to keep this UI Thread during the restarting of an activity? or maybe another type of solution?
Thanks a lot.
You should be checking your onSavedInstanceState in your Activity. This is how the Android OS is designed to handle this. You are trying to do this yourself, when you should be relying on the OS supplied functionality.
Quite a few examples of this (if you search SO):
Android: Efficient Screen Rotation Handling
Handle screen rotation without losing data - Android
If you want to save configuration, you need to save specific things. You can do this in the onPause() or on onSaveInstanceState().
If onCreate() is called after your configuration change, you can get what you need back out of the bundle. when you get it back out, you can then set what you need.
See this: http://developer.android.com/training/basics/activity-lifecycle/recreating.html
I am correctly retaining the data object but after a device rotation the function in UI thread has no effect, a function to change the selected section in the NavigationDrawer. I thought it was because I was losing the correct UI thread but actually, what I was losing is this NavigationDrawerFragment.
Just by adding the setRetainInstance(true) line in the OnCreate() of the NavigationDrawerFragment solves the problem:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
...
In my app I am using TTS. I have 20 different activities which are changed when the user swipe left or right. According the activity, a text is spoken. I am executing tts with separate thread and activity selection is done with main thread. But the problem is very slow, the UI feels slugish. When I swipe left or right, once tts is finished speaking the text, the activity changes which shouldn't happen because I am using separate thread for tts.
Here is the codE:
TTS class:
public class textToSpeech {
TextToSpeech tts=null;
public textToSpeech(Context con)
{
tts = new TextToSpeech(con,new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if(status != TextToSpeech.ERROR) // initialization me error to nae ha
{
tts.setPitch(1.1f); // saw from internet
tts.setSpeechRate(0.4f); // f denotes float, it actually type casts 0.5 to float
tts.setLanguage(Locale.US);
}
}
});
}
public void SpeakText (String text)
{
tts.speak(text, TextToSpeech.QUEUE_FLUSH, null); // TextToSpeech.QUEUE_FLUSH forces the app to stop all the sounds that are currently playing before speaking this text
}
public void stopSpeak()
{
tts.stop();
}
Gesture Reader Class: (separate class)
public void decideAlphabet()
{
tts.stopSpeak();
threadForTTS.start();
switch (i)
{
case 0:
activities=null;
activities = new Intent(contxt,A.class);
contxt.startActivity(activities);
break;
case 1:
activities=null;
activities = new Intent(contxt,B.class);
contxt.startActivity(activities);
break;
....... 20 more case statements for selecting activities
}
decideActivity() method is called when it is checked, which swipe was made, swipe to right or left.
NOTE:
Before adding tts in this app, the UI was performing properly without lag or slowness. After I added TTS, the app became slow. How can I solve this problem
Regards
I had the same problem and was about to comment on seeing the following logcat error ...skipped x many frames. The application may be doing too much work on its main thread.
Of course I was sure TTS was being called from another thread which I checked using Thread.currentThread().getName() But it turns out however that OnInit was indeed still running on the main thread and it looks like setting the language is an expensive operation. A quick change to run contents of onInit in a new thread and the UI freezing/choreographer complaining stopped:
#Override
public void onInit(int status) {
new Thread(new Runnable() {
public void run() {
if(status != TextToSpeech.ERROR) // initialization me error to nae ha
{
tts.setPitch(1.1f); // saw from internet
tts.setSpeechRate(0.4f); // f denotes float, it actually type casts 0.5 to float
tts.setLanguage(Locale.US);
}
}
}
}).start()
I have this code that allows me to press a button to turn on my phones flashlight. What would be the best way to keep the light on, while the application is closed? I heard asynctask is good, but I read that it's meant for a background task that will communicate with the UI. What kind of "thread" should I use for this type of "application".
My onClickListener code:
button.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
//If Flag is set to true
if (isFlashOn) {
Log.i("info", "torch is turned off!");
//Set the flashmode to off
p.setFlashMode(Parameters.FLASH_MODE_OFF);
//Pass the parameter ti camera object
camera.setParameters(p);
//Set flag to false
isFlashOn = false;
//Set the button text to Torcn-ON
button.setText("Torch-ON");
}
//If Flag is set to false
else {
Log.i("info", "torch is turned on!");
//Set the flashmode to on
p.setFlashMode(Parameters.FLASH_MODE_TORCH);
//Pass the parameter ti camera object
camera.setParameters(p);
//Set flag to true
isFlashOn = true;
//Set the button text to Torcn-OFF
button.setText("Torch-OFF");
}
}});
}
Sounds that you need a service
A Service is an application component representing either an application's desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use
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.