Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Normy
Jul 1, 2004

Do I Krushchev?


Is anyone else doing that Coursera Android development course that was posted by someone awhile ago? I find it a little hard to follow. Like the lectures don't really explain what the assignments are asking you to do. This one here: https://class.coursera.org/android-001

Adbot
ADBOT LOVES YOU

Unperson_47
Oct 14, 2007



Normy posted:

Is anyone else doing that Coursera Android development course that was posted by someone awhile ago? I find it a little hard to follow. Like the lectures don't really explain what the assignments are asking you to do. This one here: https://class.coursera.org/android-001

I felt the same way about this course. There was another one that was easier to follow with "playful" in the name by a Lawrence Angrave. I'd get you the link but I'm on a phone and it's a hassle.

fritz
Jul 26, 2003

Glimm posted:

I'm not sure the Gradle build system functions with Eclipse at the moment. Maybe try Android Studio?

I can't even gradle it from the command line. I tried Android Studio and:
code:
3:06:56 PM Failed to refresh Gradle project 'BasicMultitouch'
           Unable to load class 'org.gradle.api.artifacts.result.ResolvedComponentResult'.
           This is an unexpected error. Please file a bug containing the idea.log file.
           File a bug Show log file
So there's something I don't have installed?

fritz
Jul 26, 2003

OK here's a question. I have a custom View that I instantiate in onResume:
code:
	@Override 
	protected void onResume(){
		super.onResume();
		TV = new TheView(this);
		setContentView(TV);
		//setContentView(new TheView(this));
	}
and that's working ok, I can put images up on a canvas and draw on it based on mouse events and everything. But now I want to add buttons. I'd like to have something like

pre:
|-------|
|       |
|       |
|       |
|       |
| x y z |
|-------|
where the whole thing (or some part) is a canvas and I can interact with it on button presses.

I don't even know where to get started with this.

I tried to add it to layout/activity_main.xml:

code:

<com.example.drawer.MainActivity.TheView 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />
    />
but I'm getting a java.lang.NoSuchMethodException from eclipse:
code:
com.example.drawer.MainActivity.TheView failed to instantiate.
It builds and does something anyway tho, but the TheView is taking up the whole display.

zeekner
Jul 14, 2007

fritz posted:

but I'm getting a java.lang.NoSuchMethodException from eclipse:
code:
com.example.drawer.MainActivity.TheView failed to instantiate.
It builds and does something anyway tho, but the TheView is taking up the whole display.

Is it just the preview pane throwing an exception? That's normal and can be ignored. There is a View.isInEditMode() method you can use in your custom view to work around the code that would crash in that preview.

You can use a RelativeLayout to have views overlap each other. Make sure to place the buttons below the custom view in the XML file, they will draw over anything above them. RelativeLayout offers the "android:layout_alignParentBottom" and related arguments to help you position everything the way you want.

IAmKale
Jun 7, 2007

やらないか

Fun Shoe
I need some help restoring DialogFragments after device rotation. While responding to a post I made on StackOverflow, I discovered that my DialogFragments are dismissed on rotation only in Activities when there no Fragments are defined in the Activity's layout.

Before I go into details, here's a(n awful) screen recording showing what I'm talking about :
https://www.youtube.com/watch?v=psK0pzMn6oc

Here's how I open DialogFragments regardless of the dialog or the activity I'm launching it from:
Java code:
DialogKanjiLookup dialog = DialogKanjiLookup.newInstance(gSearchView.getQuery());
dialog.show(getFragmentManager(), "dialogKanjiLookup");
The Activity visible at the beginning of the video has the following layout. The DialogFragment I opened failed to reappear when I rotated the device:
XML code:
<!-- main_activity_layout.xml -->
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <!-- Main Content View -->
        <FrameLayout
            android:id="@+id/content_frame"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_above="@+id/ad_container"/>

        <LinearLayout
            android:id="@id/ad_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentEnd="false"
            android:layout_alignParentBottom="true"
            android:orientation="vertical">
        </LinearLayout>

    </RelativeLayout>

    <ListView
        android:id="@+id/nav_drawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:choiceMode="singleChoice"
        android:divider="@color/gShoSilver"
        android:dividerHeight="1dp"
        android:background="@color/gShoGrey" />

