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
Volmarias
Dec 31, 2002

EMAIL... THE INTERNET... SEARCH ENGINES...

Tusen Takk posted:

SQLiteDatabase.OPEN_READONLY

First step may be to change that.

Adbot
ADBOT LOVES YOU

FAT32 SHAMER
Aug 16, 2012



Volmarias posted:

First step may be to change that.

Yeah, I began to realize that using a HashMap as the insert argument is really dumb. I have it working now and I think that it's working, I just have to write a test class to go back and view the entries to make sure it's actually creating a db locally since i'm using the VM.

FAT32 SHAMER
Aug 16, 2012



I'm back and with more questions! So I have successfully set up a database that lets me insert poo poo with no issues and everything is amazing. Now, I'd like to be able to display this information to the user, but I'm not sure how exactly to do it. This is what I've been using:

SQLiteOpenHelper class
Java code:
package blueharmony.database;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;


/**
 * Created by thefalloftim on 3/19/16.
 */
public class BHDbHelper extends SQLiteOpenHelper {
    public static final String DATABASE_NAME = "blueharmony.db";

    public static final String JOURNAL_TABLE = "tbl_journal";
    public static final String FEELINGS_TABLE = "tbl_feeling";


    public BHDbHelper(Context context) {
        super(context, DATABASE_NAME, null, 1);
    }


    public boolean insertJournalEntry(String journalEntry, String feelingID) {
        SQLiteDatabase myDB = this.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put("entry", journalEntry);
        values.put("feeling_id", feelingID);
        long result = myDB.insert("tbl_journal", null, values);

        if(result == -1){
            return false;
        }
        else{
            return true;
        }
    }

    public void insertFeeling(String feelingID) {
        SQLiteDatabase myDB = this.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put("feeling_id", feelingID);
        myDB.insert("tbl_feeling", null, values);
        myDB.close();
    }

    public boolean insertMedReminder(String medName, String medTime){
        SQLiteDatabase myDB = this.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put("med_name", medName);
        values.put("med_time", medTime);

        long result = myDB.insert("tbl_medreminders", null, values);

        if(result == -1){
            return false;
        }
        else{
            return true;
        }
    }

    public Cursor getJournalEntries(){
        SQLiteDatabase myDB = this.getWritableDatabase();
        Cursor res = myDB.rawQuery("SELECT 'feeling_id', 'entry' FROM TABLE 'tbl_journal';", null);

        if(res.getCount() == 0){
            return null;
        }
        else{
            return res;
        }
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE 'tbl_feeling' ( '_id' INTEGER PRIMARY KEY AUTOINCREMENT, 'feeling_id' TEXT );");
        db.execSQL("CREATE TABLE 'tbl_journal' ( '_id' INTEGER PRIMARY KEY AUTOINCREMENT, 'feeling_id' INTEGER, 'entry' TEXT );");
        db.execSQL("CREATE TABLE 'tbl_medreminders' ( '_id' INTEGER PRIMARY KEY AUTOINCREMENT, 'med_name' TEXT, 'med_time' DATETIME );");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS 'android_metadata'");
        db.execSQL("DROP TABLE IF EXISTS '" + JOURNAL_TABLE + "'");
        db.execSQL("DROP TABLE IF EXISTS '" + FEELINGS_TABLE + "'");
        db.execSQL("DROP TABLE IF EXISTS 'tbl_medreminders'");

        oldVersion = 0;
        newVersion = oldVersion + 1;

        onCreate(db);
    }

}

Previous Journal Entries dot class
Java code:
package blueharmony;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import blueharmony.database.BHDbHelper;

public class PrevJourActivity extends AppCompatActivity {

    private Button mBackButton;
    BHDbHelper myDB = new BHDbHelper(this);
    TextView mDisplayFeelingsView;
    TextView mDisplayJournalView;

    public void viewJournalEntries(){

        int column1 = myDB.getJournalEntries().getColumnIndex("feeling_id");
        int column2 = myDB.getJournalEntries().getColumnIndex("entry");
        myDB.getJournalEntries().moveToFirst();

        mDisplayJournalView = (TextView) findViewById(R.id.entry_display);
        mDisplayFeelingsView = (TextView) findViewById(R.id.feeling_display);
        String feelings = null;
        String entries = null;

        if(myDB.getJournalEntries() != null){
            do{
                String feeling = myDB.getJournalEntries().getString(column1);
                String entry = myDB.getJournalEntries().getString(column2);

                feelings = feelings + feeling + "\n";
                entries = entries + entry + "\n";

                System.out.println(feelings + entries);

            }while(myDB.getJournalEntries().moveToNext());
            mDisplayFeelingsView.setText(feelings);
            mDisplayJournalView.setText(entries);

        }



    }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_prevjour);

        //viewJournalEntries();

        mBackButton = (Button) this.findViewById(R.id.button_pjback);
        mBackButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                PrevJourActivity.this.startActivity(new Intent(PrevJourActivity.this,
                        JournalActivity.class));
            }
        });



        //
    }

}

