I've included a custom AlertDialog in my app. After updating my Galaxy Nexus to Jelly Bean the dialog is not displayed anymore. Only the screen is darkened. The processes around the dialog (like loading data) are working perfectly. On older OS versions the code worked (including ICS 4.0.4).
The problem appears no matter the dialog is created and shown in an AsyncTask or outside.
Has anybody similar problems?
Here is the code:
public class TLProgressDialog extends AlertDialog{
/*Log tag */
#SuppressWarnings("unused")
private static final String TAG = "TLProgressDialog";
#SuppressWarnings("unused")
private Context context;
private AnimationDrawable animation;
protected TLProgressDialog(Context context) {
super(context);
this.context = context;
}
public TLProgressDialog(Context context, boolean cancelable,
OnCancelListener cancelListener) {
super(context, cancelable, cancelListener);
this.context = context;
}
public TLProgressDialog(Context context, int theme) {
super(context, theme);
this.context = context;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tlprogressdialog);
ImageView img = (ImageView)findViewById(R.id.dialog_img);
img.setBackgroundResource(R.drawable.tlprogress_animation);
animation = (AnimationDrawable) img.getBackground();
img.post(new Starter());
}
public static TLProgressDialog show(Context context){
TLProgressDialog dlg = new TLProgressDialog(context);
dlg.setCanceledOnTouchOutside(false);
dlg.setCancelable(false);
dlg.show();
return dlg;
}
private class Starter implements Runnable {
public void run() {
animation.start();
}
}
}
The xml layout is just a single ImageView which hostes an animated image:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="#+id/dialog_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"/>
</RelativeLayout>
Did you uncheck "Show notification" for your app? (check it in Settings/apps/ and "show notifications").
My fault, just found out that I've included GIF's for the animation. This seems not working anymore. After converting to PNG's it works again.
Related
I have activity and when it is created it sends some requests, so it takes time to load this activity.
Is it possible to show "loading layout" while requests are proceeding?
I tried something like this, but it doesn't work:
setContentView(R.layout.loading);
sendRequests();
setContentView(R.layout.main);
To accomplish this, you could add a "loading layout" to your main layout.
Something like this:
<FrameLayout
android:id="#+id/loading_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Loading stuff" />
</FrameLayout>
Then when it is time to show your loading layout you can do:
FrameLayout loadingLayout = findViewById(R.id.loading_layout);
loadingLayout.setVisibility(View.VISIBLE);
When you want to hide it simply:
loadingLayout.setVisibility(View.GONE);
You will want to make sure that you do network requests off of the main thread, and return to the main thread whenever it is time to update the UI (i.e. show/hide the loading layout).
You can add a progress bar in activity or fragment.
If you are using Retrofit or etc., use this approach:
Set the progressbar visible before request
and invisible it when onResponse or onFailure called
binding.progressBar.setVisibility(View.VISIBLE);
// request
call.enqueue(new Callback<MovieResponse>() {
#Override
public void onResponse(Response<MovieResponse> response) {
Log.d(TAG, "onResponse is called");
// invisible progress bar here
binding.progressBar.setVisibility(View.INVISIBLE);
if (!response.isSuccess()) {
Log.d(TAG, "No Success");
}
mMovieList = response.body().getMovies(); // <- response is null here
mMovieAdapter.notifyDataSetChanged();
}
#Override
public void onFailure(Throwable t) {
Log.i(TAG, "onFailure is called");
// invisible progress bar here
binding.progressBar.setVisibility(View.INVISIBLE);
Toast.makeText(getActivity(), "Failed !", Toast.LENGTH_LONG).show();
}
});
You can create common class for custom progress dialog,
public class CustomProgressDialog extends Dialog {
public CustomProgressDialog(#NonNull Context context) {
super(context);
init(context);
}
public CustomProgressDialog(#NonNull Context context, int themeResId) {
super(context, themeResId);
init(context);
}
protected CustomProgressDialog(#NonNull Context context, boolean cancelable, #Nullable OnCancelListener cancelListener) {
super(context, cancelable, cancelListener);
init(context);
}
void init(Context context) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().getDecorView().getRootView().setBackgroundResource(android.R.color.transparent);
getWindow().setDimAmount(0.1f);
getWindow().getDecorView().setOnApplyWindowInsetsListener((v, insets) -> {
insets.consumeSystemWindowInsets();
return insets;
});
View view = LayoutInflater.from(context).inflate(
R.layout.dialog_custom, null
);
setContentView(view);
setCancelable(false);
setCanceledOnTouchOutside(false);
}
}
dialog_custom.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="10dp">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_centerHorizontal="true"
android:indeterminateTint="#color/colorPrimary" />
</RelativeLayout>
Declare this class in your activity or parent activity to use in every child classes,
public class BaseFragment extends Fragment {
protected CustomProgressDialog mDialog;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDialog = new CustomProgressDialog(requireActivity());
}
}
To show dialog before your api call
mDialog.show();
To dismiss dialog in response or error
mDialog.dismiss();
I found this link that states how I could make the glow effect on my ImageButton. So whenever the user press the ImageButton the onTouchEvent() function is called and there I call the setImageBitmap() function. The problem is this function (setImageBitmap()) seems to have no effect at all.
What works:
1) So far I extended the ImageButton as below
// Pen.java
public class Pen extends ImageButton {
public Pen(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
System.out.println("Now I am setting Pen");
return true;
}
}
Then inside Activity I create Pen (custom ImageButton) instance, define setGlow() and call setImageBitmap() from instance of Pen.
//MainActivity.java
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Pen myImgbutton;
myImgbutton = (Pen) findViewById(R.id.pen);
myImgbutton.setImageBitmap(setGlow(R.drawable.pen));
}
}
public Bitmap setGlow(int resourceId) {
......
}
What doesn't work:
1) All same as above ( extending a ImageButton in android ), but this time I am calling the
setImageBitmap function from inside onTouchEvent(). For this case I have define setGlow function in inside Pen.java
// Pen.java
public class Pen extends ImageButton {
public Pen(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
System.out.println("Now I am setting Pen");
// Here I say to apply the glow effect to the image
setImageBitmap(setGlow(R.drawable.pen));
return true;
}
public Bitmap setGlow(int resourceId) {
....
}
}
Then in xml file I do :
.....
<com.example.testsetimagebmp.Pen
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/pen"
android:background="#drawable/pen" />
....
Finally in MainActivity
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
// ....
}
I think this might be the classic out of memory issue. You can try to use the bitmap of the launcher icon if you want to check whether this is true:
public class Pen extends ImageButton {
public Pen(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
System.out.println("Now I am setting Pen");
// Here I say to apply the glow effect to the image
setImageBitmap(setGlow(R.mipmap.ic_launcher));
return true;
}
public Bitmap setGlow(int resourceId) {
....
}
}
If this is the problem check this link.
You can't do that because you will out of memory if you put setImageBitmap(setGlow(R.drawable.pen)) in onTouchEvent.
onTouchEvent will be triggered serval times per second.And you will create serval bitmaps in memory per second.It will out of memory before you setImageBitmap successfully.
I built the project as you post, but it works fine. It sets the Bitmap correctly. So maybe the getGlow() method doesn't work well. Make some Logs as below
public Bitmap setGlow(int resourceId) {
Bitmap bm = BitmapFactory.decodeResource(getResources(),resourceId);
Log.e("tag", "Size: " + bm.getByteCount());
return bm;
}
then check whether the return is right.
I'm searching for a solution to preload some videos from different urls into VideoViews, so that they could be played without any delay.
I'm trying to do this in an async task:
class VideoPreloadTask extends AsyncTask<String, Void, Void> {
private Context mContext;
private CustomVideoView mVideoView;
public VideoPreloadTask(Context context) {
mContext = context;
}
#Override
public void onPreExecute() {
mVideoView = new CustomVideoView(mContext);
}
#Override
protected Void doInBackground(String... params) {
final String url = params[0];
mVideoView.setVideoPath(url);
mVideoView.setOnPreparedListener(new OnPreparedListener() {
//Wird aufgerufen, wenn das Video fertig geladen ist
#Override
public void onPrepared(MediaPlayer mp) {
mCounter++;
mVideoView.pause();
mVideoView.setPreloaded(true);
//Fuege das fertig geladene Video der Liste hinzu
mVideos.put(url, mVideoView);
}
});
mVideoView.start();
return null;
}
}
Now within the doInBackground-Method I set the path Url and start the loading of the video with start(). But the onPrepare-Listener does not work. The function never gets called and I don't understand why. I've tried loading some videos outside of an async task and it works well.
The async tasks are started like this:
for(String url : videoUrls) {
VideoPreloadTask task = new VideoPreloadTask(context);
task.execute(url);
}
and my CustomVideoView-Class looks like the following:
public class CustomVideoView extends VideoView {
private boolean mPreloaded = false;
private String mPath = "";
public CustomVideoView(final Context context) {
super(context);
}
public CustomVideoView(final Context context, final AttributeSet set) {
super(context, set);
}
#Override
public void setVideoPath(String url) {
super.setVideoPath(url);
mPath = url;
}
public boolean isPreloaded() {
return mPreloaded;
}
public void setPreloaded(boolean isPreloaded) {
mPreloaded = isPreloaded;
}
public String getVideoPath() {
return mPath;
}
}
Does anybody know, what causes this behaviour or where I've made a mistake?
Finally solved my problem. For everyone whos interested, heres the answer:
It seems as if Android only preloads the VideoViews video, when the view is part of an XML-Layout, which is also currently active. So if you want to preload a video, make the videoview part of your xml and do not create a videoview-object with the constructor, as I've done it.
Then it should work! :D
I'm a newbie to OpenGL on Android and last week I described a problem failing to get the renderer to start for a GLSurfaceView declared in the layout. It starts fine if I declare the renderer in the Activity class and setContentView to it. Here's a simplifed version with all the source code. What am I doing wrong?
Layout . . .
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/dummy"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="a Button" />
<FrameLayout
android:id="#+id/framelay"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.test.rendertest.RTSurface
android:id="#+id/RTSurfaceView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</FrameLayout>
</LinearLayout>
Activity class. UNcomment the //A's, and comment-out the //B's and the renderer runs. But as shown below the renderer does not run even though its constructor gets called.
public class RenderTest extends Activity {
RTSurface myView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// myView = new RTSurface(this); // A
// setContentView(myView); //A
setContentView(R.layout.main); // B
myView = (com.test.rendertest.RTSurface)findViewById(R.id.RTSurfaceView); //B
}
#Override
protected void onPause() {
super.onPause();
myView.onPause();
}
#Override
protected void onResume() {
super.onResume();
myView.onResume();
}
}
GLSurfaceView . . .
class RTSurface extends GLSurfaceView {
private final RTRenderer renderer;
public RTSurface(Context context) {
super(context);
Log.i("rendertest", "RTSurface constructor - Default Form");
renderer = new RTRenderer();
setRenderer(renderer);
}
public RTSurface(Context context, AttributeSet attrs) {
super(context, attrs);
Log.i("rendertest", "RTSurface constructor - Layout Form");
renderer = new RTRenderer();
setRenderer(renderer);
}
}
. . . and the Renderer (just stubs)
class RTRenderer implements GLSurfaceView.Renderer {
public RTRenderer () {
// a constructor just to have somewhere to set
// breakpoints and logcat messages
Log.i("rendertest", "RTRenderer Constructor");
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
Log.i("rendertest", "onSurfaceCreated in RTRenderer");
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
Log.i("rendertest", "onSurfaceChanged in RTRenderer");
}
public void onDrawFrame(GL10 gl) {
Log.i("rendertest", "onDrawFrame in RTRenderer");
}
}
Thanks in advance!!
You didn't specify your LinearLayout orientation, so it is set to horizontal by default. This means your GLSurfaceView is outside of the screen (because you set your button width to fill_parent).
Just add the following attribute to your LinearLayout :
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
I made a simple extension of CheckBoxPreference so that I could have my own custom view with an image icon to the left of the title. The code is below:
public class CustomCheckBoxPreference extends CheckBoxPreference {
private Drawable icon;
public CustomCheckBoxPreference(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.CustomCheckBoxPreference, 0, 0);
icon = arr.getDrawable(R.styleable.CustomCheckBoxPreference_icon);
setLayoutResource(R.layout.custom_checkbox_pref);
}
#Override
protected void onBindView(View view) {
super.onBindView(view);
ImageView prefsIcon = (ImageView) view.findViewById(R.id.prefs_icon);
prefsIcon.setImageDrawable(icon);
}
The problem is that for some reason the OnPreferenceChangeListener I set to any CustomCheckboxPreference has no effect and is not stored. I tried overriding some of the android methods for the implementation calling super and then printing a line to see what gets called. Notably callChangeListener does not get called. It is this method that leads to the callback for onPreferenceChanged. I tried throwing in a call to onPreferenceChanged inside of setChecked just to see what would happen and the OnPreferenceChangeListener is null:
getOnPreferenceChangeListener().onPreferenceChange(this, checked);
This is how I set the preferencechangelistener:
mTwitterPref.setChecked(!mTwitter.needsAuth());
mTwitterPref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
System.out.println("Twitter Preference Changed!");
if ((Boolean) newValue) {
if (mTwitter.needsAuth()) {
System.out.println("We Need To Login To Twitter!");
IntentUtils.startActivityForResult(ProfileAccountsActivity.this,
TwLoginActivity.class, ACTIVITY_OAUTH);
}
} else {
showDialog(DIALOG_LOGOUT_TWITTER);
}
return false;
}
});
I am a bit confused as to why the preferencechangelistener is not working properly as I only overwrite onBindView and the constructor; I call super in both. Any thoughts?
Set android:focusable="false" and android:clickable="false" on the CheckBox:
<CheckBox
android:id="#+android:id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false"
android:clickable="false" />
More info on this thread: Clickable rows on custom ArrayAdapter
I had the same issue with custom button. I tried the solution provided by #jeanh and it works. But my button was not pressed, only area around it was highlighted. Moreover, what if you have a few buttons? Obviously, that this solution won't work. So, I decided to dig deeper and my solution was below:
xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/widget_frame" android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingLeft="15dp"
android:paddingTop="5dp"
android:paddingRight="10dp"
android:paddingBottom="5dp"
>
<!-- define my button -->
<Button android:id="#android:id/title"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="17sp"
android:typeface="sans"
android:textStyle="bold"
android:textColor="#000000"
></Button>
</RelativeLayout>
Java class:
public class ButtonPreference extends Preference {
private final String TAG = getClass().getName();
public interface ButtonListener {
public void onCustomClick();
}
public ButtonListener buttonListener;
public void setButtonListener(ButtonListener buttonListener){
this.buttonListener = buttonListener;
}
public ButtonPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ButtonPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected View onCreateView(ViewGroup parent){
RelativeLayout layout = null;
try {
LayoutInflater mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
layout = (RelativeLayout)mInflater.inflate(R.layout.button_preference, parent, false);
//FIND OUR BUTTON IN LAYOUT
Button button = (Button) layout.findViewById(android.R.id.title);
if(button!=null){
Log.e(TAG, "button found");
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(buttonListener!=null){
buttonListener.onCustomClick(); //INVOKE OUR EVENT!
}
}
});
}
}
catch(Exception e)
{
Log.e(TAG, "Error creating info preference", e);
}
return layout;
}
}
HOW TO USE IT? Simple!
public class WallpaperSettings extends PreferenceActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.prefs);
ButtonPreference defaultSettingsButton = (ButtonPreference) findPreference(EngineCore.pref+"defaultSettings");
defaultSettingsButton.setButtonListener(new ButtonListener() {
#Override
public void onCustomClick() {
Gdx.app.log("ButtonListener", "onCustomClick");
}
});
}
}
I hope it helps someone else.
I found solution !
In my case, I extends DialogPreference to my custom Dialog class,
public class SvDialogPreference extends DialogPreference
I also confuse, because in PreferenceFragment, onPreferenceChange never worked.
SvDialogPreference pref= (SvDialogPreference) findPreference("mainKey");
if( pref != null ) {
pref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
// Never execute !
}}
To resolve this. I called "super.callChangeListener" in onDialogClosed.
public class SvDialogPreference extends DialogPreference{
....
#Override
protected void onDialogClosed(boolean positiveResult) {
double InputValue = Double.parseDouble(KEY.getText().toString());
super.callChangeListener(InputValue);
super.onDialogClosed(positiveResult);
}
Now, onPreferenceChange worked fine !