</android.support.v4.widget.DrawerLayout>
When I need to load a Fragment into the above layout, I do so in the following manner:
Java code:
Fragment frag = getFragmentManager().findFragmentByTag("fragTag");
if(frag == null)
	frag = FragmentFoo.newInstance("bar");
fragmentManager.beginTransaction().replace(R.id.content_frame, frag, tag).commit();
This down here is the layout of the Vocabulary activity I navigate to. As you can see, two DialogFragments I launch from that Activity reappear after I rotate my phone:
XML code:
<!-- vocabulary_layout.xml -->
<RelativeLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	xmlns:tools="http://schemas.android.com/tools"
	android:id="@+id/container"
	android:orientation="horizontal"
	android:layout_width="match_parent"
	android:layout_height="match_parent"
	android:baselineAligned="false">

	<fragment
		class="com.gshoapp.FragmentTaggedWords"
		android:id="@+id/fragment_tagged_words"
		android:layout_width="fill_parent"
		android:layout_height="fill_parent"
		tools:layout="@layout/fragment_searchresults"
		android:layout_above="@+id/ad_container"/>

	<LinearLayout
		android:id="@id/ad_container"
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:layout_alignParentEnd="false"
		android:layout_alignParentBottom="true"
		android:orientation="vertical">
	</LinearLayout>

</RelativeLayout>
What the hell is going on? This problem has been plaguing me for a few days now and I'm not sure if I'm even barking up the right tree. I thought the FragmentManager was supposed to be smart about reloading existing fragments when the Activity is recreated, but for all I know right now maybe it is and I'm just an idiot who's doing things improperly. :sigh:

Can you guys help me figure out why my DialogFragments aren't remaining open through device rotation?

NoDamage
Dec 2, 2000
So onRetainNonConfigurationInstance() is deprecated, which I was using to store my AsyncTasks when my Activities are re-created during rotation. The suggested solution is to store it in Fragment with setRetainInstance(true), which seems a bit bizarre to me. Is this really the recommended method for saving AsyncTasks between configuration changes? Shove it in an interface-less Fragment?

Glimm
Jul 27, 2005

Time is only gonna pass you by

NoDamage posted:

So onRetainNonConfigurationInstance() is deprecated, which I was using to store my AsyncTasks when my Activities are re-created during rotation. The suggested solution is to store it in Fragment with setRetainInstance(true), which seems a bit bizarre to me. Is this really the recommended method for saving AsyncTasks between configuration changes? Shove it in an interface-less Fragment?