Activity.xml
XML code:
<?xml version="1.0" encoding="utf-8"?>
<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:background="@color/backgroundBlue"
    tools:context=".PrevJourActivity">

    <ScrollView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:scrollbars="vertical"
        android:fillViewport="true"
        android:layout_above="@+id/button_pjback">


        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="test"
            android:id="@+id/feeling_display"/>
        
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/entry_display"/>
    </ScrollView>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/button_pjback"
        android:text="Back"
        android:background="@drawable/button_background"
        android:textColor="@android:color/black"
        android:textStyle="bold"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="46dp"/>


</RelativeLayout>

Now, for some reason, the way I have my layout file causes the java file to throw an error on Line 54 (setContentView(R.layout.activity_prevjour);). I'm assuming it's because it doesn't like the grid view in the scrollview in the relative layout, but I have no idea.

I also assume that the rest of the reason for the crash is because it doesn't want to write the data to the TextView, and if that's the case, how the heck to I display it to the user? Or is it because I'm returning Null in the getJournalEntries() method?

Thanks for any help or input :)

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

What does the stack trace in your log say? It should tell you exactly where it's crashing and why (the type of exception and the error message it carries), and then further down it will probably give you the exception that caused that, and maybe there's another one that caused that...

Point is you don't really need to guess about it, there's a trail a clues right there which will at least point you in the right direction, show you which method crashed etc. You might need to google the error message to learn more but at least you'll be on the trail!

This isn't a 'fix it yourself!' post, I'm just encouraging you to look at the logs because they're really useful (and it'll make it easier for people to help you when you've narrowed the problem down)

Crash stack traces are logged at the Error level so you can filter logcat to display those and you'll find your app's crash really easily


e- just offhand I can't see anything wrong with the XML (so the stack trace would really help to see why it's choking on setContentView), but your getJournalEntries method can return null, right? You do a null check but earlier in the method you call it again and immediately call a method on the result, so you need to handle it there too. It's probably a good idea to make sure the views you're findingById aren't null too.

If you're using an IDE then the linter should be highlighting these and giving you a tooltip that says heyyyy this might be null - if you're in Android Studio then try putting the cursor on a highlighted bit and hitting Alt+Return, instant fixes!

baka kaba fucked around with this message at 04:18 on Apr 10, 2016

FAT32 SHAMER
Aug 16, 2012



baka kaba posted:

What does the stack trace in your log say? It should tell you exactly where it's crashing and why (the type of exception and the error message it carries), and then further down it will probably give you the exception that caused that, and maybe there's another one that caused that...

Point is you don't really need to guess about it, there's a trail a clues right there which will at least point you in the right direction, show you which method crashed etc. You might need to google the error message to learn more but at least you'll be on the trail!

This isn't a 'fix it yourself!' post, I'm just encouraging you to look at the logs because they're really useful (and it'll make it easier for people to help you when you've narrowed the problem down)

Crash stack traces are logged at the Error level so you can filter logcat to display those and you'll find your app's crash really easily

Oh wow so that's what all of that is :shobon:. Here's what it output for me:

code:
04-04 15:49:44.678 29377-29377/? E/AndroidRuntime: FATAL EXCEPTION: main
                                                   Process: timclyne.blueharmony, PID: 29377
                                                   java.lang.RuntimeException: Unable to start activity ComponentInfo{timclyne.blueharmony/blueharmony.PrevJourActivity}: java.lang.IllegalStateException: ScrollView can host only one direct child
                                                       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2325)
                                                       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
                                                       at android.app.ActivityThread.access$800(ActivityThread.java:151)
                                                       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
                                                       at android.os.Handler.dispatchMessage(Handler.java:102)
                                                       at android.os.Looper.loop(Looper.java:135)
                                                       at android.app.ActivityThread.main(ActivityThread.java:5254)
                                                       at java.lang.reflect.Method.invoke(Native Method)
                                                       at java.lang.reflect.Method.invoke(Method.java:372)
                                                       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
                                                       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
                                                    Caused by: java.lang.IllegalStateException: ScrollView can host only one direct child
                                                       at android.widget.ScrollView.addView(ScrollView.java:266)
                                                       at android.view.LayoutInflater.rInflate(LayoutInflater.java:810)
                                                       at android.view.LayoutInflater.rInflate(LayoutInflater.java:809)
                                                       at android.view.LayoutInflater.inflate(LayoutInflater.java:504)
                                                       at android.view.LayoutInflater.inflate(LayoutInflater.java:414)
                                                       at android.view.LayoutInflater.inflate(LayoutInflater.java:365)
                                                       at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:256)
                                                       at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:109)
                                                       at timclyne.blueharmony.PrevJourActivity.onCreate(PrevJourActivity.java:54) //<-------------------------------------
                                                       at android.app.Activity.performCreate(Activity.java:5990)
                                                       at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
                                                       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278)
                                                       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387) 
                                                       at android.app.ActivityThread.access$800(ActivityThread.java:151) 
                                                       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303) 
                                                       at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                       at android.os.Looper.loop(Looper.java:135) 
                                                       at android.app.ActivityThread.main(ActivityThread.java:5254) 
                                                       at java.lang.reflect.Method.invoke(Native Method) 
                                                       at java.lang.reflect.Method.invoke(Method.java:372) 
                                                       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) 
                                                       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698) 
