Categories
discuss

How do I get the position selected in a RecyclerView?

I am experimenting with the support library’s recyclerview and cards. I have a recyclerview of cards. Each card has an ‘x’ icon at the top right corner to remove it:

The card xml, list_item.xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp">
<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/taskDesc"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:textSize="40sp"
        android:text="hi"/>
    <ImageView
        android:id="@+id/xImg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentRight="true"
        android:src="@drawable/ic_remove"/>
</RelativeLayout>
</android.support.v7.widget.CardView>

I attempted to tag the row with the position I would use in notifyItemRemoved(position) in TaskAdapter.java:

public class TaskAdapter extends RecyclerView.Adapter<TaskAdapter.TaskViewHolder>  {

private List<Task> taskList;
private TaskAdapter thisAdapter = this;


// cache of views to reduce number of findViewById calls
public static class TaskViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
    protected TextView taskTV;
    protected ImageView closeBtn;
    public TaskViewHolder(View v) {
        super(v);
        taskTV = (TextView)v.findViewById(R.id.taskDesc);
    }

    @Override
    public void onClick(View v) {
        int position = v.getTag();
        adapter.notifyItemRemoved(position);
    }
}


public TaskAdapter(List<Task> tasks) {
    if(tasks == null)
        throw new IllegalArgumentException("tasks cannot be null");
    taskList = tasks;
}


// onBindViewHolder binds a model to a viewholder
@Override
public void onBindViewHolder(TaskViewHolder taskViewHolder, int pos) {
    final int position = pos;
    Task currTask = taskList.get(pos);
    taskViewHolder.taskTV.setText(currTask.getDescription());

    taskViewHolder.closeBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            thisAdapter.notifyItemRemoved(position);
        }
    });
}

@Override
public int getItemCount() {
    return taskList.size();
}


// inflates row to create a viewHolder
@Override
public TaskViewHolder onCreateViewHolder(ViewGroup parent, int pos) {
    View itemView = LayoutInflater.from(parent.getContext()).
                                   inflate(R.layout.list_item, parent, false);

    return new TaskViewHolder(itemView);
}
}

This won’t work because you can’t set a tag nor can I access the adapter from onClick.

Answer

Set your onClickListeners on onBindViewHolder() and you can access the position from there. If you set them in your ViewHolder you won’t know what position was clicked unless you also pass the position into the ViewHolder

EDIT

As pskink pointed out ViewHolder has a getPosition() so the way you were originally doing it was correct.

When the view is clicked you can use getPosition() in your ViewHolder and it returns the position

Update

getPosition() is now deprecated and replaced with getAdapterPosition()

Update 2020

getAdapterPosition() is now deprecated and replaced with getAbsoluteAdapterPosition() or getBindingAdapterPosition()

Kotlin code:

override fun onBindViewHolder(holder: MyHolder, position: Int) {
        // - get element from your dataset at this position
        val item = myDataset.get(holder.absoluteAdapterPosition)
    }
Categories
discuss

Jooq Maven and multiple schemas

I’m trying to use maven to auto generate pojo for my postgres database. Though even if I take maven out of the equation I have the issue.

My data is split upon multiple schemas, and I’ll need to work with all of them in my code base. I’d like to know how I can accomplish this short of setting up a task for each one of them in maven. This is what I have so far.

Obviously this only seems to work for a single schema. I’d like to be able to generate POJOs for multiple ones. I tried multiple xml elements, or comma delimited but it just errors out.