Bleh, personally I recommend using something decoupled from the Activity lifecycle like Android Priority Jobqueue, or maybe RxJava (good post on RxJava here: http://mttkay.github.io/blog/2013/08/25/functional-reactive-programming-on-android-with-rxjava/) and just posting when operations are done via Otto or some other EventBus.

You could do that with an AsyncTask as well, just make sure the reference isn't tied to a particular Activity.

Tunga
May 7, 2004

Grimey Drawer
The officially recommended way (which doesn't necessarily mean the best way, I've not really done anything with RxJava and the other stuff mentioned above so I can't really comment on those) is to use a headless Fragment.

Here's some general info on creating headless Fragments:
http://www.vogella.com/tutorials/AndroidFragments/article.html#headlessfragments

And here's some sample code which looked to be mostly sane at a quick glance:
http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html

IAmKale
Jun 7, 2007

やらないか

Fun Shoe
What are my options if I want to implement a two-column ListView? A single-column ListView will waste too much space on larger devices like a Nexus 7, so I'd like to switch to a two-column mode on them. Something like this:

Phones
code:
[     List	]
|	A	|
|	B	|
|	C	|
|	D	|
[_______E_______]
Tablets
code:
[	       List		]
|	  A	||	  B	|
|	  C	||	  D	|
|	  E	|		|
[_______________________________]
Would it be as simple as loading a tablet layout that has a GridView instead of a ListView?

Glimm
Jul 27, 2005

Time is only gonna pass you by

Karthe posted:

What are my options if I want to implement a two-column ListView? A single-column ListView will waste too much space on larger devices like a Nexus 7, so I'd like to switch to a two-column mode on them. Something like this:

Phones
code:
[     List	]
|	A	|
|	B	|
|	C	|
|	D	|
[_______E_______]
Tablets
code:
[	       List		]
|	  A	||	  B	|
|	  C	||	  D	|
|	  E	|		|
[_______________________________]
Would it be as simple as loading a tablet layout that has a GridView instead of a ListView?

Yeah using the GridView in the tablet layout is the way to go, you should even be able to reuse your adapter!

IAmKale
Jun 7, 2007

やらないか

Fun Shoe

Glimm posted:

Yeah using the GridView in the tablet layout is the way to go, you should even be able to reuse your adapter!
My god, that was easier than I could have imagined. After making the new layout the only thing I had to change in my code was to switch references of ListView to AbsListView instead. Thanks!

Glimm
Jul 27, 2005

Time is only gonna pass you by

Karthe posted:

My god, that was easier than I could have imagined. After making the new layout the only thing I had to change in my code was to switch references of ListView to AbsListView instead. Thanks!

Yeah, this is definitely a strength of the Android framework :)

Unperson_47
Oct 14, 2007



I'm new to the whole Android thing. Am I right in letting fragments act like separate, modular activities embedded in another or should they only be used as UI elements?

IAmKale
Jun 7, 2007

やらないか

Fun Shoe
Are Bugsense and Google Analytics two sides of the same coin? I'm already using Bugsense, but since I'm not particularly attached to it I'm tempted to switch to Analytics for the tighter integration with the Google Play Dashboard. They appear to have similar features, but is one is better than the other?

IAmKale fucked around with this message at 17:55 on Mar 15, 2014

Literally Elvis
Oct 21, 2013

So I'm trying to get the hang of Android development by making a simple random color generation app. I did this in C# with relatively little problems, but Android is completely wigging out on me, for one reason or another.

I have a simple class that uses Java.random to generate numbers between 0 and 255 for the RGB values:

code:
    final int MAX = 256;
    Random random = new Random();

    int red,
	green,
        blue;

    ColorGen()
    {
        int red = random.nextInt(MAX),
            green = random.nextInt(MAX),
            blue = random.nextInt(MAX);

        Log.d("ColorGen constructor", "R value: " + red);
        Log.d("ColorGen constructor", "G value: " + green);
        Log.d("ColorGen constructor", "B value: " + blue);
    }
and my MainActivity calls one function called newColor:

code:
        Log.d("MainActivity.newColor", "newColor called.");
        ImageView colorBox = (ImageView) findViewById(R.id.colorBox);
        ColorGen newColor = new ColorGen();
        int color = Color.rgb(newColor.red, newColor.green, newColor.blue);
        colorBox.setBackgroundColor(color);
        Log.d("MainActivity.newColor", "Color = " + color);
These are the sorts of log statements I'm getting, though:
code:
D/MainActivity.newColor&#65109; newColor called.
D/ColorGen constructor&#65109; R value: 102
D/ColorGen constructor&#65109; B value: 145
D/ColorGen constructor&#65109; G value: 171
D/MainActivity.newColor&#65109; Color = -16777216

D/MainActivity.newColor&#65109; newColor called.
D/ColorGen constructor&#65109; R value: 157
D/ColorGen constructor&#65109; B value: 164
D/ColorGen constructor&#65109; G value: 18
D/MainActivity.newColor&#65109; Color = -16777216
wut. I have no idea what is even happening here. The developer site for Color.rgb seems to indicate I'm doing everything by the book. The only thing I'm not 100% certain of is my use of an ImageView for the color box.

I've also never seen the use of these weird integer identifiers for colors before, where are these from?

edit: while I was writing this post, I thought maybe there was some sort of issue with newColor.red/green/blue being first declared in the arguments for Color.rgb so I did this:

code:
        Log.d("MainActivity.newColor", "newColor called.");
        int red = newColor.red,
            green = newColor.green,
            blue = newColor.blue;
        int color = Color.rgb(red, blue, green); //simply for debug statement below
        ImageView colorBox = (ImageView) findViewById(R.id.colorBox);
        colorBox.setBackgroundColor(Color.rgb(red, green, blue));
        Log.d("MainActivity.newColor", "Color = " + color);
Same problem, genuinely stumped.

Literally Elvis fucked around with this message at 07:23 on Mar 16, 2014

Tunga
May 7, 2004

Grimey Drawer
Looks like Color.toString() doesn't have defined behaviour so probably avoid just putting the object in the log output.

Other than that, you didn't really describe what problem you are actually having. What behaviour are you seeing?

Doctor w-rw-rw-
Jun 24, 2008

Tunga posted:

Looks like Color.toString() doesn't have defined behaviour so probably avoid just putting the object in the log output.

Other than that, you didn't really describe what problem you are actually having. What behaviour are you seeing?
What are you smoking? There's no object being printed here. The problem is clear - the color isn't being set.

Elvis:
-2^24 is 0xFF000000. In ARGB this means a totally opaque black. This means that red, green, and blue are consistently zero. Take a look at your constructor and you'll see you never actually set the instance variables.

I assume you're new to programming, if not in general, then at least to Java. You would do well (generally) to recognize certain powers of two, and (specifically) learn how to use Java's debugger. Those will go a long way in helping you solve your problems in the future. Luckily, Java is one of the easiest languages to use a debugger with IMO, its other shortcomings aside.

Doctor w-rw-rw- fucked around with this message at 08:55 on Mar 16, 2014

Tunga
May 7, 2004

Grimey Drawer

Doctor w-rw-rw- posted:

What are you smoking? There's no object being printed here. The problem is clear - the color isn't being set.
Holy poo poo, posting two minutes after I wake up is a terrible idea.

Literally Elvis
Oct 21, 2013

Doctor w-rw-rw- posted:

-2^24 is 0xFF000000. In ARGB this means a totally opaque black. This means that red, green, and blue are consistently zero. Take a look at your constructor and you'll see you never actually set the instance variables.

I assume you're new to programming, if not in general, then at least to Java. You would do well (generally) to recognize certain powers of two, and (specifically) learn how to use Java's debugger. Those will go a long way in helping you solve your problems in the future. Luckily, Java is one of the easiest languages to use a debugger with IMO, its other shortcomings aside.

I am new-ish to programming, and you were totally right. By using Java's debugger, do you mean jdb or things like breakpoints in Android Studio?

I'm unsure if my use of Log.d() is appropriate or not. I've been using it the way I've used it above because it's helpful to see the filtered output in logcat for diagnosing various problems (though this didn't help, and presumably breakpoints would have). Should I be using them more frequently/sparingly?

Doctor w-rw-rw-
Jun 24, 2008

Literally Elvis posted:

I am new-ish to programming, and you were totally right. By using Java's debugger, do you mean jdb or things like breakpoints in Android Studio?

I'm unsure if my use of Log.d() is appropriate or not. I've been using it the way I've used it above because it's helpful to see the filtered output in logcat for diagnosing various problems (though this didn't help, and presumably breakpoints would have). Should I be using them more frequently/sparingly?

I meant the IDE's debugger, such as the one in Android Studio, yes. GUIs shouldn't be taboo if they help you use powerful tools better (but if you are uncommon and text is your thing, and you're more productive that way, all power to you). As for whether your use of Log.d(), sure - use whatever tool you can to track down problems. If logging is confusing you on a bug, then try a different approach. Debugging is hard to get good at, but the first step is recognizing where it can help, and you've already spotted a good example.

Another thing that might help is using a good color scheme that is not only easy on your eyes (i.e. a dark gray or black background instead of white), but which has good contrast in its colors, so you can figure out that you're setting a local variable instead of an instance variable by inspection by looking at the color of the variable.

Really, any additional signal you can add to finding problems that doesn't increase the noise by too much is probably worth considering. For example, religiously autoformatting your source code so that code lines up consistently might help, too, or naming variables consistently (i.e. always declare a FooBarController as FooBarController fooBarController unless you have reason not to) helps you spend your brain worrying about problems that actually matter.

Jarl
Nov 8, 2007

So what if I'm not for the ever offended?
It seems to me that string resources can only consist of the first 127 characters that all encodings share, even though though the first line in the xml file specifies the encoding to be UTF-8 and the editing actually has been done with an editor in UTF-8 mode.
I know you can do things like \u0086, but that is not good enough.

Is there a way for a spanish guy to edit my text resource file's content without having to look up the code point for for every character not among the 127?

fritz
Jul 26, 2003

Uncomfortable Gaze posted:

You can use a RelativeLayout to have views overlap each other. Make sure to place the buttons below the custom view in the XML file, they will draw over anything above them. RelativeLayout offers the "android:layout_alignParentBottom" and related arguments to help you position everything the way you want.

That's what I thought I was doing, but no luck:
code:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

<com.example.drawer.MainActivity.TrailView
    android:layout_width="match_parent"
    android:layout_height="300dp"
    android:layout_above="@+id/button1"
    android:layout_alignParentRight="true" />
   
    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:text="Button1" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/button1"
        android:layout_alignBottom="@+id/button1"
        android:layout_toRightOf="@+id/button1"
        android:text="Button2" />

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/button2"
        android:layout_alignBottom="@+id/button2"
        android:layout_toRightOf="@+id/button2"
        android:text="Button3" />

</RelativeLayout>
I thought maybe it was because I wasn't actually creating the buttons in the MainActivity, but when I try to do it like this:

code:

public class MainActivity extends Activity {
	String drawntext = new String("HELLO");
	TrailView TV;
	Button button1;
	Button button2;
	Button button3;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
	}
	@Override 
	protected void onResume(){
		super.onResume();
		TV = new TrailView(this);
		setContentView(TV);
		

		button1 = (Button) findViewById(R.id.button1);
		button1.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				Log.w("CLICK","BUTTON 1 CLICKED");
			}
		});
 
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}
	public class TrailView extends View implements OnTouchListener {
         // View code goes here, it seems to work ok
       } 
}
I get runtime null pointer exceptions at the line: "button1.setOnClickListener()...".