So it says that it's crashing from Line 54 of PrevJourActivity.java, which is the line setContentView(R.layout.activity_prevjour);. Is it because "Caused by: java.lang.IllegalStateException: ScrollView can host only one direct child"?

Welp that makes life easy, the crashes were from having two textviews in one scroll view :newlol:

edit: I guess I have some SQLite syntax errors floating around and a few other easy fixes, so I guess that just leaves the question of what's the best way to getting the contents of your database into a textview or similar so the user can see it :D

FAT32 SHAMER fucked around with this message at 04:37 on Apr 10, 2016

kitten smoothie
Dec 29, 2001

If you're goofing with sqlite you will probably find this to be really handy as you develop:

http://facebook.github.io/stetho/


edit: that said, "as you develop" is the operative phrase. Watch out not to accidentally have Stetho enabled in the production version you put up on the store. Maybe see some advice here for keeping it contained

http://stackoverflow.com/questions/30172308/include-stetho-only-in-the-debug-build-variant

kitten smoothie fucked around with this message at 05:02 on Apr 10, 2016

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

Tusen Takk posted:

So it says that it's crashing from Line 54 of PrevJourActivity.java, which is the line setContentView(R.layout.activity_prevjour);. Is it because "Caused by: java.lang.IllegalStateException: ScrollView can host only one direct child"?

Welp that makes life easy, the crashes were from having two textviews in one scroll view :newlol:

Yep! You should look at the docs for ScrollView, but it's basically meant as a wrapper around another view, so that if that view gets too big to fit on the screen (or the space you've allowed for it), the ScrollView will let you swipe it around. So if you want to have two TextViews, stick them in a Layout of some kind, and wrap the Layout in the ScrollView

('View' is basically the base UI component class if the name sounds confusing, it took me a while to get my head around it. So Layouts are Views too, you build your UI with them)

As far as getting your stuff on-screen goes, it really depends how you want to display it and there are a lot of approaches you can take - some are a lot easier than others. Have a look at this, it's probably closest to what you have already:
https://github.com/codepath/android_guides/wiki/Populating-a-ListView-with-a-CursorAdapter

baka kaba fucked around with this message at 08:14 on Apr 10, 2016

FAT32 SHAMER
Aug 16, 2012



baka kaba posted:

Yep! You should look at the docs for ScrollView, but it's basically meant as a wrapper around another view, so that if that view gets too big to fit on the screen (or the space you've allowed for it), the ScrollView will let you swipe it around. So if you want to have two TextViews, stick them in a Layout of some kind, and wrap the Layout in the ScrollView

('View' is basically the base UI component class if the name sounds confusing, it took me a while to get my head around it. So Layouts are Views too, you build your UI with them)

As far as getting your stuff on-screen goes, it really depends how you want to display it and there are a lot of approaches you can take - some are a lot easier than others. Have a look at this, it's probably closest to what you have already:
https://github.com/codepath/android_guides/wiki/Populating-a-ListView-with-a-CursorAdapter

This is brilliant! Thanks so much for showing me this :3: I edited their code for it to work with mine, but for some reason for every entry it also puts the button under it, like this:



edited code!

Adapter:
Java code:
public class PrevJourCursorAdapter extends CursorAdapter {
    public PrevJourCursorAdapter(Context context, Cursor cursor, int flags) {
        super(context, cursor, 0);
    }

    // The newView method is used to inflate a new view and return it,
    // you don't bind any data to the view at this point.
    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        return LayoutInflater.from(context).inflate(R.layout.activity_prevjour, parent, false);
    }

    // The bindView method is used to bind all data to a given view
    // such as setting the text on a TextView.
    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        // Find fields to populate in inflated template
        TextView tvBody = (TextView) view.findViewById(R.id.feeling_display);
        TextView tvPriority = (TextView) view.findViewById(R.id.entry_display);
        // Extract properties from cursor
        String feeling = cursor.getString(cursor.getColumnIndexOrThrow("feeling_id"));
        String entry = cursor.getString(cursor.getColumnIndexOrThrow("entry"));
        // Populate fields with extracted properties
        tvBody.setText(feeling);
        tvPriority.setText(String.valueOf(entry));
    }
}
viewStuff method!
Java code:
    public void viewJournalEntries(){

        //mDisplayFeelingsView = (TextView) findViewById(R.id.feeling_display);
        //mDisplayJournalView = (TextView) findViewById(R.id.entry_display);

        BHDbHelper helper = new BHDbHelper(this);
        SQLiteDatabase db = helper.getWritableDatabase();
        Cursor cursor = db.rawQuery("SELECT * from 'tbl_journal';", null);

        ListView lvDisplayStuff = (ListView) findViewById(R.id.list_stuff);
        PrevJourCursorAdapter prevJourCursorAdapter = new PrevJourCursorAdapter(this, cursor, 0);

        lvDisplayStuff.setAdapter(prevJourCursorAdapter);

    }
