I am trying to learn services and background threads that can update UI, here, this service is started by calling startService() method from MainActivity, the problem is: when the loop runs for a larger value of i, Toasts are not shown for all of the values (interestingly Toast made after the loop also not showing ), but this time I tested with 10/20 etc and working perfectly.
Here are codes, of MyService.java:
public class MyService extends IntentService {
Handler mhandler;
public MyService() {
super("Hello");
}
#Override
public void onCreate() {
Toast.makeText(this, "Service Starting!", Toast.LENGTH_SHORT).show();
super.onCreate();
mhandler = new Handler();
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
mhandler.post(new Runnable() {
#Override
public void run() {
int i;
for (i = 0; i < 100; i++) {
Toast.makeText(MyService.this, "i is: " + i, Toast.LENGTH_SHORT).show();
}
Toast.makeText(MyService.this, "finally i is: "+i, Toast.LENGTH_SHORT).show();
}
});
}
}
And request for some really helpful resources for very beginner on Android Services, Background Tasks, Broadcast receiver. I got developer.android.com (Not too.. helpful for beginner), www.vogella.com, etc. Thanks in advance.
I believe the reason you are only seeing the first few values of i is because android will not allow an application to spam the toast queue.
As mentioned by #David Wasser in the OP post's comments, Toast is not a reliable debugging tool.
Use the logcat instead:
Log.v("TAG", "Message")
Related
My app is working not correctly. Exactly when I click one button, I am logged out automatically. Here there is source code.
protected void previewStack() {
this.currentSubeditor.dataFromUIFields();
Toast.makeText(getApplicationContext(), "Generating preview..", Toast.LENGTH_SHORT).show();
updatePostButtonState();
Hype4DController controller = Hype4DController.getInstance();
controller.previewStack(getApplicationContext(), this, this.stack);
}
So I debugged on Toast.maketext() then it shows,
public Looper getMainLooper() {
return mBase.getMainLooper();
}
And warn that this loop is not in correct.
I think this is because of Toast maketext() function. Because other functions are working correctly.
So anyone please help me.
It seems that you run it in another thread, you must execute Toast in the main thread, you can try this:
activity.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(getApplicationContext(), "Generating preview..", Toast.LENGTH_SHORT).show();
}
});
Toast.makeText() should only be called from Main/UI thread :
protected void previewStack() {
this.currentSubeditor.dataFromUIFields();
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(getApplicationContext(), "Generatingpreview..",Toast.LENGTH_SHORT).show();
}
});
updatePostButtonState();
Hype4DController controller = Hype4DController.getInstance();
controller.previewStack(getApplicationContext(), this, this.stack);
}
I'have tried all kind of solutions and code but any of this solutions worked for me, and I don't know why. Please help me.
My MainActivity code is:
if(isNotificationServiceEnabled())
{
Intent i= new Intent(this,NotificationsService.class);
i.putExtra("command", "get_status");
startService(i);
}
else
startActivity(new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS));
Now I'm just tryng to check if the service read a nostification posted, but from log i can only see that it enters in onCreate method but no in onNotificationPosted.
This is the code for my service class:
public class NotificationsService extends NotificationListenerService {
#Override
public void onListenerConnected(){
Log.d(TAG, "Connected");
}
#Override
public void onNotificationPosted(final StatusBarNotification sbn){
Log.d(TAG,"got it");
}
I have tried also solutions with broadcast service , but it still doesn't work.
Thanks.
I have found the solutions. In my code I had some problems, but then I tested other code about notification listener in an other project, and It worked. So then I modify my code and now it works.
About notification lisener You don't need to launch the service, because when you launch the app the service is launched. So I just made this changes to my code:
Main
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(!isNotificationServiceEnabled())
{
startActivity(new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS));
}
}
#Override
protected void onDestroy() {
super.onDestroy();
}
And in the service I just put the log code to write in debug the notification package.
Instead I got that broadcast are just used to exchange the data between service and my activity, for example to write the notifications in a textview.
My App has a button to open reward videos >> when this button is pressed for the first time, it toasts "Check your Internet connection", when hit the second or third time, it shows the video with no problems
MobileAds.initialize(getActivity(), getString(R.string.VID_App_ID));
mRewardVideoAd = MobileAds.getRewardedVideoAdInstance(getActivity());
mRewardVideoAd.loadAd(getString(R.string.VID_App_Unit_ID), new AdRequest.Builder()
.addTestDevice(getString(R.string.TestDeviceID))
.build());
mRewardVideoAd.setRewardedVideoAdListener(this);
loadRewardedVideoAd();
Here are the methods used :
private void loadRewardedVideoAd() {
mRewardVideoAd.loadAd(getString(R.string.VID_App_Unit_ID), new AdRequest.Builder()
.addTestDevice(getString(R.string.TestDeviceID))
.build());
}
#OnClick(R.id.button_more_money)
public void more_money() {
if (mRewardVideoAd.isLoaded()) {
mRewardVideoAd.show();
} else
{
Toast.makeText(getActivity(), "Check your internet connection", Toast.LENGTH_LONG).show();
loadRewardedVideoAd();
}
}
#Override
public void onResume() {
mRewardVideoAd.resume(getActivity());
super.onResume();
loadRewardedVideoAd();
}
Edit: Solved
- It took some time and the solution was to load at onCreate()
Thanks to Martin De Simone and Avi Levin
Rewarded videos take time to load, your code is fine, the first time you are pressing, the video is loading and then when you press probably the video has already loaded.
Try to toast something in the onAdLoaded to check this
As Martin said, RV ad takes a time to load. basically, it needs to download ~30-second video which takes sometimes few second.
I recommend using the SDK provided RewardedVideoAdListener interface which will help you know when the ad is ready to show. furthermore, it will help you to understand the AdMob rewarded video ad's life cycle.
In order to use it you need to do the following phases:
Implement RewardedVideoAdListener listener in your java class
Override the following methods (I used Toast UI messages for visualization, it can be deleted)
Code:
#Override
public void onRewarded(RewardItem reward) {
Toast.makeText(this, "onRewarded! currency: " + reward.getType() + " amount: " +
reward.getAmount(), Toast.LENGTH_SHORT).show();
}
#Override
public void onRewardedVideoAdLeftApplication() {
Toast.makeText(this, "onRewardedVideoAdLeftApplication",
Toast.LENGTH_SHORT).show();
}
#Override
public void onRewardedVideoAdClosed() {
Toast.makeText(this, "onRewardedVideoAdClosed", Toast.LENGTH_SHORT).show();
}
#Override
public void onRewardedVideoAdFailedToLoad(int errorCode) {
Toast.makeText(this, "onRewardedVideoAdFailedToLoad", Toast.LENGTH_SHORT).show();
}
#Override
public void onRewardedVideoAdLoaded() {
Toast.makeText(this, "onRewardedVideoAdLoaded", Toast.LENGTH_SHORT).show();
}
#Override
public void onRewardedVideoAdOpened() {
Toast.makeText(this, "onRewardedVideoAdOpened", Toast.LENGTH_SHORT).show();
}
#Override
public void onRewardedVideoStarted() {
Toast.makeText(this, "onRewardedVideoStarted", Toast.LENGTH_SHORT).show();
}
BTW: before a show call, I recommend using isLoaded() method in order to if the AdMob is ready to show something, for example:
if (mAd.isLoaded()) {
mAd.show();
}
More information can be found inside Google AdMob doc's
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 have a crash report of the same error like in this question: WebView methods on same thread error
There it is suggested to create a Runnable().
I don't understand why exactly this solves the problem. The error says "Webview methods on same Thread", but the answer suggests to create the method on the UI-Thread (Main Thread). But isn't the UI-Thread the one and only thread? Could someone explain this whole process in detail (considering I create a new Webview in every activity in the constructor)?
My code to implement Javascript functions/methods looks like this:
public class JS_Bind {
private static final String TAG = "JS_Bind";
private Context context;
private AdvancedWebView mWebView;
public JS_Bind(Context c, AdvancedWebView mWebView) {
context = c;
this.mWebView = mWebView;
}
#JavascriptInterface
public void openActivity(String activityName) {
try {
Class activityClass = Class.forName(PACKAGE_NAME + "." + activityName);
context.startActivity(new Intent(MainActivity.this, activityClass));
} catch (ClassNotFoundException e) {
Toast.makeText(context, "Invalid activity name: " + activityName, Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
#JavascriptInterface
public void makeToast(String toast) {
Toast mToast = Toast.makeText(context, toast, Toast.LENGTH_SHORT);
mToast.setGravity(Gravity.CENTER, 0, 0);
mToast.show();
}
#JavascriptInterface
public void external(String url) {
mTracker.send(new HitBuilders.EventBuilder().setCategory("Action").setAction("External Link: " + url).build());
Uri uri = Uri.parse(url);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
#JavascriptInterface
public String showToken() {
return gcmToken;
}
#JavascriptInterface
public int showUid() {
SharedPreferences pref = getSharedPreferences("Pref", Activity.MODE_PRIVATE);
int uid = pref.getInt("uid", 0);
return uid;
}
#JavascriptInterface
public void buyPremium() {
bp.purchase(MainActivity.this, PRODUCT_ID);
}
}
Do I have to change EVERY function to this code (first answer in the question I refered to):
#JavascriptInterface
mWebView.post(new Runnable() {
#Override
public void makeToast() {
// ...
}
});
?
By the way, this is how I create the webview in the constructor activies onCreate method:
mWebView = (AdvancedWebView) findViewById(R.id.webView);
mWebView.setListener(this, this);
mWebView.addJavascriptInterface(new JS_Bind(this, mWebView), "Android");
mWebView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
if (!DetectConnection.checkInternetConnection(this)) {
mWebView.loadUrl("file:///android_asset/offline.html");
}
else {
mWebView.loadUrl("http://example.com/tw3/index.php?s=home");
}
But isn't the UI-Thread the one and only thread?
No. WebView has its own pool of threads. There can be many other threads in an Android application.
Do I have to change EVERY function to this code
Not necessarily.
First, I do not see how you are getting that error (A WebView method was called on thread 'JavaBridge'. All WebView methods must be called on the same thread.) from your #JavascriptInterface methods shown above. That error is when you call a method on the WebView itself, and you are not doing that.
You will need to use runOnUiThread() (or equivalent techniques) if:
Your #JavascriptInterface methods refer to the WebView itself, or
Your #JavascriptInterface try to do something else that has to be done on the main application thread (which will yield a different error message, as it will not be tied specifically to WebView)
Your startActivity() call might need to be called on the main application thread — I forget if that can be called on a background thread or not. Similarly with your Toast work — while I think that can be done on a background thread, I am not certain of it. It has been ages since I tried doing either of those things from a background thread.
Also, please only use your code if you control every single byte of what is being displayed in the WebView. Exposing startActivity() to arbitrary Web content has significant security implications.