ETA: ok, "button1" is null somehow. R.id.button1 is certainly in the activity_main.xml, but it's not getting found. I also tried moving it to onCreate, no luck.

The big picture that I'm going for is:
* I want an area of the screen that I can put images on, capture touch events, and draw things on
* I want an area that I can put text in and control the displayed text
* I want a set of buttons to manipulate the text and the area on which I did the drawing.

I am so far outside my core competency here. This is stuff that should be simple and either I'm complicating it up or I'm just missing basic things.

fritz fucked around with this message at 20:26 on Mar 24, 2014

zeekner
Jul 14, 2007

fritz posted:

That's what I thought I was doing, but no luck:

You are on the right track, but the major problem is here:
code:
		TV = new TrailView(this);
		setContentView(TV);
You should be calling setContentView(R.layout.whatever_activity_layout) and that should be happening in onCreate(). The contents of that XML file are only used when you specify that layout in the setContentView call.

e: Also, anything configuring views (like setting the button onClickListener) should happen shortly after the setContentView call in onCreate, not in onResume. Anything in onResume will happen every time the screen turns off, the user hits the home button and returns, or you launch another activity and return.

The activity lifecycle is really critical, make sure you read through this page: http://developer.android.com/reference/android/app/Activity.html
e: Actually this one is better: http://developer.android.com/guide/components/activities.html