And finally the Activity xml
XML code:
<?xml version="1.0" encoding="utf-8"?>
<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:background="@color/backgroundBlue"
    tools:context=".PrevJourActivity">


    <TextView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:id="@+id/feeling_display"
        android:layout_above="@+id/entry_display"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/entry_display"/>

    <ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/list_stuff">


    </ListView>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/button_pjback"
        android:text="Back"
        android:background="@drawable/button_background"
        android:textColor="@android:color/black"
        android:textStyle="bold"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="46dp"/>


</RelativeLayout>

Now, based on what little I know about how View newView works, I assume it's creating a new instance of activity_prevjour every time it is called (which would be every time it pulls an item from the database), so now to figure that part out!

Thanks for all your help :)

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

You need two layouts - one is for the activity, and that contains the ListView, which is like a special frame that makes a list. You put that wherever you want it on the screen. You also need a layout for your items in the list

The ListView works by creating a View for each item in the list, which is what the Adapter handles. There are two methods you're overriding in there - newView() and bindView(). newView() is what's called when the ListView needs to create a new View to hold an item - you're inflating a layout to create your item's UI View, and that will go into the ViewGroup which is like an empty box in the list. "Hey what do I put in here" is what it's basically asking. This version is just inflating the same layout for every view, so they'll all look the same. This is where you need a layout that only holds your item's stuff - you're inflating the activity's layout again, so each list item has a mini activity layout in it, complete with button (and ListViews!)

Aaand just so you know, bindView() is where the ListView actually needs to display an item's details, so that's where you find all the TextViews and such in your item's layout, and set them to info from the Cursor. The view that's being passed in is the one newView() created. So newView() makes generic list items, and bindView() puts the data in them. Because it's a CursorAdapter it automagically gets the record for each item (the Cursor is always pointing at the right one), other Adapters might give you a position on the list, and then you look up what item that refers to in a list or array or whatever

Literal Hamster
Mar 11, 2012

YOSPOS


I'm having problems with a custom view. The issue is that the segmented inner buttons in light blue are misaligned downwards and partially cut-off. I think it's happening because I'm miscalculating the dimensions of the outer arc during onMeasure(), but I'm not sure how I should go about confirming that. Relevant code below, project is here.

Code is in C#/Xamarin, but I can do a quick translate to Java if necessary.

XML code:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:seekarc="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">
    <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/measurement_preview" android:layout_gravity="center_horizontal" android:layout_centerInParent="true" tools:src="@android:drawable/progress_indeterminate_horizontal"/>
    <seekarc.SeekArc
        android:id="@+id/seekArc"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:padding="30dp"
        seekarc:rotation="180"
        seekarc:startAngle="30"
        seekarc:sweepAngle="300"
        seekarc:touchInside="false"
        seekarc:progressWidth="6dp"
        seekarc:arcWidth="4dp" />
    <circularselector.CircularSelector
        android:id="@+id/edit_state_selector"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_centerInParent="true" />
    <TextView
        android:id="@+id/component_value_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true" />
</RelativeLayout>
C# code:
protected override void OnDraw (Canvas canvas)
{
	foreach (var segment in Segments)
	{
		canvas.DrawPath (segment.Path, segment.Paint);
	}
}
C# code:
protected override void OnMeasure (int widthMeasureSpec, int heightMeasureSpec)
{
	var height = GetDefaultSize (SuggestedMinimumHeight, heightMeasureSpec);
	var width = GetDefaultSize (SuggestedMinimumWidth, widthMeasureSpec);
	var minimum = Math.Min (width, height);

	var arcDiameter = minimum - PaddingLeft;
	ArcRadius = arcDiameter / 2;
	float top = (height / 2) - (arcDiameter / 2);
	float left = (width / 2) - (arcDiameter / 2);

	if (Segments.Count < SegmentCount)
	{
		var startAngle = 0f;
		var sweepAngle = (360f / SegmentCount) * (1 - GapWidthRatio);
		var gap = sweepAngle * GapWidthRatio;

		for (var iterator = 0; iterator < SegmentCount; iterator++)
		{
			Segments.Add (new Segment (new RectF (left, top, left + arcDiameter, top + arcDiameter),
										SegmentWidth,
										iterator + 1,
										startAngle + gap,
										sweepAngle,
										ArcRadius,
										SegmentColor));
			startAngle += (sweepAngle + gap);
		}
	}

	base.OnMeasure (widthMeasureSpec, heightMeasureSpec);
}
C# code:
protected sealed class Segment
{
	private readonly float _startAngle;
	private readonly float _endAngle;
	private readonly int _arcRadius;
	private readonly RectF _arcRectangle;
	private readonly float _width;

	public Segment (RectF arcRectangle, float width, int position, float startAngle, float sweepAngle, int arcRadius, Color color)
	{
		Position = position;
		_startAngle = startAngle;
		_endAngle = startAngle + sweepAngle;
		_arcRadius = arcRadius;
		_arcRectangle = arcRectangle;
		_width = width;

		Path = new Path ();
		Paint = new Paint
		{
			Color = color,
			AntiAlias = true,
			StrokeWidth = 10f
		};
		Paint.SetStyle (Paint.Style.FillAndStroke);
		Path.AddArc (arcRectangle, startAngle, sweepAngle);
		Path.ArcTo (arcRectangle.Scale (width), startAngle + sweepAngle, -sweepAngle);
		Path.Close ();
	}

