I have an app that alot of users have helped me on so far and I really appreciate it. Now I have a force close issue when the case is exicuted below. When I click the button 2 it will load the Ship.Class and everything works like I want it too. When I click button1 It will not load Ocean.Class and it force closes. The Ocean.Class is a mirror of the Ship.Class except for the variable names have been updated to reflect the different class. Is using the variable (a) like I am in the switch not something that is allowable?
package com.androidsleepmachine.gamble;
import android.app.Activity;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
public class Ocean extends Activity implements View.OnClickListener {
public static final Integer[] TIME_IN_MINUTES = { 30, 45, 60, 180, 360 };
public MediaPlayer mediaPlayer;
public Handler handler = new Handler();
public Button button1;
public Spinner spinner1;
// Initialize the activity
#Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.ocean);
button1 = (Button) findViewById(R.id.btn1);
button1.setOnClickListener(this);
spinner1 = (Spinner) findViewById(R.id.spinner1);
ArrayAdapter<Integer> adapter = new ArrayAdapter<Integer>(this,
android.R.layout.simple_spinner_item, TIME_IN_MINUTES);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner1.setAdapter(adapter);
}
// Play the sound and start the timer
private void playSound(int resourceId) {
// Cleanup any previous sound files
cleanup();
// Create a new media player instance and start it
mediaPlayer = MediaPlayer.create(this, resourceId);
mediaPlayer.start();
// Create the timer to stop the sound after x number of milliseconds
int selectedTime = TIME_IN_MINUTES[spinner1.getSelectedItemPosition()];
handler.postDelayed(runnable, selectedTime * 60 * 1000);
}
// Handle button callback
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn1:
playSound(R.raw.ocean_birds);
break;
}
}
// Stop the sound and cleanup the media player
public void cleanup() {
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
// Cancel any previously running tasks
handler.removeCallbacks(runnable);
}
// Runnable task used by the handler to stop the sound
public Runnable runnable = new Runnable() {
public void run() {
cleanup();
}
};
}
This is what I gathered from the Logcat
09-17 11:11:15.704: I/dalvikvm(1634): | sysTid=1634 nice=0 sched=0/0 cgrp=[fopen- error:2] handle=-1207757760
09-17 11:11:58.690: E/Trace(1665): error opening trace file: No such file or directory (2)
09-17 11:18:47.446: I/dalvikvm(1735): | sysTid=1735 nice=0 sched=0/0 cgrp=[fopen-error:2] handle=-1207757760
09-17 11:39:46.139: E/Trace(1758): error opening trace file: No such file or directory (2)
09-17 11:39:53.705: I/dalvikvm(1758): | sysTid=1758 nice=0 sched=0/0 cgrp=[fopen-error:2] handle=-1207757760
09-17 11:40:00.356: E/Trace(1774): error opening trace file: No such file or directory (2)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.androidsleepmachine.gamble"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="18" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.androidsleepmachine.gamble.Home"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.androidsleepmachine.gamble.Ship" />
<activity android:name="com.androidsleepmachine.gamble.Ocean" />
</application>
</manifest>
Your Code works perfectly fine. I did try to run it even on the emulator and it's working perfectly fine:
public class Ocean extends Activity implements View.OnClickListener {
public static final Integer[] TIME_IN_MINUTES = { 30, 45, 60, 180, 360 };
public MediaPlayer mediaPlayer;
public Handler handler = new Handler();
public Button button1;
public Spinner spinner1;
// Initialize the activity
#Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.ocean);
button1 = (Button) findViewById(R.id.btn1);
button1.setOnClickListener(this);
spinner1 = (Spinner) findViewById(R.id.spinner1);
ArrayAdapter<Integer> adapter = new ArrayAdapter<Integer>(this,
android.R.layout.simple_spinner_item, TIME_IN_MINUTES);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner1.setAdapter(adapter);
}
// Play the sound and start the timer
private void playSound(int resourceId) {
// Cleanup any previous sound files
cleanup();
// Create a new media player instance and start it
mediaPlayer = MediaPlayer.create(this, resourceId);
mediaPlayer.start();
// Create the timer to stop the sound after x number of milliseconds
int selectedTime = TIME_IN_MINUTES[spinner1.getSelectedItemPosition()];
handler.postDelayed(runnable, selectedTime * 60 * 1000);
}
// Handle button callback
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn1:
playSound(R.raw.test);
/*
* getResources().openRawResource(R.raw.test);
*/break;
}
}
// Stop the sound and cleanup the media player
public void cleanup() {
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
// Cancel any previously running tasks
handler.removeCallbacks(runnable);
}
// Runnable task used by the handler to stop the sound
public Runnable runnable = new Runnable() {
public void run() {
cleanup();
}
};
}
The music keeps playing even when the app is closed.
I don't think there's anything wrong with the code.
Check whether you have added Ocean class (activity) in android manifest file .
Check whether you have id same as button1 in the layout .
Related
My Job executes perfectly if the app is open but if i close the app the jobservice is never executed. I have followed the tutorial here; Job Scheduler - Code In Flow and it just does not run (or maybe it runs and we do not know it runs?). I have put in notifications and Log.d methods with in my methods so i can see if the job runs and while the app is open the log msgs and notifications push through as expected.
Any help would be appreciated . Thank you
UPDATE 2
===============
I have discovered, since the job runs while the app is open, if i close the app the job gets cancelled without the onStopJob being called. theoretically if i am not wrong job scheduler should continue the job irrespective of the app running or not.
the Log.d msgs looks like this
D/global_PEA: Job Scheduled //Schedule Job Button Pressed
D/global_PEA: Job Started //ExJobService runs
D/global_PEA: run: 0
D/global_PEA: run: 1
D/global_PEA: run: 2
D/global_PEA: run: 3
D/global_PEA: run: 4
// App closed and the output and notifications stop
// in theory it should continue till 9
=======
UPDATE
===============
Here is the adb shell dump of my app. it looks like its scheduled?
I cant get any notification or Log.d msgs when i force run the job from adb like so
adb shell cmd jobscheduler run -f com.raaif.pea 902
which leads me to think that maybe the job does infact run but nothing is shown to the user about it like the notification. Is there any way it could notify the application, even if its openning the app when the job is done?
==============
here are my code files
public class HomeFragment extends Fragment {
private Context mContext;
private Button btn1;
private Button btn2;
#Override
public void onAttach(Context context) {
mContext = context;
super.onAttach(context);
}
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_home, container, false);
btn1 = root.findViewById(R.id.button1);
btn2= root.findViewById(R.id.button2);
btn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
scheduleJob();
}
});
btn2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
cancelJob();
}
});
return root;
}
public void scheduleJob(){
ComponentName componentName = new ComponentName(mContext, ExJobService.class);
JobInfo info = new JobInfo.Builder(JOB_ID_1, componentName)
.setRequiresCharging(false)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
.setPersisted(true)
.setPeriodic(15 * 60 * 1000)
.build();
JobScheduler scheduler = (JobScheduler) mContext.getSystemService(JOB_SCHEDULER_SERVICE);
int resultcode = scheduler.schedule(info);
if(resultcode==JobScheduler.RESULT_SUCCESS){
Log.d(globals.appTag,"Job Scheduled");
}else{
Log.d(globals.appTag,"Job Scheduling failed");
}
}
public void cancelJob(){
JobScheduler scheduler = (JobScheduler)getContext().getSystemService(JOB_SCHEDULER_SERVICE);
scheduler.cancel(JOB_ID_1);
Log.d(globals.appTag,"Job cancelled");
}
}
And here is my JobService class
import android.app.Notification;
import android.app.job.JobParameters;
import android.app.job.JobService;
import android.content.Intent;
import android.util.Log;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import static com.raaif.pea.Constants.CHANNEL_ID_NOTIFICATION_HIGH;
import static com.raaif.pea.Constants.HIGH_NOTIF_ID;
public class ExJobService extends JobService {
private Globals globals = Globals.getInstance();
private boolean jobcancelled = false;
private boolean reschedulestatus = false;
#Override
public boolean onStartJob(JobParameters params) {
Log.d(globals.appTag, "Job Started");
//output low notification
notify("Scheduled JobService", "Starting Background Work");
doBackgroundWork(params);
return true;
}
private void doBackgroundWork(final JobParameters params) {
new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < 10; i++) {
if (jobcancelled) return;
Log.d(globals.appTag, "run: " + i);
ExJobService.this.notify("Thread Iterator",
String.format("Iteration Count: %d", i));
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Log.d(globals.appTag, "Job Finished");
ExJobService.this.notify("Scheduled JobService", "Background Work Finished");
jobFinished(params, reschedulestatus);
Log.d(globals.appTag, "Job Service Params returned with " + reschedulestatus);
ExJobService.this.notify("Scheduled JobService", "Job Params returned");
}
}).start();
}
#Override
public boolean onStopJob(JobParameters params) {
Log.d(globals.appTag, "Job Cancelled before completion");
jobcancelled = true;
notify("OnStopJob", "Job Cancelled");
return false;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//return Service.START_STICKY;
return super.onStartCommand(intent, flags, startId);
}
public void notify(String title, String content) {
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
Notification notification =
new NotificationCompat.Builder(ExJobService.this, CHANNEL_ID_NOTIFICATION_HIGH)
.setSmallIcon(R.drawable.ic_memory_black_24dp)
.setContentTitle(title)
.setContentText(content)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setOnlyAlertOnce(false)
.build();
notificationManager.notify(HIGH_NOTIF_ID, notification);
}
}
Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.raaif.pea">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:name=".App"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<!-- SERVICES -->
<service android:name=".ExJobService"
android:permission="android.permission.BIND_JOB_SERVICE" />
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
I see here is a problem but i don't know how do you handle it?! look at this:
public class ExJobService extends JobService {
...
private boolean reschedulestatus = false;
#Override
public boolean onStartJob(JobParameters params) {
....
doBackgroundWork(params);
return true;
}
private void doBackgroundWork(final JobParameters params) {
new Thread(new Runnable() {
....
jobFinished(params, reschedulestatus);
....
}).start();
}
}
You are passing false to jobFinished method that unintentionally you do not reschedule the job.
When doing stuff periodically in the background — JobScheduler, WorkManager, AlarmManager etc. — you have to take into account that your process might not be around when it is time for you to do your work. Android will fork a process for you, but it is "starting from scratch". Anything that your UI might have set up in memory, such as a database, would have been for some prior process and might not be set up in the new process.
Currently i am working with an application and my app has a feature that the user will be able to click on a Navigate button and my app will start the Google Map. Till now it's fine and i have done it. But the fact where i am stuck is that i want my app to perform some tasks. To achieve that i have used JobService and scheduled it to run after every 5 seconds even when the app is in background.
When the user presses the back button then inside onDestroy method i have cancelled the scheduler. But when the app is removed from the background by sliding or pressing the cross icon the JobService keeps running as the onDestroy method can be called or not by the os when it is removed from the background. How can i stop the scheduled job when the app is removed from the background?
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="javarank.com.serviceinbackground">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MyJobService" android:exported="true" android:permission="android.permission.BIND_JOB_SERVICE" />
</application>
</manifest>
MyJobService class
public class MyJobService extends JobService {
#Override
public boolean onStartJob(final JobParameters jobParameters) {
Toast.makeText(getApplicationContext(), "Doing job", Toast.LENGTH_SHORT).show();
jobFinished(jobParameters, true);
return false;
}
#Override
public boolean onStopJob(JobParameters jobParameters) {
return false;
}
}
Here is my MainActivity
public class MainActivity extends AppCompatActivity {
private static final int JOB_ID = 1;
private JobInfo jobInfo;
private JobScheduler scheduler;
private Button navigateButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ComponentName componentName = new ComponentName(this, MyJobService.class);
JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, componentName);
builder.setPeriodic(5000);
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
// if true this job exists even after a system reboot...
builder.setPersisted(false);
jobInfo = builder.build();
scheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
scheduler.schedule(jobInfo);
navigateButton = (Button) findViewById(R.id.navigate_button);
navigateButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
StringBuffer url = new StringBuffer("https://www.google.com/maps/dir/?api=1");
url.append("&origin=23.755736,90.374627");
url.append("&destination=23.754047,90.371682");
url.append("&travelmode=driving");
Uri gmmIntentUri = Uri.parse(url.toString());
Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri);
mapIntent.setPackage("com.google.android.apps.maps");
startActivity(mapIntent);
}
});
}
#Override
protected void onDestroy() {
Toast.makeText(getApplicationContext(), "Destroy called.", Toast.LENGTH_SHORT).show();
scheduler.cancel(JOB_ID);
super.onDestroy();
}
}
I think you need to override following onStop() method and put stopService() command to stop the JobService.
#Override
protected void onStop() {
// A service can be "started" and/or "bound". In this case, it's "started" by this Activity
// and "bound" to the JobScheduler (also called "Scheduled" by the JobScheduler). This call
// to stopService() won't prevent scheduled jobs to be processed. However, failing
// to call stopService() would keep it alive indefinitely.
stopService(new Intent(this, MyJobService.class));
super.onStop();
}
You can create a new service like
MyService.java
public class MyService extends Service {
public MyService() {
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
//stop you jobservice from here
stopSelf();
}
}
and start it from MainActivity.java
startService(new Intent(MainActivity.this,MyService.class));
Android> 7 automatically saves battery power. You must turn on the application's battery saving stop feature.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Intent intent = new Intent();
String packageName = getPackageName();
PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
if (!pm.isIgnoringBatteryOptimizations(packageName)) {
intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + packageName));
startActivity(intent);
}
}
add this to AndroidManifest.xml
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
I faced this issue, but I found that after schedule job service, it can't be canceled (From view).
So I turned to stop it inside the job service by calling onStopJob(params)
and it worked.
I am currently working with ActivityRecognitionClient , but unfortunately that Google has announced that the class had been deprecated and to use GoogleApiClient instead.
Not sure if I am doing it wrong or not, I am getting confused with the new API file. I have imported the Google Play Libraries, setup the API v2 key. I followed an online source on coding up the ActivityRecognitionClient version.
Below are the codes of the different files, whenever I switch tab to the actRecog it crashes and points the error to this line with a null pointer exception.
mActivityRecognitionPendingIntent = PendingIntent.getService(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Full source code below : (API v2 keys are intentionally hidden for privacy purposes.)
MainActivity.java
package com.example.healthgps;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.app.Activity;
import android.app.TabActivity;
import android.content.Context;
import android.content.Intent;
import android.widget.TabHost;
import android.widget.TabHost.TabSpec;
public class MainActivity extends TabActivity {
TabHost mTabHost;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTabHost = getTabHost();
TabSpec firstSpec = mTabHost.newTabSpec("Stats");
firstSpec.setIndicator("Stats");
Intent firstIntent = new Intent(this, FirstActivity.class);
firstSpec.setContent(firstIntent);
TabSpec thirdSpec = mTabHost.newTabSpec("ActRecog");
thirdSpec.setIndicator("ActRecog");
Intent thirdIntent = new Intent(this, activityrecignition.class);
thirdSpec.setContent(thirdIntent);
mTabHost.addTab(firstSpec);
mTabHost.addTab(thirdSpec);
}
}
Manifest XML File :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.healthgps"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="11"
android:targetSdkVersion="17" />
<permission
android:name="com.example.healthgps.permission.MAPS_RECEIVE"
android:protectionLevel="signature" />
<uses-feature
android:glEsVersion="0x00020000"
android:required="true" />
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION"/>
<uses-permission android:name="com.example.healthgps.permission.MAPS_RECEIVE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" />
<activity
android:name="com.example.healthgps.MainActivity"
android:label="Health Kit"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".FirstActivity"
android:label="Health Kit" >
</activity>
<activity
android:name=".activityrecignition"
android:label="Health Kit" >
</activity>
<service
android:name="com.example.healthgps.ActivityRecognitionIntentService"
android:label="#string/app_name"
android:exported="false">
</service>
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
</application>
</manifest>
activityrecignition.java (purposely typo for the name)
package com.example.healthgps;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender.SendIntentException;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks;
import com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.ActivityRecognition;
import com.google.android.gms.location.ActivityRecognitionResult;
import com.google.android.gms.location.DetectedActivity;
public class activityrecignition extends FragmentActivity implements ConnectionCallbacks,OnConnectionFailedListener {
public static final int MILLISECONDS_PER_SECOND = 1000;
public static final int DETECTION_INTERVAL_SECONDS = 20;
public static final int DETECTION_INTERVAL_MILLISECONDS =
MILLISECONDS_PER_SECOND * DETECTION_INTERVAL_SECONDS;
private final static int
CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
private PendingIntent mActivityRecognitionPendingIntent;
// Store the current activity recognition client
private GoogleApiClient mGoogleApiClient;
private Context mContext;
private Intent intent;
TextView tv;
ActivityRecognitionIntentService ar;
private boolean mInProgress;
public enum REQUEST_TYPE {START, STOP}
private REQUEST_TYPE mRequestType;
Intent i;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.third);
mActivityRecognitionPendingIntent = PendingIntent.getService(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
tv=(TextView) findViewById(R.id.activityname);
mInProgress=false;
ar.onHandleIntent(i);
}
#SuppressLint("NewApi") public static class ErrorDialogFragment extends DialogFragment {
private Dialog mDialog;
#SuppressLint("NewApi") public ErrorDialogFragment() {
super();
mDialog = null;
}
public void setDialog(Dialog dialog) {
mDialog = dialog;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return mDialog;
}
public void show(FragmentManager supportFragmentManager, String tag) {
}
}
#Override
protected void onActivityResult(
int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case CONNECTION_FAILURE_RESOLUTION_REQUEST :
switch (resultCode) {
case Activity.RESULT_OK :
break;
}
}
}
private boolean servicesConnected() {
int resultCode =
GooglePlayServicesUtil.
isGooglePlayServicesAvailable(this);
if (ConnectionResult.SUCCESS == resultCode) {
Log.d("Activity Recognition", "Google Play services is available.");
return true;
} else {
Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
resultCode,
this,
CONNECTION_FAILURE_RESOLUTION_REQUEST);
if (errorDialog != null) {
// Create a new DialogFragment for the error dialog
ErrorDialogFragment errorFragment = new ErrorDialogFragment();
// Set the dialog in the DialogFragment
errorFragment.setDialog(errorDialog);
// Show the error dialog in the DialogFragment
errorFragment.show(
getSupportFragmentManager(),
"Activity Recognition");
}
return false;
}
}
public class ActivityRecognitionIntentService extends IntentService {
public ActivityRecognitionIntentService(String name) {
super(name);
// TODO Auto-generated constructor stub
}
private String getNameFromType(int activityType) {
switch(activityType) {
case DetectedActivity.IN_VEHICLE:
return "in_vehicle";
case DetectedActivity.ON_BICYCLE:
return "on_bicycle";
case DetectedActivity.ON_FOOT:
return "on_foot";
case DetectedActivity.STILL:
return "still";
case DetectedActivity.UNKNOWN:
return "unknown";
case DetectedActivity.TILTING:
return "tilting";
}
return "unknown";
}
#Override
protected void onHandleIntent(Intent intent) {
// If the incoming intent contains an update
if (ActivityRecognitionResult.hasResult(intent)) {
// Get the update
ActivityRecognitionResult result =
ActivityRecognitionResult.extractResult(intent);
// Get the most probable activity
DetectedActivity mostProbableActivity =
result.getMostProbableActivity();
/*
* Get the probability that this activity is the
* the user's actual activity
*/
int confidence = mostProbableActivity.getConfidence();
/*
* Get an integer describing the type of activity
*/
int activityType = mostProbableActivity.getType();
String activityName = getNameFromType(activityType);
tv.setText(activityName);
/*
* At this point, you have retrieved all the information
* for the current update. You can display this
* information to the user in a notification, or
* send it to an Activity or Service in a broadcast
* Intent.
*/
} else {
/*
* This implementation ignores intents that don't contain
* an activity update. If you wish, you can report them as
* errors.
*/
tv.setText("There are no updates!!!");
}
}
}
public void onClick(View v){
if(v.getId()==R.id.Start){
startUpdates();
}
if(v.getId()==R.id.Stop){
stopUpdates();
}
}
public void startUpdates() {
// Check for Google Play services
mRequestType = REQUEST_TYPE.START;
if (!servicesConnected()) {
return;
}
// If a request is not already underway
if (!mInProgress) {
// Indicate that a request is in progress
mInProgress = true;
// Request a connection to Location Services
mGoogleApiClient.connect();
//
} else {
/*
* A request is already underway. You can handle
* this situation by disconnecting the client,
* re-setting the flag, and then re-trying the
* request.
*/
mInProgress = true;
mGoogleApiClient.disconnect();
ActivityRecognition.ActivityRecognitionApi.requestActivityUpdates(mGoogleApiClient, DETECTION_INTERVAL_MILLISECONDS, mActivityRecognitionPendingIntent);
}
}
#Override
public void onConnected(Bundle dataBundle) {
// TODO Auto-generated method stub
ActivityRecognition.ActivityRecognitionApi.requestActivityUpdates(mGoogleApiClient, DETECTION_INTERVAL_MILLISECONDS, mActivityRecognitionPendingIntent);
/*
* Since the preceding call is synchronous, turn off the
* in progress flag and disconnect the client
*/
mInProgress = false;
mGoogleApiClient.disconnect();
switch (mRequestType) {
case START :
/*
* Request activity recognition updates using the
* preset detection interval and PendingIntent.
* This call is synchronous.
*/
ActivityRecognition.ActivityRecognitionApi.requestActivityUpdates(mGoogleApiClient, DETECTION_INTERVAL_MILLISECONDS, mActivityRecognitionPendingIntent);
break;
case STOP :
ActivityRecognition.ActivityRecognitionApi.removeActivityUpdates(mGoogleApiClient, mActivityRecognitionPendingIntent);
/*
* An enum was added to the definition of REQUEST_TYPE,
* but it doesn't match a known case. Throw an exception.
*/
default :
try {
throw new Exception("Unknown request type in onConnected().");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
}
#Override
public void onDisconnected() {
// TODO Auto-generated method stub
mInProgress = false;
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
// Turn off the request flag
mInProgress = false;
/*
* If the error has a resolution, start a Google Play services
* activity to resolve it.
*/
if (connectionResult.hasResolution()) {
try {
connectionResult.startResolutionForResult(
this,
CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (SendIntentException e) {
// Log the error
e.printStackTrace();
}
// If no resolution is available, display an error dialog
} else {
// Get the error code
int errorCode = connectionResult.getErrorCode();
// Get the error dialog from Google Play services
Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
errorCode,
this,
CONNECTION_FAILURE_RESOLUTION_REQUEST);
// If Google Play services can provide an error dialog
if (errorDialog != null) {
// Create a new DialogFragment for the error dialog
ErrorDialogFragment errorFragment =
new ErrorDialogFragment();
// Set the dialog in the DialogFragment
errorFragment.setDialog(errorDialog);
// Show the error dialog in the DialogFragment
errorFragment.show(
getSupportFragmentManager(),
"Activity Recognition");
}
}
}
public void stopUpdates() {
// Set the request type to STOP
mRequestType = REQUEST_TYPE.STOP;
/*
* Test for Google Play services after setting the request type.
* If Google Play services isn't present, the request can be
* restarted.
*/
if (!servicesConnected()) {
return;
}
// If a request is not already underway
if (!mInProgress) {
// Indicate that a request is in progress
mInProgress = true;
// Request a connection to Location Services
mGoogleApiClient.connect();
//
} else {
/*
* A request is already underway. You can handle
* this situation by disconnecting the client,
* re-setting the flag, and then re-trying the
* request.
*/
}
}
}
In the old code, it contains a part where the ActivityRecognitionClient requires an instantiation, but GoogleApiClient doesn't have.
Is there anyone who manage to switch over to the new API already ? I need some guide to get it there.
Thanks.
you must use GoogleApiClient.Builder in the following way
GoogleApiClient.Builder builder = new GoogleApiClient.Builder(<context>)
.addApi(<some api, i.e LocationServices.API>)
.addConnectionCallbacks(new ConnectionCallbacks() {
#Override
public void onConnectionSuspended(int arg) {}
#Override
public void onConnected(Bundle arg0) {
Intent intent = new Intent(getApplicationContext(), ActivityRecognitionService.class); // your custom ARS class
mPendingIntent = PendingIntent.getService(getApplicationContext(), 0, intent,PendingIntent.FLAG_UPDATE_CURRENT);
ActivityRecognition.ActivityRecognitionApi
.requestActivityUpdates(mGoogleApiClient, ACTIVITY_RECOGNITION_INTERVAL, mPendingIntent);}
}
.addOnConnectionFailedListener(new OnConnectionFailedListener() {
#Override
public void onConnectionFailed(ConnectionResult arg0) {
}
});
mGoogleApiClient = builder.build();
mGoogleApiClient.connect();
I know this is very lame but I'm totally new to android development. I'm writing a sensor based app which will change wallpaper each time the phone is shaked. Once the app is minimized it runs in background.
It works wonderfully when I run it for the first time.But When I minimize it and re-open it looks like 2 instances of the app are running. So it goes on. Every time I minimize and open the app, looks like one more instance is started in parallel.
Problem it causes:
1: Multiple instances of same app listening to "shake"
2: Multiple instances of same app trying to change wallpaper
3: Wallpaper change made by the the last instance of the app is noticeable
I tried setting below:
android:clearTaskOnLaunch="true"
android:launchMode="singleInstance"
Nothing works.
Kindly help.
Below is my activity class & Manifext file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="abhijit.android.sensor"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.SET_WALLPAPER" />
<application
android:name="abhijit.android.sensor.GlobalVarible"
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="abhijit.android.sensor.SensorTestActivity"
android:label="#string/app_name"
android:clearTaskOnLaunch="true"
android:launchMode="singleInstance" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
SensorTestActivity.java
package abhijit.android.sensor;
import java.io.IOException;
import java.util.Date;
import java.util.Random;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.WallpaperManager;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Vibrator;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class SensorTestActivity extends Activity implements SensorEventListener {
private SensorManager sensorManager;
private boolean color = false;
private View view;
TextView text;
private long lastUpdate;
Random rnd = new Random();
int colors;
private Vibrator vibrate;
GlobalVarible globalVariable;
WallpaperManager myWallpaperManager;
Button b1,b2,b3;
private static String AppVersion ="WALL-e v0.7 (Beta)";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
// requestWindowFeature(Window.FEATURE_NO_TITLE);
// getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sensor_test);
view = findViewById(R.id.textView);
text = (TextView) findViewById(R.id.textView);
view.setBackgroundColor(Color.GREEN);
b1 = (Button) findViewById(R.id.Enable_button);
b2 = (Button) findViewById(R.id.Dis_button);
b3 = (Button) findViewById(R.id.Exit_button);
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
vibrate = (Vibrator) getSystemService(VIBRATOR_SERVICE);
myWallpaperManager = WallpaperManager.getInstance(getApplicationContext());
lastUpdate = new Date().getTime();
// Calling Application class (see application tag in AndroidManifest.xml)
globalVariable = (GlobalVarible) getApplicationContext();
//Set name and email in global/application context
globalVariable.setCounter(0);
globalVariable.setWall(1);
System.out.println("Counter set to :" + globalVariable.getCounter());
}
#Override
public void onSensorChanged(SensorEvent event)
{
if ((event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) & globalVariable.appEnabled) {getAccelerometer(event);}
}
private void getAccelerometer(SensorEvent event) {
float[] values = event.values;
// Movement
float x = values[0];
float y = values[1];
float z = values[2];
float accelationSquareRoot = (x * x + y * y + z * z) / (SensorManager.GRAVITY_EARTH * SensorManager.GRAVITY_EARTH);
// long actualTime = event.timestamp;
long actualTime = (new Date()).getTime() + (event.timestamp - System.nanoTime()) / 1000000L;
if (accelationSquareRoot >= 3) //
{
long timediff = actualTime - lastUpdate;
if (timediff < 1000) {
return;
}
// Toast.makeText(this, "Detected device movement & working !!! ", Toast.LENGTH_SHORT).show();
globalVariable.setCounter(globalVariable.getCounter()+1);
vibrate.vibrate(300);
if (color)
{
colors= Color.argb(255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
view.setBackgroundColor(colors);
} else {
view.setBackgroundColor(colors);
}
color = !color;
System.out.println("Counter # " + globalVariable.getCounter());
if(globalVariable.getCounter()==1)
{
globalVariable.setCounter(0);
try
{
switch (globalVariable.getWall())
{
case 1:myWallpaperManager.setResource(R.drawable.wall1);break;
case 2:myWallpaperManager.setResource(R.drawable.wall2);break;
case 3:myWallpaperManager.setResource(R.drawable.wall3);break;
case 4:myWallpaperManager.setResource(R.drawable.wall4);break;
case 5:myWallpaperManager.setResource(R.drawable.wall5);break;
case 6:myWallpaperManager.setResource(R.drawable.wall6);break;
case 7:myWallpaperManager.setResource(R.drawable.wall7);break;
case 8:myWallpaperManager.setResource(R.drawable.wall8);break;
case 9:myWallpaperManager.setResource(R.drawable.wall9);break;
case 10:myWallpaperManager.setResource(R.drawable.wall10);break;
case 11:myWallpaperManager.setResource(R.drawable.wall11);break;
case 12:myWallpaperManager.setResource(R.drawable.wall12);break;
case 13:myWallpaperManager.setResource(R.drawable.wall13);break;
case 14:myWallpaperManager.setResource(R.drawable.wall14);break;
case 15:myWallpaperManager.setResource(R.drawable.wall15);break;
case 16:myWallpaperManager.setResource(R.drawable.wall16);break;
case 17:myWallpaperManager.setResource(R.drawable.wall17);break;
case 18:myWallpaperManager.setResource(R.drawable.wall18);break;
case 19:myWallpaperManager.setResource(R.drawable.wall19);break;
case 20:myWallpaperManager.setResource(R.drawable.wall20);break;
case 21:myWallpaperManager.setResource(R.drawable.wall21);break;
case 22:myWallpaperManager.setResource(R.drawable.wall22);break;
case 23:myWallpaperManager.setResource(R.drawable.wall23);break;
case 24:myWallpaperManager.setResource(R.drawable.wall24);break;
case 25:myWallpaperManager.setResource(R.drawable.wall25);break;
case 26:myWallpaperManager.setResource(R.drawable.wall26);break;
case 27:myWallpaperManager.setResource(R.drawable.wall27);break;
default:break;
}
Toast.makeText(this, "Successfully set as wallpaper to :"+globalVariable.getWall(), Toast.LENGTH_SHORT).show();
System.out.println("Counter : Wallerpaper Set to #"+globalVariable.getWall());
globalVariable.setWall(globalVariable.getWall()+1);
if(globalVariable.getWall()>27) globalVariable.setWall(1);
lastUpdate = actualTime;
} catch (IOException e)
{Toast.makeText(this, "Error set as wallpaper :", Toast.LENGTH_SHORT).show();}
}
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
#Override
protected void onResume() {
super.onResume();
// register this class as a listener for the orientation and
// accelerometer sensors
sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),SensorManager.SENSOR_DELAY_NORMAL);
Toast.makeText(this, "Sensor detection resumed !!!", Toast.LENGTH_SHORT).show();
}
#Override
protected void onPause() {
// unregister listener
super.onPause();
// sensorManager.unregisterListener(this);
Toast.makeText(this, "Sensor detection running in background !!!", Toast.LENGTH_SHORT).show();
// System.exit(0);
}
public void b1_Onclick(View v)
{
System.out.println("new Enabled!!!");
globalVariable.appEnabled=true;
sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),SensorManager.SENSOR_DELAY_NORMAL);
text.setText("Application is [ ENABLED ]");
}
public void b2_Onclick(View v)
{
System.out.println("new Disbled!!!");
globalVariable.appEnabled=false;
sensorManager.unregisterListener(this);
text.setText("Application is [ DISABLED ]");
}
public void b3_Onclick(View v)
{
System.out.println("new exit!!!");
sensorManager.unregisterListener(this);
this.onPause();
this.finish();
}
public void b4_Onclick(View view)
{
AlertDialog.Builder dlgAlert = new AlertDialog.Builder(this);
dlgAlert.setMessage(AppVersion + " \n \nCopyright \u00a9 2014, \nAbhijit Mishra");
dlgAlert.setTitle(AppVersion);
dlgAlert.setPositiveButton("OK", null);
dlgAlert.setCancelable(true);
dlgAlert.create().show();
dlgAlert.setPositiveButton("Ok", new DialogInterface.OnClickListener(){public void onClick(DialogInterface dialog, int which){}});
}
}
GlobalVariable.Java
package abhijit.android.sensor;
import android.app.Application;
public class GlobalVarible extends Application{
public int counter,wall;
boolean appEnabled=true;
public int getWall() {
return wall;
}
public void setWall(int wall) {
this.wall = wall;
}
public int getCounter() {
return counter;
}
public void setCounter(int counter) {
this.counter = counter;
}
}
Please let me know what should I do next so that Only 1 thread of the the application runs even if I minimize and bring it back up.
Regards,
Abhijit
The problem is here:
#Override
protected void onResume() {
super.onResume();
// register this class as a listener for the orientation and
// accelerometer sensors
sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
protected void onPause() {
// unregister listener
// sensorManager.unregisterListener(this);
}
You're not unregistering the listener, so it is registered multiple times.
I understand that what you want to do is to keep listening even if the activity is paused, and you could use a boolean flag to only register once. But it's probably not a good idea. Activites that are not visible can be finished by the system at any time.
For these kinds of use cases a Service would be far more appropriate (as a bonus, you could set it up to start on BOOT_COMPLETED, so that you don't need to re-run the app to set up this listener when you restart the device).
So, in short, I would recommend:
Create a Service. In onCreate(), register the service as a listener to SensorManager (very much as you do here).
When your activity runs, send an Intent to start the service (see docs).
Optionally, specify a listener for ACTION_BOOT_COMPLETED so that the service is restarted when the device restarts. See this answer.
I am creating an android app and when I go to debug it on my samsung galaxy the Splash activity loads first,as it should, but after that the app crashes/stops right after doing the "Splash" activity. It doesn't go to the "MainActivity" activity after the thread sleeps for 5 seconds. Does anyone know what might be causing the problem? Plus after I tried debugging the app and loaded it onto my phone the app isn't even showing up. I am using Eclipse by the way. It shows the app in my application manager on my phone but it doesn't show the icon in my app screen.
Here is my Splash.java:
package com.example.mihirsandroidapp;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
public class Splash extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
Thread timer = new Thread(){
public void run(){
try{
sleep(5000);
} catch (InterruptedException e){
e.printStackTrace();
}finally{
Intent openMainActivity = new Intent("com.example.mihirandroidsapp.MAINACTIVITY");
startActivity(openMainActivity);
}
}
};
timer.start();
}
#Override
protected void onPause() {
super.onPause();
finish();
}
}
Here is my Manifest:
<?xml version="1.0" encoding="utf-8"?>
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19" />
<application
android:debuggable="true"
android:allowBackup="true"
android:icon="#drawable/cartooncat"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".Splash"
android:label="#string/app_name" >
<intent-filter>
<action android:name="com.example.mihirsandroidapp.SPLASH" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="com.example.mihirsandroidapp.MAINACTIVITY" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
And here is my main activity which should start after the splash screen:
package com.example.mihirsandroidapp;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
int counter;
Button add, sub;
TextView display;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
counter = 0;
add = (Button) findViewById(R.id.bAdd);
sub = (Button) findViewById(R.id.bSub);
display = (TextView) findViewById(R.id.tvDisplay);
add.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
counter += 1;
display.setText("Total is " + counter);
}
});
sub.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
counter -= 1;
display.setText("Total is " + counter);
}
});
}
}
Oh.. Where do I start.. Let's go through all of the issues:
1) Fix your manifest. Definitely not the right way to declare your activities. Here is what it should look like:
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19" />
<application
android:debuggable="true"
android:allowBackup="true"
android:icon="#drawable/cartooncat"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".Splash"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
</activity>
</application>
2) Now let's fix the way you start your activity:
Intent openMainActivity = new Intent(Splash.this, MainActivity.class);
3) Don't call finish() in onPause() - you break native activity lifecycle flow. Call finish() right after you start new activity:
Intent openMainActivity = new Intent(Splash.this, MainActivity.class);
startActivity(openMainActivity);
finish();
4) Instead of creating separate thread, just a create a Handler and post Runnable there with 5 seconds delay:
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//this will be called after 5 seconds delay
}
}, 5000);
Here is entire file put together:
public class Splash extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
Intent openMainActivity = new Intent(Splash.this, MainActivity.class);
startActivity(openMainActivity);
finish();
}
}, 5000);
}
If it doesn't help - we definitely need to look at logcat output...
A simple way to achieve this if one is ready to compromise on drawing performance is to define custom theme with splash image that one wants to use as window background and use this custom theme as application theme
styles.xml
<resources>
<style name="CustomTheme" parent="android:Theme">
<item name="android:windowBackground">#drawable/background_image</item>
<item name="android:windowNoTitle">true</item>
</style>
</resources>
AndroidManifest.xml
<application
android:debuggable="true"
android:icon="#drawable/icon"
android:theme="#style/CustomTheme"
android:label="#string/app_name">
...
</application>
This would use the #drawable/background_image as the window.background. As a result if the activities has transparent background then #drawable/background_image will be visible as activities background. One can avoid this by setting appropriate color or drawable in onCreate of every activity programatically as
public void onCreate(){
super.onCreate(savedInstanceState);
setContentView(R.layout.layoutResID);
activity.getWindow().setBackgroundDrawableResource(R.color.window_bg);
}
Check this for more information
All what you need for a splash screen
SplashActivity.java
public class SplashActivity extends AppCompatActivity {
private final int SPLASH_DISPLAY_DURATION = 1000;
#Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
new Handler().postDelayed(new Runnable(){
#Override
public void run() {
Intent mainIntent = new Intent(SplashActivity.this,MainActivity.class);
SplashActivity.this.startActivity(mainIntent);
SplashActivity.this.finish();
}
}, SPLASH_DISPLAY_DURATION);
}}
In drawables create this bg_splash.xml
<?xml version="1.0" encoding="utf-8"?><layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="#color/app_color"/>
<item>
<bitmap
android:gravity="center"
android:src="#drawable/ic_in_app_logo_big"/>
</item></layer-list>
In styles.xml create a custom theme
<style name="SplashTheme" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowBackground">#drawable/bg_splash</item>
</style>
and finally in AndroidManifest.xml specify the theme to your activity
<activity
android:name=".activities.SplashActivity"
android:label="#string/app_name"
android:screenOrientation="portrait"
android:theme="#style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Cheers.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Thread th = new Thread(new Runnable() { /*create a new thread */
#Override
public void run() { /*
* The purpose of this thread is to
* navigate from one class to another
* after some time
*/
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
/*
* We are creating this new thread because we don’t
* want our main thread to stop working for that
* time as our android stop working and some time
* application will crashes
*/
e.printStackTrace();
}
finally {
Intent i = new Intent(MainActivity.this,
Splash_Class.class);
startActivity(i);
finish();
}
}
});
th.start(); // start the thread
}
http://www.codehubb.com/android_splash_screen
I have added splash screen by using following code:
public class SplashActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash_layout);
initConstatnts();// method for intilizing any constants
new Thread(new Runnable() {
#Override
public void run() {
if (!isFinishing()) // checking activity is finishing or not
{
try {
Thread.sleep(3000);//delay
Intent i = new Intent(getBaseContext(),
HomeActivity.class);
startActivity(i);
finish();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}).start();
}
private void initConstatnts() {
}
}
Flow the below steps to Create your own splash screen
Create Activity1 and XML file
Design the XML file and put the welcome message
Crete Activity2 and XML file.
Start the Activity1
Start a Thread in Activity1 and sleep for 5 seconds
Start Activity2 from the Thread
There is nothing called readymade splash screen in Android . we can achieve that using above steps.
In a single line, start Activity1 wait for 5 sec then start Activity2.
So user will feel that first screen is splash screen.
You can download the complete code from below link
http://javaant.com/splash-screen-android/#.VwzHz5N96Hs
i have faced the same problem.... i think you code is perfect for the app
u just try with this in the Intent Creation in your splash activity class
Intent openMainActivity = new Intent("android.intent.action.MAIN");//MAIN is the that u want to start
//next after the current Activity