To clarify, you will need something like this in onCreate:

code:
setContentView(R.layout.activity_main);
TV = (TrailView) findViewById(R.id.trailview);  //set android:id="@+id/trailview" for the TrailView in your XML
myButtonOne = (Button) findViewById(R.id.button1);
myButtonOne.setOnClickListener(ect ect)

zeekner fucked around with this message at 20:34 on Mar 24, 2014

fritz
Jul 26, 2003

Uncomfortable Gaze posted:

You are on the right track, but the major problem is here:
code:
		TV = new TrailView(this);
		setContentView(TV);
You should be calling setContentView(R.layout.whatever_activity_layout) and that should be happening in onCreate(). The contents of that XML file are only used when you specify that layout in the setContentView call.

e: Also, anything configuring views (like setting the button onClickListener) should happen shortly after the setContentView call in onCreate, not in onResume. Anything in onResume will happen every time the screen turns off, the user hits the home button and returns, or you launch another activity and return.

The activity lifecycle is really critical, make sure you read through this page: http://developer.android.com/reference/android/app/Activity.html

To clarify, you will need something like this in onCreate:

code:
setContentView(R.layout.activity_main);
TV = (TrailView) findViewById(R.id.trailview);  //set android:id="@+id/trailview" for the TrailView in your XML
myButtonOne = (Button) findViewById(R.id.button1);
myButtonOne.setOnClickListener(ect ect)
Oh, excellent, thanks.