	public Path Path { get; }
	public Paint Paint { get; }
	public int Position { get; }

	public bool IsWithinBounds (float x, float y)
	{
		var xRemainder = x - _arcRectangle.CenterX ();
		var yRemainder = y - _arcRectangle.CenterY ();
		var radius = Math.Sqrt (xRemainder * xRemainder + yRemainder * yRemainder);
		var angle = Math.Atan2 (yRemainder, xRemainder);
		angle = ((angle >= 0) ? angle : (2 * Math.PI + angle)).ToDegrees ();

		return angle > _startAngle && angle < _endAngle && radius > (_arcRadius * _width) && radius < _arcRadius;
	}
}
Edit: For whatever reason, overriding onSizeChanged() instead of onMeasure() seems to have fixed the problem. :shrug:

Literal Hamster fucked around with this message at 00:03 on Apr 12, 2016

FAT32 SHAMER
Aug 16, 2012



baka kaba posted:

You need two layouts - one is for the activity, and that contains the ListView, which is like a special frame that makes a list. You put that wherever you want it on the screen. You also need a layout for your items in the list

The ListView works by creating a View for each item in the list, which is what the Adapter handles. There are two methods you're overriding in there - newView() and bindView(). newView() is what's called when the ListView needs to create a new View to hold an item - you're inflating a layout to create your item's UI View, and that will go into the ViewGroup which is like an empty box in the list. "Hey what do I put in here" is what it's basically asking. This version is just inflating the same layout for every view, so they'll all look the same. This is where you need a layout that only holds your item's stuff - you're inflating the activity's layout again, so each list item has a mini activity layout in it, complete with button (and ListViews!)

Aaand just so you know, bindView() is where the ListView actually needs to display an item's details, so that's where you find all the TextViews and such in your item's layout, and set them to info from the Cursor. The view that's being passed in is the one newView() created. So newView() makes generic list items, and bindView() puts the data in them. Because it's a CursorAdapter it automagically gets the record for each item (the Cursor is always pointing at the right one), other Adapters might give you a position on the list, and then you look up what item that refers to in a list or array or whatever

This did the trick, thank you!!

And much to everyone's relief, that finishes our senior project app, so I probably won't be bothering you guys much now :3:

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

We released ReDex today, a bytecode optimizer for Android apps. It takes in an APK and produces an optimized one. 25% improvements in speed and size aren't uncommon.

http://fbredex.com/ is the main site. https://code.facebook.com/posts/1480969635539475/optimizing-android-bytecode-with-redex is the post where we first announced it, which describes some of the optimizations it performs.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

Subjunctive posted:

We released ReDex today, a bytecode optimizer for Android apps. It takes in an APK and produces an optimized one. 25% improvements in speed and size aren't uncommon.

http://fbredex.com/ is the main site. https://code.facebook.com/posts/1480969635539475/optimizing-android-bytecode-with-redex is the post where we first announced it, which describes some of the optimizations it performs.

Nice :)

Are those comparisons against "plain" compiled code, or is that being compared against the same app with Proguard's optimizations?

Does running something through Proguard impair later optimizing it with redex?

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

Jabor posted:

Nice :)

Are those comparisons against "plain" compiled code, or is that being compared against the same app with Proguard's optimizations?

Does running something through Proguard impair later optimizing it with redex?

Versus Proguarded code, since that's what we use on our apps.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
That's pretty impressive.

Is there a similar performance gain if you're just using redex (without proguard)? The reflection-aware optimizations seem really cool, but of slightly dubious value if you still have to tell proguard about everything you're doing there. Or do you just have proguard keep everything and let redex do all of the class renaming and dead-code removal?

How fast is the actual optimization process? Is it feasible to use on dev builds?

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

Jabor posted:

That's pretty impressive.

Is there a similar performance gain if you're just using redex (without proguard)? The reflection-aware optimizations seem really cool, but of slightly dubious value if you still have to tell proguard about everything you're doing there. Or do you just have proguard keep everything and let redex do all of the dead-code removal?

How fast is the actual optimization process? Is it feasible to use on dev builds?

I would expect bigger gains vs non-Proguarded, but I can ask. The internal post I'm reading is somewhat old (enough so that I want to recheck my vs-Proguard claim).

I'm not sure what the best practice is for DCE, but I suspect it's letting ReDex do it all. ReDex's optimizations are a superset.

Speed I don't know off-hand, will depend on size of app, but we're pretty sensitive to build time.

JawnV6
Jul 4, 2004

So hot ...
I'm building the firmware side of a BLE interface and trying to debug an issue with Android. The short version is that Android doesn't listen for notifications before writing to a characteristic. iOS does, LightBlue does, and Android works fine if one of those runs first.

The code looks like:
code:
setCharacteristicNotification(writeCharacteristic, true);

