setContentView() Crashes when used with GLSurfaceView - java

I have been trying to make my first android app. I am stuck with this strange problem. There are lot of people who had faced same problem (like here, here, here and lots of other places) in past but none of the solutions seems to work for me.
My problem is if I set layout file like setContentView(R.layout.MainActivity) application crashes on this function but if I directly set GLSurfaceView as content view application works just fine. I want to have a ListView and GLSurfaceView on same screen thats why I am trying to add it in XML.
Here is my layout file
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.example.camerafilters.CameraGLSurfaceView
android:id="#+id/CameraGLSurfaceView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
<!-- <ListView
android:id="#+id/ShaderList"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
-->
</LinearLayout>
Here is relevant portion from main activity. Note that CameraGLSurfaceView is an inner class.
public class CameraMainActivity extends Activity implements
SurfaceTexture.OnFrameAvailableListener
{
private CameraGLSurfaceView _cameraGLView;
/**
* Captures frames from an image stream as an OpenGL ES texture. The image stream may come from either camera preview or video decode.
* A SurfaceTexture may be used in place of a SurfaceHolder when specifying the output destination of a Camera or MediaPlayer object
*/
private SurfaceTexture _surface;
CameraGLRenderer _renderer;
private Camera _camera;
private ListView _shaderListView;
class CameraGLSurfaceView extends GLSurfaceView
{
CameraGLRenderer renderer;
public CameraGLSurfaceView(Context context, AttributeSet attrs)
{
super(context, attrs);
// Create an OpenGL ES 2.0 context
setEGLContextClientVersion(2);
// Set the Renderer for drawing on the GLSurfaceView
renderer = new CameraGLRenderer((CameraMainActivity)context);
setRenderer(renderer);
// Render the view only when there is a change in the drawing data
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
public CameraGLRenderer getRenderer()
{
return renderer;
}
}
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
_cameraGLView = new CameraGLSurfaceView(this, null);
// Create a GLSurfaceView instance and set it
// as the ContentView for this Activity.
setContentView(R.layout.activity_main);
_cameraGLView = (CameraGLSurfaceView) findViewById(R.id.CameraGLSurfaceView);
_renderer = _cameraGLView.getRenderer();
}
Any pointers where i am wrong ?

First, have a look at the exception stacktrace in logcat to find the exact problem.
Then, guessing the problem is that the view specified in your XML cannot be instantiated: your inner class needs to be public static and you need to refer to it correctly in XML, like
com.example.camerafilters.CameraMainActivity$CameraGLSurfaceView
though it's cleaner to have it as a separate class instead of an inner class.

Why u calling it before onCreate ? You don't need to call it since you defined it in your xml layout.
You dont need to call it all. Just delete the line before setContentView.

You should call GLSurfaceView.setRenderer() in your Activity.onCreate()

Related

Drawing a shape?

I have tried to draw a shape for a long time without an answer. I used setContentView(view) for that view. However, I have another setContentView:
setContentView(R.layout.activity_main);//Buttons, Views from XML...
setContentView( mCustomDrawableView);//Custom Shape
Problem is, it only shows ONE view, the shape. The Buttons defined on XML are gone. Basically whichever setContentView(view) is called last is the only View who is drawed. I've also tried many other ways to draw the shape without an answer that works.
I have seen that multiple setContentView do overlap each other, but this is the only way that partially works. Any way to display both Views or another way to draw a shape and my XML Views?
EDIT:
My shape is made in java, not XML
EDIT 2:
Here is my customShape Class:
public class CustomDrawableView extends View {
private ShapeDrawable mDrawable;
public CustomDrawableView(Context context) {
super(context);
int x = 10;
int y = 10;
mDrawable = new ShapeDrawable(new RectShape());
// If the color isn't set, the shape uses black as the default.
mDrawable.getPaint().setColor(0xff74AC23);
mDrawable.setBounds(x,y,x+10,y+10);
}
protected void onDraw(Canvas canvas) {
mDrawable.draw(canvas);
}
}
OK ... setContentView is something which takes a layout/view/whatever and the input defines the contents of the activity/fragment your are setting it to.
So of course your first call does the whole layout, and the second wipes that and sets the content to what you're sending to it.
The thing is to have your view and then add it to a layout. If you have any view in your initial setContentView xml named (+id) and defined (Layout x = getfromid(r.id.x) you can then add your view to that layout with x.addview(myview) or x.addview(CustomDrawableView(context)).
-edit for clarification-
An Activity/Fragment has a Layout which you set using setContentView. You do this once, normally. A Layout defines where Views are placed.
So, you setContentView(your.xml) in onCreate. If you have a programmatic View class, you can then do two things: add new YourView to a named and specified layout in your act/frag (using any layout defined in xml, passed to your frag/act in the xml passed in setContentView and then defined by Layout x = findViewById(R.id.idoflayoutinxmlinfield 'android:id="#+id/x") in code.
Then you can x.addview(new MyView(context)) or Myview z = new MyView(context) and x.addView(z);
-edit2-
When you get better, you can also just add your custom View to the original layout by adding it to the original xml definition.
-edit3-
Sigh. OK. Here it is:
In your activities java file:
RelativeLayout myRellayout;
#Override
public void onCreate(){
setContenView(your.xml)
myRelLayout = findViewByID(R.id.myrellayout);
myRelLayout.addView(new MyCustomView(this));
//or define your custom view and the add it by:
//MyCustomView mcv = new MyCustomView(this);
//myRelLayout.addView(mcv);
}
And your xml should contain any layout like this:
<RelativeLayout
android:id="#+id/myrellayout"
android:width="whatever"
android:height="whatever"
/>

What is the recommended way to launch a DialogFragment from a ViewModel?

I have a list objects in a Recyclerview. When long-pressing an item I want to show a dialog with data from the item clicked.
The Recyclerview is using data binding for each item and I am able to display data from the selected item using Log when long-pressing.
When trying to show a dialog, however, you need to get to the Activity, which is not recommended to use in the ViewModel object.
So how can I show the dialog?
Thanks, Ove
Conceptually a ViewModel strikes me as the wrong place to launch a Dialog from. To do it more cleanly I would pass the RecyclerView.ViewHolder into the layout, and have a method on the ViewHolder that triggers a custom listener on your RecyclerView.Adapter. Then whoever subscribes to that listener (Activity/Fragment) can launch the Dialog. May seem a little roundabout, but I don't think a ViewModel of a list item should have knowledge or control of its environment.
Here is an example. This is a general pattern for handling RecyclerView item clicks with data binding and a ViewModel. This is not a complete example, just the code to highlight this specific pattern.
Layout:
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
>
<data>
<variable
name="viewHolder"
type="com.example.ViewHolder"
/>
<variable
name="viewModel"
type="com.example.ViewModel"
/>
</data>
<com.example.View
android:layout_width="match_parent"
android:layout_height="24dp"
android:onClick="#{() -> viewHolder.onClick(viewModel)}"
/>
</layout>
Adapter:
class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
public interface SelectionListener {
void onSelectionChanged(int newPosition, ViewModel viewModel);
}
private #NonNull WeakReference<SelectionListener> selectionListener =
new WeakReference<>(null);
public void setSelectionListener(#Nullable SelectionListener listener) {
selectionListener = new WeakReference<>(listener);
}
public class ViewHolder extends RecyclerView.ViewHolder<ViewBinding> {
ViewHolder(ViewBinding binding) {
super(binding.getRoot());
binding.setViewHolder(this);
binding.setViewModel(new ViewModel());
}
public void onClick(ViewModel viewModel) {
SelectionListener listener = selectionListener.get();
if (listener != null) {
listener.onSelectionChanged(getAdapterPosition(), viewModel);
}
}
}
}
See the Variables section of the official documentation of the Data Binding Library. There you find a variable context you can use.
A special variable named context is generated for use in binding expressions as needed. The value for context is the Context from the root View's getContext(). The context variable will be overridden by an explicit variable declaration with that name.
Basically you could just pass it to another variable like the viewModel to show the dialog from there.
android:onClick="#{v -> viewModel.showDialog(context)}"
I think using a binding adapter for a recyclerview and put the adapter n ViewModel, then make the viewmodel is the model of fragment and passing adapter for the setAdapter method in xml itself.
So you can use the context of item for example itemView.getContext() to show AlertDialog
The hint from Bayoudh led me in the right direction, but I'm posting this to put the pieces together. Below is a cardview that is clickable. Since my ViewModel holds no reference to the activity we have to pass the view in question as a parameter.
<android.support.v7.widget.CardView
android:id="#+id/cardviewContact"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/text_margin_0.5x"
android:layout_marginRight="#dimen/text_margin_0.5x"
android:layout_marginTop="#dimen/text_margin_0.5x"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:minHeight="50dp"
card_view:cardCornerRadius="4dp"
android:onClick="#{(view) -> viewModel.onClick(view)}" >
The android:onClick="#{(view) -> viewModel.onClick(view)}" statement takes the current view as a parameter so you can use it in the ViewModel to get context with view.getContext() as Bayoudh states.

The java backend code to the xml code

I have a basic android application that has several pages accessible from the home page, anyways I change the layout by doing
public void main(View view) {
setContentView(R.layout.main);
}
and changing the layout to the main game page. Now I want to add characters to it and so I added protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint green = new Paint();
green.setColor(Color.GREEN);
Rect theRect = new Rect();
theRect.set(0,0,canvas.getWidth()/2,canvas.getHeight()/2);
canvas.drawRect(theRect, green);
}
but I only want to call it for the "main" or the scene/layout that the game is played in. It appears to not be called at all and that may be due to the fact that I do not completely understand the relationship between the xml and multiple java files and functions. I'm new to android so this may be a stupid question, I just couldn't find anything with multiple web searches, with no luck.
You can add your game view into activity class:
Class GameView extends View/SurfaceView
{
//-- contains onDraw() method
}
To add this game view into your activity, you have to do
get reference of layout in whioch you want to add this gameview.
eg: LinearLayout layout=(LinearLayout) findViewById(R.id.linearlayout);
Add GameView into this layout
eg: layout.addView(new GameView());
For more detail, you can get reference from http://www.edu4java.com/en/androidgame/androidgame3.html
Hope this helps you

Android overlaying GLSurfaceView with camera's SurfaceView

I'm looking to put an openGL model (via GLSurfaceView) on top of the camera, which has its own SurfaceView. Surely this must be possible, apps like Layar do this.
Here is what I am trying:
public class MainActivity extends Activity {
private CameraSurfaceView mCameraSurfaceView;
private GLSurfaceView mCubeGLSurfaceView;
private FrameLayout mFrameLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
mFrameLayout = new FrameLayout(this);
mCameraSurfaceView = new CameraSurfaceView(this);
mCubeGLSurfaceView = new GLSurfaceView(this);
mCubeGLSurfaceView.setRenderer(new CubeRenderer());
//mCubeGLSurfaceView.setZOrderMediaOverlay(true);
mFrameLayout.addView(mCameraSurfaceView);
mFrameLayout.addView(mCubeGLSurfaceView);
setContentView(mFrameLayout);
}
}
Right now: just the camera shows up. I've read online about the SetZOrderMediaOverlay attribute for GLSurfaceView; setting it TRUE in the above code has the 3D cube show up with a black background (i.e. no camera preview shown).
References:
Here is the Cube OpenGL code I'm using: http://intransitione.com/blog/create-a-spinning-cube-with-opengl-es-and-android/
Here is the CameraSurfaceView code:
https://github.com/davefp/android-camera-api-example/blob/master/src/com/example/cameraexample/CameraSurfaceView.java
Other tests I've tried: changing the addView order of the respective surfaceviews doesn't help; it only shows the camera (I read somewhere changing the addView order may help).
Thanks for any help!
Since you state that only the camera preview is currently visible it may be that you have not ordered your views correctly. This is what I have done to create what you desire.
In the Activity create
instance of MySurfaceView derived from GLSurfaceView
instance of MyCameraPreview derived from SurfaceView
in my Activity's onCreate method I do the following:
mySurfaceView = new MySurfaceView(this);
addContentView(mySurfaceView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
myCameraPreview = new MyCameraPreview(this, myCamera);
addContentView(myCameraPreview, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
Please note that using this method you do not use a layout xml.
This will create your two views on top of each other with the camera preview in the background.
Now you need to get the MySurfaceView to draw a transparent background so the camera preview will show behind the objects you render. If you are using OpenGL ES 2.0 add this to the constructor of your MySurfaceView class.
setEGLContextClientVersion(2);
setEGLConfigChooser(8,8,8,8,16,0);
getHolder().setFormat(PixelFormat.TRANSLUCENT);
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
I just worked through this process myself so I may have missed some details.

NotFoundException in layout editor for Android?

I'm trying to extend a RelativeLayout object and include an embedded SurfaceView object that uses a png file in my /res/drawable folder as its background but I keep getting an error in the XML Layout editor. See the following code:
public class StopMotionRelativeLayout extends RelativeLayout
{
private Context myContext;
private SurfaceView surfaceView1;
private BitmapFactory.Options myBitmapOptions;
private final android.view.ViewGroup.LayoutParams params =
new LayoutParams(LayoutParams.FILL_PARENT, android.view.ViewGroup.LayoutParams.FILL_PARENT);
public StopMotionRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
myContext = context;
this.setBackgroundColor(Color.GREEN);
//init images
surfaceView1 = new SurfaceView(myContext,attrs);
surfaceView1.setVisibility(View.INVISIBLE);
this.addView(surfaceView1, params);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
myBitmapOptions = new Options();
myBitmapOptions.outWidth = widthMeasureSpec;
myBitmapOptions.outHeight = heightMeasureSpec;
surfaceView1.setBackgroundDrawable(new BitmapDrawable(BitmapFactory.decodeResource(this.myContext.getResources(),
R.drawable.golf1, myBitmapOptions)));
}
}
I get the following error:
NotFoundException: Could not find
drawable resource matching value
0x7F020002 (resolved name: golf1) in
current configuration.
I have seen this type of error may times now and it always happens when I try to load something from a resource file via code and not XML. Curiously, this error does not stop me from compiling the app, and the app runs without error in the emulator. I'd like to get back the use of my layout editor though...
Please help.
UPDATE: Here is the layout XML
<?xml version="1.0" encoding="utf-8"?>
<com.games.test.StopMotionRelativeLayout android:id="#+id/RelativeLayout01"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
</com.games.test.StopMotionRelativeLayout>
I wonder if it would work if you specified a value for android:background in the XML and then override it in your code.
As a workaround, you could also try calling the isInEditMode() function and not set the background in edit mode.

Categories

Resources