I'm getting errors on the setContentView tho:
code:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.drawer/com.example.drawer.MainActivity}: android.view.InflateException: Binary XML file line #11: Error inflating class com.enimai.drawer.MainActivity.TrailView
...
Caused by: java.lang.ClassNotFoundException: Didn't find class "com.example.drawer.MainActivity.TrailView" on path: DexPathList[[zip file "/data/app/com.example.drawer-1.apk"],nativeLibraryDirectories=[/data/app-lib/com.example.drawer-1, /system/lib]]

but when I look at bin/classes.dex.d in the build directory I can see it there:
code:
...
(fullpath)/bin/classes/com/example/drawer/MainActivity$TrailView.class \
...
This is my onCreate now:
code:

	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.activity_main);
		TV = (TrailView)findViewById(R.id.trailview);
		
		button1 = (Button) findViewById(R.id.button1);
		if (button1==null){
			Log.e("NULL","BUTTON 1 IS NULL");
		}
		button1.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				Log.w("CLICK","BUTTON 1 CLICKED");
			}
		});
	}
	@Override 
	protected void onResume(){
		super.onResume();

 
	}

zeekner
Jul 14, 2007

Oh, right, having the TrailView inside the activity class complicates things. It's usually better to split them into separate classes.

To reference it like you have now you'll need to use the generic view item in the layout xml:
code:
<view class="com.example.drawer.MainActivity$TrailView"
	android:layout_width="match_parent"
	ect ect />
e: The dollar sign indicates that the class is an inner class.

zeekner fucked around with this message at 21:03 on Mar 24, 2014

fritz
Jul 26, 2003

Uncomfortable Gaze posted:

Oh, right, having the TrailView inside the activity class complicates things. It's usually better to split them into separate classes.

To reference it like you have now you'll need to use the generic view item in the layout xml:
code:
<view class="com.example.drawer.MainActivity$TrailView"
	android:layout_width="match_parent"
	ect ect />
e: The dollar sign indicates that the class is an inner class.

Oh, cool, that worked (plus I had to change the constructor in the View to take an AttributeSet and make some fields static).

Thanks!

:toot:

ETA: also the reason I nested the classes is because I wanted the inner class to see state belonging to the parent class, I suppose I should have implemented getter/setter methods in TrailView instead and call those?

zeekner
Jul 14, 2007

fritz posted:

Oh, cool, that worked (plus I had to change the constructor in the View to take an AttributeSet and make some fields static).

Thanks!

:toot:

ETA: also the reason I nested the classes is because I wanted the inner class to see state belonging to the parent class, I suppose I should have implemented getter/setter methods in TrailView instead and call those?

Yea, the normal way to handle this is to split the view class into a separate file and interface with it like any other class. Once you get the hang of it you'll figure out the proper separation of concerns and an easy way to communicate between view and activity. It's probably little daunting to jump straight into a custom view as part of your first app.

fritz
Jul 26, 2003

Uncomfortable Gaze posted:

Yea, the normal way to handle this is to split the view class into a separate file and interface with it like any other class. Once you get the hang of it you'll figure out the proper separation of concerns and an easy way to communicate between view and activity. It's probably little daunting to jump straight into a custom view as part of your first app.

I'm a backend/signals/data guy, this is technically my second app, the first had a bunch of bluetooth/wifi/sensor API calls that sort of works. :shobon:

Let me go try pulling out the view class and I'll be back with questions.

fritz
Jul 26, 2003

fritz posted:

Let me go try pulling out the view class and I'll be back with questions.

OK, so I made a TrailView.java and put all the TrailView code in there, then updated activity_main.xml:

<view class="com.example.drawer.TrailView"
android:id="@+id/trailview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/button1"
android:layout_alignParentRight="true" />
and it works.

But (and this was happening before) in onCreate I do:
code:
TV = (TrailView)findViewById(R.id.trailview);
and TV is null.

zeekner
Jul 14, 2007

fritz posted:

OK, so I made a TrailView.java and put all the TrailView code in there, then updated activity_main.xml:

<view class="com.example.drawer.TrailView"
android:id="@+id/trailview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/button1"
android:layout_alignParentRight="true" />
and it works.