UUID uuid = UUID.fromString(GattServerAttributes.CLIENT_CHARACTERISTIC_CONFIG); // "00002902-...
BluetoothGattDescriptor descriptor = writeCharacteristic.getDescriptor(uuid);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(descriptor);
From SO answers (edit: and the official docs), this looks like the correct way to do things. I am certain I want Notifications, not Indications. After this runs, the onDescriptorWrite callback fires with status=0 (so it thinks it went well) and goes on to write to the characteristic.

On the embedded side, I don't actually see the descriptor write come through. I'm confused enough by how this is all set up, it seems like they're discovering services all the time, and there's a lot of un-registering for notifications to get around the KitKat limit of 4, but MTU limitations have pushed us to Lollipop anyway.

I'm single stepping over these things and not seeing the descriptor transaction making it across. I'm stuck, I'd welcome whatever suggestions come up.

JawnV6 fucked around with this message at 02:36 on Apr 14, 2016

speng31b
May 8, 2010

Some bluetooth profile implementations support indications and not notifications. you'll need to check and use indications as a fallback if notifications aren't supported. sorry about that. here's a snippet that should point you in the right direction.

code:
final int propNoti = BluetoothGattCharacteristic.PROPERTY_NOTIFY;
      final byte[] enableNotificationsValue = (charac.getProperties() & propNoti) == propNoti
          ? BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
          : BluetoothGattDescriptor.ENABLE_INDICATION_VALUE;
      if (!desc.setValue(enableNotificationsValue)) {
        throw new RuntimeException("failed setValue(enableNotificationsValue)");
      }

JawnV6
Jul 4, 2004

So hot ...

speng31b posted:

Some bluetooth profile implementations support indications and not notifications. you'll need to check and use indications as a fallback if notifications aren't supported.

I wrote the profile on the device. Do you mean Android implementation? Like its phone specific if I can even ask for notifications?

The firmware is hardcoded to check for 1, 2 won't work on that side.

e: Our EE figured it out. Difference in RESPONSE/NORESPONSE, Android was using "write command" instead of "write request". Thanks for the pointers!

JawnV6 fucked around with this message at 16:17 on Apr 14, 2016

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

I'm idly thinking about doing an Android app again for the first time in years. Lately I've been doing a lot of web work with React...does anyone here have anything to say about React Native for Android development?

StashAugustine
Mar 24, 2013

Do not trust in hope- it will betray you! Only faith and hatred sustain.

I took a community college class on Android but the textbook was pretty garbage, and I like to have reference books for that kind of thing. Does anyone have a good recommendation for a reference for Android programming?

FAT32 SHAMER
Aug 16, 2012



StashAugustine posted:

I took a community college class on Android but the textbook was pretty garbage, and I like to have reference books for that kind of thing. Does anyone have a good recommendation for a reference for Android programming?

I wouldn't really call it a reference book but I got Big Nerd Ranch's Android Programming book and it took me from knowing jack poo poo about Android to writing a decent app and laying foundations for more complicated things/indepth complicated things in the course of three weeks. Probably quicker if I had devoted more than a few minutes a day to it.

Thom ZombieForm
Oct 29, 2010

I will eat you alive
I will eat you alive
I will eat you alive
Hey android peoples. This semester's group project is in android which our group is "learning" as we go. We are pulling from a movie database and allowing the user to bookmark movies. I began coding the bookmark portion, and currently my solution to saving their bookmarks is to write to a file the movie id (I'm using http://www.androidinterview.com/android-internal-storage-read-and-write-text-file-example/ this as a guide). Is this the best way to save stuffs?

kitten smoothie
Dec 29, 2001

Thom ZombieForm posted:

Hey android peoples. This semester's group project is in android which our group is "learning" as we go. We are pulling from a movie database and allowing the user to bookmark movies. I began coding the bookmark portion, and currently my solution to saving their bookmarks is to write to a file the movie id (I'm using http://www.androidinterview.com/android-internal-storage-read-and-write-text-file-example/ this as a guide). Is this the best way to save stuffs?

No, use a database.

http://developer.android.com/training/basics/data-storage/databases.html

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

Counterpoint: write a JSON file of the IDs in an array, read it at startup. Keep it sorted if you want to search more quickly. SQL is overkill, complexity you don't need right now.

Thom ZombieForm
Oct 29, 2010

I will eat you alive
I will eat you alive
I will eat you alive
Thanks guys. I played around with both methods.

I have one more question - and it pertains to the overall layout of the project, this is how babbys first android project evolved-

- We started with three activities- one for searching movies (this is the main activitiy), one for accessing bookmarks, and one for changing settings.

- From there we added classes for obtaining data, (model/adapter/async/listener stuff). (I don't have a firm grasp on the concepts here and need to find a good tutorial, but they work)

- Then we learnt of fragments / retrofit / gson

I am playing around / learning fragments at the moment, and hoping to alter the project (if not for app performance, then for learning) by

A) having just one activity, which has a search, bookmarks, and settings fragment, and fragments for the api calls

and

B) Rebuilding the async stuff from scratch to actually understand it and then scrapping it for retrofit etc.