mvn -PDBGen generate-sources #is the command i use

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.foobar.sandbox</groupId>
    <artifactId>playBox</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <jooq-version>3.4.4</jooq-version>
        <psql-version>9.1-901-1.jdbc4</psql-version>
    </properties>

    <profiles>
        <profile>
            <id>DBGen</id>

            <build>
                <plugins>

                    <!-- Maven Auto Generation -->
                    <plugin>
                        <groupId>org.jooq</groupId>
                        <artifactId>jooq-codegen-maven</artifactId>
                        <version>${jooq-version}</version>

                        <!-- The plugin should hook into the generate goal -->
                        <executions>
                            <execution>
                                <goals>
                                    <goal>generate</goal>
                                </goals>
                            </execution>
                        </executions>

                        <!-- Manage the plugin's dependency. In this example, we'll use a PostgreSQL database -->
                        <dependencies>
                            <dependency>
                                <groupId>postgresql</groupId>
                                <artifactId>postgresql</artifactId>
                                <version>${psql-version}</version>
                            </dependency>
                        </dependencies>

                        <!-- Specify the plugin configuration.
                             The configuration format is the same as for the standalone code generator -->
                        <configuration>

                            <!-- JDBC connection parameters -->
                            <jdbc>
                                <driver>org.postgresql.Driver</driver>
                                <url>jdbc:postgresql://localhost:5433/mydb</url>
                                <user>user</user>
                                <password>s3cret</password>
                            </jdbc>

                            <!-- Generator parameters -->
                            <generator>
                                <name>org.jooq.util.DefaultGenerator</name>
                                <database>
                                    <name>org.jooq.util.postgres.PostgresDatabase</name>
                                    <includes>.*</includes>
                                    <inputSchema>ui</inputSchema>
                                    <excludes></excludes>
                                </database>
                                <target>
                                    <packageName>com.foobar.playbox.jooq.generated</packageName>
                                    <directory>target/generated-sources/jooq</directory>
                                </target>
                            </generator>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>

    </profiles>


    <build>
        <plugins>
            <!-- compiler -->
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>build-helper-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>add-source</goal>
                        </goals>
                        <configuration>
                            <sources>
                                <source>target/generated-sources/jooq</source>
                            </sources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

        </plugins>
    </build>


    <dependencies>
        <!-- postgres -->
        <dependency>
            <groupId>postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>${psql-version}</version>
        </dependency>
        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.33</version>
        </dependency>
        <!-- DataBase -->
        <dependency>
            <groupId>org.jooq</groupId>
            <artifactId>jooq</artifactId>
            <version>${jooq-version}</version>
        </dependency>
        <dependency>
            <groupId>org.jooq</groupId>
            <artifactId>jooq-meta</artifactId>
            <version>${jooq-version}</version>
        </dependency>
        <dependency>
            <groupId>org.jooq</groupId>
            <artifactId>jooq-codegen</artifactId>
            <version>${jooq-version}</version>
        </dependency>
        <!-- Logging -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.7</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.7</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.16</version>
        </dependency>
        <!-- Test -->
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-all</artifactId>
            <version>1.9.5</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

Answer

The secret is to replace this:

<inputSchema>ui</inputSchema>

By this:

<schemata>
  <schema>
    <inputSchema>ui</inputSchema>
  </schema>
  <schema>
    <inputSchema>other_schema</inputSchema>
  </schema>
</schemata>

You could also entirely remove all <inputSchema/> configuration, then the jOOQ code generator will generate classes for all the schemas it discovers (including pg_catalog and information_schema)

More details can be found in the jOOQ manual.

Categories
discuss

How to keep $.ajax() async inside $.each() loop but react to result on each iteration

I’m having trouble with some dumb architecture because I’m dumb. I’m trying to loop over YouTube videos posted to Reddit, extract URLs and process them into an .m3u playlist.

Full code at Subreddit to YouTube Source Bookmarklet – Play YouTube music from subreddits in Foobar with foo_youtube

At some point I get the idea that I could check each URL to see if the video is dead or not, and offer an alternative if they’re removed.

So I do AJAX requests to YouTube API and if there’s an error I’m supposed to react to it and change that item’s URL.

But the problem is it only works if the AJAX is NOT async – this takes many seconds, during which the page is jammed.

I’d like to let the AJAX be async but I don’t know how I should structure my code.

Here is PSEUDOCODE of how it is now:

var listing = // data from reddit API
$.each(listing, function(key, value) {
    var url = // post URL from reddit posts listing 
    // ( "http://youtu.be/XmQR4_hDtpY&amp;hd=1" )
    var aRegex = // to parse YouTube URLs 
    // ( (?:youtube(?:-nocookie)?.com/....bla...bla )
    var videoID = // YouTube video ID, extracted with regex 
    // ( "XmQR4_hDtpY" )
    var itemArtist = // parsed from reddit posts listing 
    // ( "Awesome Artist" )
    var itemTitle = // parsed from reddit posts listing 
    // ( "Cool Song (Original Mix)" )
    var itemURL = // url, further processed 
    // ( "3dydfy://www.youtube.com/watch?v=XmQR4_hDtpY&hd=1" )

    $.ajax({
            type: "HEAD",
            url: "https://gdata.youtube.com/feeds/api/videos/" + videoID,
            error: function() { 
                // If it's no longer available 
                // (removed, deleted account, made private)
                deadVid++; // chalk up another dead one, for showing progress
                itemURL = // dead videos should get a different URL 
           // ( "3dydfy-search://q=Awesome%20Artist%20Cool%20Song....." )
            }
        });

    // further process itemURL!
    // at this point I want itemURL changed by the .ajax()'s error callback
    // but I'm trying to keep the requests async 
    // to not jam the page while a hundred HTTP requests happen!
    if (condition){
        itemURL += // append various strings
    }
    // Write the item to the .m3u8 playlist
    playlist += itemURL + 'n';
}// end .each()

Answer

Basically you want to know

  • What the errors were and
  • When every ajax request is finished

If you push the errors into a list, the results will be ready at the end (order not guaranteed of course).

For the second part, if you keep an array of the ajax promises returned from each $.ajax you can use $.when and wait for them all to complete using always().

As a basic example (other details removed):

var listing = {}; // data from reddit API
var promises = [];
var results = [];
$.each(listing, function(key, value) {
    // [snip]
    promises.push($.ajax({
            type: "HEAD",
            url: "https://gdata.youtube.com/feeds/api/videos/" + videoID,
            error: function() { 
                //[snip]
                results.push({
                   itemArtist: itemArtist,
                   videoID: videoID,
                   url: itemURL});
            }
        });
    );
}
// Wait for all promises to complete (pass or fail) 
$.when.apply($, promises).always(function(){
    // process list of failed URLs
});

Apologies for any typos. This was coded straight into the answer, but you get the idea.

I note you mention 100s of requests, but the browser will only allow a handful through at a time, so no need for additional processing.

If always is not working you can add your own deferred objects that resolve on success or fail:

var listing = {}; // data from reddit API
var promises = [];
var results = [];
$.each(listing, function(key, value) {
    var deferred = $.Deferred();
    promises.push(deferred.promise());
    // [snip]
    $.ajax({
            type: "HEAD",
            url: "https://gdata.youtube.com/feeds/api/videos/" + videoID,
            complete: function(){
                // resolve on success or fail
                deferred.resolve();
            },
            error: function() { 
                //[snip]
                results.push({
                   itemArtist: itemArtist,
                   videoID: videoID,
                   url: itemURL});
            }
        });
    );
}
// Wait for all promises to complete (pass or fail) 
$.when.apply($, promises).always(function(){
    // process list of failed URLs
});

Update Dec 2015

Here is another cool way to chain parallel promises together, without using an array (so long as you do not need the data values passed through to the callbacks):

Simplified code:

   var promise;   // Undefined is also a resolved promise when passed to $.when()
   $.each(listing, function(key, value) {
       // Each new Ajax promise is chained, in parallel, with the previous promise
       promise = $.when(promise, $.ajax({...}));
   });
   // When they are all finished, fire a final callback
   $.when(promise).always(function(){
       // All done!
   });

This has had some criticism, mainly from people that feel it is “unclean”, but for the simplifying of parallel promise code the trade-off is minimal.

I figured out this was possible when I saw someone use promise = promise.then(newpromise) to chain events in sequence. After some experimenting I found I could do the same in parallel using promise = $.when(promise, newpromise)

Categories
discuss

Is there an easy way to determine an HTML element’s content category?

HTML elements belong to content cagetories. For my task at hand, I need to ensure that I’m not nesting interactive content nodes.

Currently, I can traverse the node’s parents to make sure none of them are of the type <a>, <button>, <details>, <embed>, <iframe>, <keygen>, <label>, <select>, and <textarea>. All of these elements are part of the “Interactive content” category.

Other types can also be interactive.

  • <audio>, if the controls attribute is present
  • <img>, if the usemap attribute is present
  • <input>, if the type attribute is not in the hidden state
  • <menu>, if the type attribute is in the toolbar state
  • <object>, if the usemap attribute is present
  • <video>, if the controls attribute is present

Additionally, any element with a tabindex attribute is considered interactive.

These rules are all part of the HTML spec and are well-documented, but kind of a pain to keep track of. Is there an easier way of checking which content categories an element belongs to?

Answer

No, there is nothing in the DOM for the classification of elements that way. The classifications have been made in HTML5 spec prose only. There are few old classifications that are reflected in the DOM, such as classification of form fields by their type, with the type property, and you can indirectly find some classifications according to rendering rules in the sense that different elements have different display property value in style settings. But all these modern classifications need to be implemented in your code using lists of element names. You can see this from by taking a very close look at DOM definitions in HTML5 and finding out that they don’t cover the classifications.

Categories
discuss

Calendar returns date in wrong time zone

If I execute the following on a computer in the GMT timezone

TimeZone timeZone = TimeZone.getTimeZone('IST');  // India Standard Time
Calendar calendar = Calendar.getInstance(timeZone);

System.out.println(calendar.getTime());

It prints

Fri Oct 31 15:18:22 GMT 2014

Why is the date printed in the computer’s default time zone, rather than the TimeZone the Calendar was constructed with?

Answer

because Date object doesn’t have timezone as part of its state, You need SimpleDateFormat to format and print the date in your required timezone

Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..