But (and this was happening before) in onCreate I do:
code:
TV = (TrailView)findViewById(R.id.trailview);
and TV is null.

With the class separated you can use the normal class syntax:
code:
<com.example.drawer.TrailView
    android:id="@+id/trailview" 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    .../>
The findViewById call must happen after setContentView, the views are not created until the setContentView call.
The TrailView class is extending View, right?

fritz
Jul 26, 2003

Uncomfortable Gaze posted:

With the class separated you can use the normal class syntax:
code:
<com.example.drawer.TrailView
    android:id="@+id/trailview" 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    .../>
The findViewById call must happen after setContentView, the views are not created until the setContentView call.
The TrailView class is extending View, right?
OK, I put it back to the normal syntax:
code:
<com.example.drawer.TrailView
    android:id="@+id/trailview" 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_above="@+id/button1"
    class="com.example.drawer.TrailView" />
but I'm still getting the null. And it does extend View:
code:
public class TrailView extends View implements OnTouchListener
I'm making the call immediately after setContentView:
code:
		setContentView(R.layout.activity_main);
		TV = (TrailView)findViewById(R.id.trailview);
and fwiw this is my onClick code:
code:
		button3 = (Button) findViewById(R.id.button3);
		button3.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				Log.w("CLICK","BUTTON 3 CLICKED");
				TV.setClicks(1);
                                TV.invalidate();

			}
		});