I am mostly wondering if A) is a decent design decision, or if there's something to consider that I missed.

I am very scrub and learning (java as well - I've only known c++ before this class) through lots of googling and official/unofficial android guides / android api.

brap
Aug 23, 2004

Grimey Drawer
Fragments basically suck but so does everything else Google gives you. As far as I know these complaints still apply.

Stick with model-view-presenter if you can.

Sereri
Sep 30, 2008

awwwrigami

Has anyone here ever come across this:

I have a webview that does not accept data via loadDataWithBaseURL(). It just stays with empty html and body tags. I can get the html code in via loadData() just fine but that won't allow me to load files from the asset folder.
Interestingly it also works fine with loadDataWithBaseURL() on my phone with an updated system webview but won't work if I uninstall the updates. Still won't help with my non-updated emulator or system webviews.

Vesi
Jan 12, 2005

pikachu looking at?

Sereri posted:

Has anyone here ever come across this:

I have a webview that does not accept data via loadDataWithBaseURL(). It just stays with empty html and body tags. I can get the html code in via loadData() just fine but that won't allow me to load files from the asset folder.
Interestingly it also works fine with loadDataWithBaseURL() on my phone with an updated system webview but won't work if I uninstall the updates. Still won't help with my non-updated emulator or system webviews.

I do it like this, it was done several years ago so I no longer remember why but it's been tested on hundreds of devices:

code:
        if(blankchat == null) {
            InputStream is = null;
            try {
                is = getActivity().getAssets().open("chat/blankchat.html");
                blankchat = convertStreamToString(is);

            }catch(IOException ex) {
                Ln.e(ex, "chat/blankchat.html");
            }finally{
                if(is != null) {
                    try {
                        is.close();
                    }catch(IOException ignored) {
                    }
                }
            }
        }

        webView.loadDataWithBaseURL("file:///android_asset/", blankchat, "text/html", "utf-8", null);
with

code:
    private static String blankchat;
    static String convertStreamToString(java.io.InputStream is) {
        java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
        return s.hasNext() ? s.next() : "";
    }

Jake Armitage
Dec 11, 2004

+69 Pimp
This is a total stab in the dark, but has anyone ever worked with displaying Jpeg2000 (.jpf, .j2k, .jpe) files in an Android app? I am an iOS developer, and loading j2k files was stupid easy on iOS, but all my Googling is telling me on Android, anything other than like two image formats, jpg and png, requires linking poorly documented, barely maintained C libraries and something called NDK and I just can't believe that's correct. I actually expected Android to be way ahead of iOS on this.

On iOS it's automatic. It recognizes the filetype automatically and just loads it into a UIImageView. Has anyone ever done this on Android?

Sereri
Sep 30, 2008

awwwrigami

Vesi posted:

I do it like this, it was done several years ago so I no longer remember why but it's been tested on hundreds of devices:

with


Thanks for the reply. However my html code is generated at runtime. Also webView.loadDataWithBaseURL() for some reason does apparently absolutely nothing. The weird thing is that Awful.apk has 2 other webviews with mostly the same code and everything is working fine there. Only this one just doesn't want to play ball.
I think as a last resort I might just load the javascript and css via stream from the asset folder and inline it into the html, then just use loadData() :suicide:

speng31b
May 8, 2010

JawnV6 posted:

I wrote the profile on the device. Do you mean Android implementation? Like its phone specific if I can even ask for notifications?

The firmware is hardcoded to check for 1, 2 won't work on that side.

e: Our EE figured it out. Difference in RESPONSE/NORESPONSE, Android was using "write command" instead of "write request". Thanks for the pointers!

Sorry for the super delayed response, my bad for not totally reading the question. I've implemented just about every permutation of bullshit on the Android side for BLE, but I've never done the opposite side, just worked with hardware teams on that. Didn't see that you had control over the profile on the other end. Glad you figured it out :)

Not sure if this matters to you, but FWIW, this is one of those Android things where you really need to test on Motorola, Samsung, LGE, 4.3, 4.4.2, 4.4.4, 5.0, 5.1, 6.0+ - all of the above. BLE is ultrafucked on Android and every stack is a little bit different. It actually comes down to things like "if you gatt connect on the UI thread on a Samsung running 4.4+, it breaks in this way that delays connect by X ms but is recoverable, but if you do it on the LE scan callback thread it works rightaway, but breaks on Motorola in an unrecoverable way", and so much more fun like that.

speng31b fucked around with this message at 01:25 on Apr 23, 2016

Volmarias
Dec 31, 2002

EMAIL... THE INTERNET... SEARCH ENGINES...

Jake Armitage posted:

This is a total stab in the dark, but has anyone ever worked with displaying Jpeg2000 (.jpf, .j2k, .jpe) files in an Android app? I am an iOS developer, and loading j2k files was stupid easy on iOS, but all my Googling is telling me on Android, anything other than like two image formats, jpg and png, requires linking poorly documented, barely maintained C libraries and something called NDK and I just can't believe that's correct. I actually expected Android to be way ahead of iOS on this.

On iOS it's automatic. It recognizes the filetype automatically and just loads it into a UIImageView. Has anyone ever done this on Android?

Conveniently enough, a friend of mine was working in this area. Check out https://code.google.com/p/jj2000 and https://github.com/izzytwosheds/jjlossless/ (his library), hopefully that helps.

JawnV6
Jul 4, 2004

So hot ...

speng31b posted:

Sorry for the super delayed response, my bad for not totally reading the question. I've implemented just about every permutation of bullshit on the Android side for BLE, but I've never done the opposite side, just worked with hardware teams on that. Didn't see that you had control over the profile on the other end. Glad you figured it out :)

Not sure if this matters to you, but FWIW, this is one of those Android things where you really need to test on Motorola, Samsung, LGE, 4.3, 4.4.2, 4.4.4, 5.0, 5.1, 6.0+ - all of the above. BLE is ultrafucked on Android and every stack is a little bit different. It actually comes down to things like "if you gatt connect on the UI thread on a Samsung running 4.4+, it breaks in this way that delays connect by X ms but is recoverable, but if you do it on the LE scan callback thread it works rightaway, but breaks on Motorola in an unrecoverable way", and so much more fun like that.

Thanks for this. It's confirming what QA is hitting at the very least. I'm trying to work out happy-path scenarios for it (like once connected, rush to do absolutely everything) but getting reports from users that it's still wonky.

speng31b
May 8, 2010

JawnV6 posted:

Thanks for this. It's confirming what QA is hitting at the very least. I'm trying to work out happy-path scenarios for it (like once connected, rush to do absolutely everything) but getting reports from users that it's still wonky.

If you check back in post history in this thread, I made a ragepost about my implementation of it. Actually has some pretty useful details surrounded by rage if you care.

cubicle gangster
Jun 26, 2005

magda, make the tea
Cross posting from the general android thread-
disclaimer - we're a technical group who have cobbled together bits of code that work, but we do not have a background in code. We're a marketing agency that has built a presentation app in unity to aid in sales pitches that is getting some fairly serious traction, but we're starting to hit our limit in what we can code. We want to upgrade it, and plan to hire someone very soon, but first i want to understand what we're asking (and also if this sounds easy, hello give me a message!)

Anyone here familiar with mirroring a unity app to another phone, or even just a piece of reference text that can say where someone is in it? no idea how difficult this is. it's so that someone using the app can be given a talk over the phone and given a properly directed sales pitch.
I also have a few other questions for any seasoned developers, namely:

How difficult is it to auto update unsigned apk's over wifi - and what do we need to use to host the apk files for this to happen? Our idea for the frontend website was a simple wordpress login/database template that links to a google drive.
by the end of this year I see us having up to 100 users, who can choose from around 50 apk files to keep on their phone of various presentations that they swap in and out of as they please. We're going to recommend that they back the installers up rather than delete outright (file sizes range from 2-500mb each), so it'd need to auto update if someone installs from an old one - or wipe clean should it not be relevant anymore.
kind of like a private app store, but hopefully not as expensive as that collection of words makes it sound.

There's another thing we were thinking about - how possible is it to automatically generate an app that acts as a front end for these apk files? The idea being they'd go on our website and pick 5 of these presentations, name it, then get a link to download an app which when started is just a launcher for the 5 presentations. it would need to check that they already exist on the phone and make note of it, but it would provide a very clean way to show these without the user having to spend time sorting through apps moving them in and out of folders constantly.

We do want to hire a coder to handle these as they're a little bit above our area of expertise. Would appreciate an idea of how difficult these things are, how long they'd take and how much it would cost a coder to get them running. If anyone here is or knows someone that could knock the first ones out easily then we've got a budget to get those done straight away. I figure the first 2 might be a little easier and the third is a little more involved (plus might need a reworking of the website?)
I didn't post this in the straight up hiring a developer part because I guess what i'm after most is an understanding of what we're asking.

speng31b
May 8, 2010

Go ahead and put out a job posting for a mid-junior-level Unity or Android dev. This isn't a development question.

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

speng31b posted:

This isn't a development question.

Ehh, it's develop-y enough that I'd say that this thread is the best fit to tell the poster what's needed (i.e. that they need a developer).

speng31b
May 8, 2010

Mission accomplished.

Adbot
ADBOT LOVES YOU

cubicle gangster
Jun 26, 2005

magda, make the tea
Kind of dick response. first and foremost I was asking if it was difficult, what it would cost and if the third thing was even possible. i just figured i'd mention that if anyone could bang out some of it in their sleep they could pm me. Shouldn't have mentioned it I guess.

This:

quote:

How difficult is it to auto update unsigned apk's over wifi - and what do we need to use to host the apk files for this to happen?
and this:

quote:

how possible is it to automatically generate an app that acts as a front end for these apk files? The idea being they'd go on our website and pick 5 of these presentations, name it, then get a link to download an app which when started is just a launcher for the 5 presentations. it would need to check that they already exist on the phone and make note of it
is something I am very curious about. I also do not think that is a junior level unity job.

cubicle gangster fucked around with this message at 01:34 on May 3, 2016

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