(which obv. raises the exception because TV is null, but I'm hopeful...)
(I checked and findViewById(R.id.trailview) is still null even inside button3's onClick).

zeekner
Jul 14, 2007


Odd, you should be working at this point, especially if you can get buttons that exist on the same layout. Only thing slightly unusual is that you don't need class="com.example.drawer.TrailView" anymore, that's handled by the tag itself. If you can't get it to work can you post a gist with the current activity code in full?

fritz
Jul 26, 2003

Uncomfortable Gaze posted:

Odd, you should be working at this point, especially if you can get buttons that exist on the same layout. Only thing slightly unusual is that you don't need class="com.example.drawer.TrailView" anymore, that's handled by the tag itself. If you can't get it to work can you post a gist with the current activity code in full?
ETA: fixed (something), I was calling the super() incorrectly in TrailView!

So I originally had the TrailView constructor looking like this:
code:
public TrailView(Context context) {
super(context);
	// ... 
}
but in the modifications I ended up changing it to:
code:
public TrailView(Context context, android.util.AttributeSet attrs) {
	super(context);	
	// ...
}
where I should have had:
code:
public TrailView(Context context, android.util.AttributeSet attrs) {
	super(context,attrs);
	// ...
}
Also thanks! Uncomfortable Gaze for all the help!

fritz fucked around with this message at 23:07 on Mar 24, 2014

zeekner
Jul 14, 2007

Just a heads up, google released a bad update to the gradle build tools (0.9.2). It will automatically cause your builds to fail if you use:
code:
classpath 'com.android.tools.build:gradle:0.9.+'
So use 0.9.1 for now I guess.

this isn't even the first time this has happened in the last few months ffs

e: Everyone should use specific point versions for this exact reason, but newly generated projects use that classpath line so this will hit a lot of people.

e2: If you get this error: "Unable to load class 'com.android.builder.testing.api.DeviceProvider'." this is the cause.

zeekner fucked around with this message at 20:27 on Mar 26, 2014

zeekner
Jul 14, 2007

Update to the 0.9.2 issue:
Turns out the issue was caused by the gradle build tools being released before some of the dependency files were uploaded. 0.9.2 should work now, but if you continue to run into that error you need to clear the gradle cache. Either delete the '~/.gradle/caches' folder or run 'gradle --cache rebuild' if you have a local install of gradle.

Jo
Jan 24, 2005

:allears:
Soiled Meat
Some beginner conceptual questions here. I'm not grokking the logical flow of the average Android app. I can use Buttons in Views to signal Intents which trigger changes to new Activities which have different Views, yes? Or have I completely lost it? Fragments, then, are when you have n ways of looking at the same data and don't want to pass it between activities?

zeekner
Jul 14, 2007

Jo posted:

Some beginner conceptual questions here. I'm not grokking the logical flow of the average Android app. I can use Buttons in Views to signal Intents which trigger changes to new Activities which have different Views, yes? Or have I completely lost it? Fragments, then, are when you have n ways of looking at the same data and don't want to pass it between activities?

That's a bit off. This is a bit complicated so I apologize in advance if I make things worse.

Views are simply UI elements, combined together inside ViewGroups to form the interface. Buttons are just a type of view, one specifically designed around its onClick function. Most views can actually be used like a button, the base View class that every UI element extends from has onClick callbacks. Most of the UI elements you need already exist (TextView/ImageView/EditText/ect). Treat them like lego blocks, plug them in wherever you need them then control them from the parent Activity or Fragment.

Activities encapsulate those views and handle lifecycle and most interaction logic. An activity should contain the UI logic for a "page" (for lack of a better term). For example, you could have a single activity to handle a login process, and another activity to show a list of content items, and another one to display the actual content itself. The lifecycle is the change between states in the activity when launching or exiting. This hopefully explains the whole cycle better than I ever could.

Intents are essentially messages used to start new activities, send broadcasts, and do more advanced stuff. The most basic use is to start a new activity, for example: when the user completes the login, you would call startActivity() with an intent that pointed to your next activity, like the content list. You can include extra data in that intent, and it's typical to include enough information that the target activity knows exactly what it needs to do. The intent used to start an activity is always accessible by calling getIntent(), and the intent has get_Extra() methods to grab that extra data.

Fragments are essentially sub-activities, they replicate most of the functionality of an Activity but must be placed within an Activity. They were introduced to allow for multi-pane layouts on tablets and are great for code re-use. You can design a content-list fragment and a content-view fragment, then on a tablet you can place both side-by-side in the same activity. Otherwise on a phone you can show just the content-list fragment, then when someone selects an item it starts a new activity that only has the content-view fragment. Most of the activity logic can be moved into the fragment, and that fragment can be inserted into any activity. If your just starting out, it might be a good idea to start with a normal Activity. You'll need to learn fragments at some point though, most modern apps depend on them.

It's probably a good idea to just start here and keep reading. Maybe get a book as well. (I have no idea what book to recommend)

e: wrong link

zeekner fucked around with this message at 06:43 on Mar 29, 2014

IAmKale
Jun 7, 2007

やらないか

Fun Shoe

Jo posted:

Some beginner conceptual questions here. I'm not grokking the logical flow of the average Android app. I can use Buttons in Views to signal Intents which trigger changes to new Activities which have different Views, yes? Or have I completely lost it? Fragments, then, are when you have n ways of looking at the same data and don't want to pass it between activities?
Activities host Fragments. That is, Activities should be containers in which Fragments sit and do their thing. For the most part, a Fragment class will contain most of a screen's logic and will handle the heavy lifting of preparing the screen for viewing. The Activity handles stuff like setting up the ActionBar and loading a Fragment into itself. The main benefit of splitting things up like this is that Fragments can be easily dropped into another Activity that uses a different layout. This would come in handy if you were developing an app that has a different layout on tablets - an Activity can be set up to use a different layout depending on the screen size, so you can reuse Fragments and code instead of writing multiple classes for all different kinds of devices.

Views are just the base class of the structural classes like ListView and LinearLayout. They define the structure of the content.

You can set onClickListeners on Buttons. In that listener, you can do something like define an Intent that will pass along some information to a new Activity or Fragment. The information can be accessed in either's onCreate() to initialize whatever you want. Whatever activity you launch can have completely different logic or appearance from the Activity or Fragment launching the activity.

Here are some tutorials that might help you wrap your head around the Android way of doing things:
http://developer.android.com/training/basics/activity-lifecycle/index.html
http://developer.android.com/training/basics/fragments/index.html
This is a great place to start, it starts with the basics and moves into more advanced topics: http://developer.android.com/training/index.html

e:fb

Adbot
ADBOT LOVES YOU

zeekner
Jul 14, 2007

Haha, I spent forever writing that and we managed to post within minutes of each other.

For some additional help, google has a ton of sample programs where each cover a specific topic. http://developer.android.com/samples/index.html

You can also generate certain pre-defined patterns when you create a new project. For example it can generate a simple list-content dual-fragment project that you can look through.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply