Saturday, April 30, 2016

Tutorial: Android ListView With Custom Adapter

There are so many apps utilizing ListView in Android. Your feed in a social network, your tasks in a to-do app, even your mail in your favorite email app stored in a ListView.


Basically, ListView is a container for a collection of items that can be represented as an array. You should be able to get any item from a collection by its index and get the size of an underlying collection. Also, it would be nice to be able to add new elements to your collection unless you want it to be constant.

In my opinion, ArrayList fits this definition perfectly. In ArrayAdapter, they use List as an underlying collection, though, but in some implementations of it (LinkedList for example) get operation is linear of index you pass to it, so it can be bad for performance. But it's not a reason to reject ArrayAdapter, just be careful with what implementation you pass to it.

Custom List Adapter

ArrayAdapter by default adapts only strings to TextViews, but we want something more interesting.

Let's say we are developing a messaging app and we want to show active conversations. We will represent our chat with this class.

public class Chat {
    private int mProfilePic;
    private String mName;
    private String mMessage;

    Chat(int profilePic, String name, String message) {
        mProfilePic = profilePic;
        mName = name;
        mMessage = message;
    }

    public int getProfilePic() {
        return mProfilePic;
    }

    public String getName() {
        return mName;
    }

    public String getMessage() {
        return mMessage;
    }
}


So we want our ListView to show some information besides strings. How do we do that?

Turns out it's not so complex if you know the basics!

There are several ways to achieve this goal. One of these is to use ArrayAdapter and override getView method (the simplest) and the other is to build your WhateverYouWantAdapter that will extend BaseAdapter class (the funniest).

Let's consider both approaches.

ArrayAdapter

There is a method getView in all adapters that returns the view of your list item.

By default ArrayAdapter just finds TextView passed as a parameter to its constructor and sets the text that is stored in underlying list (by the way if your objects are not Strings it just calls toString and makes them so). You can find this in source code (line 368 see createViewFromResource method).

So to implement custom ListView we just need to override this behavior. But wait a minute you also need some place to put your data in right. Let's build a simple layout that will represent our conversation.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="8dp">
    <!--I'm using hdodenhof's library to make image circle-->
    <de.hdodenhof.circleimageview.CircleImageView
        android:id="@+id/profile_pic_imageview"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:scaleType="centerCrop"
        android:layout_marginEnd="8dp"/>
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <TextView
            android:id="@+id/name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="@android:color/black"
            android:textSize="20sp"
            android:layout_marginBottom="12dp"/>
        <TextView
            android:id="@+id/message"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="16sp"/>
    </LinearLayout>
</LinearLayout>

Where is Harry?

So here we have our friend's profile pic, his name and last message received from him.

In our getView method, we need to get access to them and set values.

public class ChatAdapter extends ArrayAdapter<Chat> {

    public ChatAdapter(Context context, int resource, ArrayList<Chat> data) {
        super(context, resource, data);
    }

    public View getView(int position, View view, ViewGroup parent) {
        //Get the instance of our chat
        Chat chat = getItem(position);

        LayoutInflater inflater = (LayoutInflater) getContext()
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE );

        //Create new list item
        View rowView = inflater.inflate(R.layout.list_item, null, true);

        //Get UI objects
        ImageView profilePic = (ImageView) rowView.findViewById(R.id.profile_pic_imageview);
        TextView nameView = (TextView) rowView.findViewById(R.id.name);
        TextView messageView = (TextView) rowView.findViewById(R.id.message);

        //Set image profile picture
        profilePic.setImageDrawable(getContext().getResources().getDrawable(chat.getProfilePic()));

        //Set text into TextViews
        nameView.setText(chat.getName());
        messageView.setText(chat.getMessage());

        return rowView;
    }

}


After that just make some test data and set your adapter to the list, everything else will be handled by Android.

ArrayList<Chat> chats = new ArrayList<>();
chats.add(new Chat(R.drawable.hermione, "Hermione Granger", "Harry! Where are you? " +
                "Dambledore is looking for..."));
chats.add(new Chat(R.drawable.ginger, "Ron Weasley", "Wingardium leviosaaaaaaaaaaaaaaaa"));
chats.add(new Chat(R.drawable.snape, "Severus Snape", "Well, it may have escaped your " +
                "notice, but life is not ..."));
chats.add(new Chat(R.drawable.iman, "Tony Stark", "I don't know why I'm even chatting with you"));

ChatAdapter adapter = new ChatAdapter(this, R.id.listview_chats, chats);

ListView chatList = (ListView) findViewById(R.id.listview_chats);
chatList.setAdapter(adapter);

BaseAdapter

This approach is manual but it's also fun because you will build your very own adapter and will understand deeply how adapters work.

The main idea is the same to override some methods in BaseAdapter they are not even implemented, so, we will do it manually. Also in the BaseList, there is no any underlying collection to store data, it means we need to make out own.

Let's use the same layout for list items. For our adapter to work we need to implement getView, getItem, getItemId, getCount methods. But before diving in the code let's consider what these should do.

  • getView(int position, View view, ViewGroup parent): for the getView idea is the same as for ArrayAdapter it should return our list item layout.
  • getItem(int pos): this method should return an instance of the object we store in list item in pos position. 
  • getItemId(int pos): you need this when for example when you use a database to retrieve items for your list, it just makes it easier to get item's id in this database. We need to implement to make our adapter work, let's just return 0 from it.
  • getCount(): this method just returns number of elements in your list

public class ChatAdapter extends BaseAdapter {
    private final Activity mContext;
    private final ArrayList<Chat> mChats;
    private final Resources mRes;
    private final LayoutInflater mInflater;

    public ChatAdapter(Activity context, ArrayList<Chat> chats) {
        mContext = context;
        mChats = chats;
        mRes = mContext.getResources();
        mInflater = mContext.getLayoutInflater();
    }

    @Override
    public int getCount() {
        return mChats.size();
    }

    @Override
    public Chat getItem(int pos) {
        return mChats.get(pos);
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    public View getView(int position, View view, ViewGroup parent) {
        //Get the instance of our chat
        Chat chat = mChats.get(position);

        //Create new list item
        View rowView = mInflater.inflate(R.layout.list_item, null, true);

        //Get UI objects
        ImageView profilePic = (ImageView) rowView.findViewById(R.id.profile_pic_imageview);
        TextView nameView = (TextView) rowView.findViewById(R.id.name);
        TextView messageView = (TextView) rowView.findViewById(R.id.message);

        //Set image profile picture
        profilePic.setImageDrawable(mRes.getDrawable(chat.getProfilePic()));

        //Set text into TextViews
        nameView.setText(chat.getName());
        messageView.setText(chat.getMessage());

        return rowView;
    }

}

And now you can use you newborn adapter just as ArrayAdapter

There is a little bit different constructor so you should change one line of code just write
ChatAdapter adapter = new ChatAdapter(this, chats);
Instead of
ChatAdapter adapter = new ChatAdapter(this, R.id.listview_chats, chats);

Result

Stop! Tony Stark???
Both approaches led me to this view. It's pretty much it. I think we've got nice cosy layout and our users will be satisfied :)

Summary

Of course, it's better to use an ArrayAdapter but I didn't include BaseAdapter part "just because". I think it will deepen your understanding of how does ListAdapter works and will encourage you to learn how things work internally in Android.

Now I'm looking forward to writing more tutorials, so stay tuned. See you next week, peace!

P.S. You can look at my code on my GitHub repository

Sunday, April 17, 2016

What if there is a similar app that is more successful than yours?



It's so much easier to publish your app in Google Play than in Appstore, that's why there are so many similar apps in Google Play. It creates conditions for healthy competition among developers.

To perform well in this competition you should always keep your app better than the others.

But what if your app is already losing? What if there is an app that has a larger audience than yours?

Actually, I think that it's not even a problem. It's an opportunity!

An opportunity

Wait, what? An opportunity? Why losing to another app is an opportunity?

Because you losing a battle not the war!

Actually, I think that software market is a place where nobody can win the war. It's Infinite War (not the Infinity War, though), with many many small battles.

Still, why losing a battle is an opportunity? Because if you analyse the reasons of losing, and why your opponent is winning you can gather very useful information.

With this information, you can come up with a plan that is even better than your opponent's.

What kind of information?

You should pay your attention to some key moments while analysing your loss.

These key moments are

  • Is your opponents app is actually better (be honest with yourself, it's the only way to improve), if so:
    • What is the feature/features making this better than yours?
      • If you find some, can you improve the idea of this feature in build it in your app?
    • If you can't find these features pay attention to the implementation of features both apps have, maybe it's just about the quality.
    • Look at things that are in your app but not in opponent's, maybe they are surplusses and making UX worse.
      • By the way, if you decide to remove these things, you should be very careful because if you have some decent audience they can use this features and removing them will be harmful.
    • Maybe it's all about graphic design. Some users migrate from one app to another (that has the same functionality) just because of design UX can make a huge difference.
  • If it is not, likely the reason of succes of other app is marketing. 
    • Unfortunately for many developers, better code and design doesn't mean larger audience, it only means an opportunity to get a larger audience. 
    • Pay attention to how your opponent marketing his app.
    • Does he have landing page about his app?
    • What traffic sources he uses?
      • Maybe he has a blog where he writing about this app (blog can be a huge source of traffic)
    • Compare this to your ways of marketing your app, find differences and figure out what you should change to gain more audience.
Another really important source of information is feedback, not only from your app, but form every similar app out there. You can find out what people need from their own testimonials.

With all this information, you can take action and make your strategy better.

Is it even legal?

About the first part, it might seem like stealing features, yes it is, but you should be a clever thief.

You shouldn't just take your rival's app and make another x.x.x version of it. Actually, you should do the things your way.

You probably already have some picture of what is your audience and why they like your app. So do everything with this on the background.

Your actual audience is your potential audience

Actually, in every business, you should aim at the audience you already have. Improve your app for them. I think that actual audience is your potential audience. It's word of mouth marketing. 

With this approach of satisfying your actual audience, you can get exponential growth. 

It's really important, but many developers and entrepreneurs don't understand that, and they are drowning while trying to attract new users. 

When you trying to walk through someone else's path you will eventually discover that you're always second.

So don't just steal someone's features try to adapt these for your users. And if you can't do so, just don't, it means that it's not for your app.

For example, look at Apple, everyone knows that they are stealing features and ideas from other mobile manufacturers, but they do it in their own way satisfying the users they already have. I think, that this is the reason of their success.

Overview

The main idea of this post is when there is some app that already has more users than yours, it can be a source of really useful information for you if you will analyse it carefully.  But you should be pragmatic about what you doing with your app when trying to gain more users.

Okay, build your audience guys, see you next week, peace!

Sunday, April 10, 2016

How To Get an Idea For an App



There are two common problems in software development, lack of knowledge and lack of ideas.

For today's post let's consider the second one.

Lack Of Ideas

Suppose you have, decent skill in software development, so what other you need to start developing software? Right, the Idea (and IDE of course). 

So where do you find them? This question is often the main struggle for many software developers.

Common Pattern

Look at apps on your smartphone. What is common between all of them?

Yes, they are all some way useful, not productive, though, but useful.

An app should be useful

It's surprising how many devs don't understand that.

Every app is useful in its own way. Some app lets you manage your personal finances, some helps you with time management, there are a bunch of apps that let you stay connected with friend and family (e-mail/messenger apps), and some of them help you avoid boredom (I still have Flappy Bird installed for the emergency case).

So most of the apps (not only mobile) out there solve some problem. So if you are a programmer you already familiar with problem-solving, but what about problem-finding?

Problem-Finding

Basically, you need to find someone's pain to relieve it. You should be like psychotherapist when you're in search of an idea.

Many developers try to solve their own problems and make similar apps one after another. Think of it, how many software developers out there that have same problems as you? Let me help you, MILLIONS. We all have common problems in living and likely some of us already came up with a solution. So please, don't make another to-do list.


But what the other thing you can do, you can ask. The answer to this question can freak you out, especially if you're introvert (like me).

Just go out and make friends!

Yes, it's that easy, but not for a software developer. Actually, it's kinda struggling for computer worms like us. But you know what? When you get use to it you'll even like it! Yes, you definitely will, because homo sapience is a social species, so it's in your nature.

Every person you meet will be some way unique and will have interests that differ from yours and problems that differ from yours. So that's your source of ideas  - people.

Actually, it's even better to find some group of people with same interests because to solve a problem you need an accurate description of it. You can't really come up with a solution if someone just telling you that one's feeling discomfort. You need to know what is the root of evil. So the more people you know with the same problem, the more information you can gather about it.

This is kind of groups I'm talking about:
  • Photographers
  • Artists
  • Poets
  • Musicians
  • Language groups
  • Any kind of professionals (even software devs, but only if you'll seek for a problem that isn't solved yet)
This list can be really long, but I think you've got the idea.

So when you have some group of people you should find out what causing pain to them and how do they fighting with this pain to provide yourself with some ready solutions that you can just automate.

And start to solve their problems, because this is what programmers do. But before starting development process find out if someone else already solved it and how maybe you have the better approach.

PulsePoint is a great example of this kind of apps. It solves the problem of people who are suffering cardiac arrests and can actually save a life, isn't it useful?

How To Win Friends

There is a plenty of content on this topic: books, podcasts, YouTube videos, blog posts. So I think it's better to give you a reference to best of them than trying to fit everything in one blog post section.

  • How to Win Friends and Influence People by Dale Carnegie - one of the best books on the topic, I encourage you to read it several times.
  • The 7 Habits of Highly Effective People: Restoring the Character Ethic by Stephen R. Covey -  this one will give you another point of view on your live and people you meet.
  • Simple Programmer Blog - blog providing soft skills especially for software developers, founded by John Sonmez, this guy is the reason why I started to blog.
  • Also, check out his book Soft Skills: The software developer's life manual you'll find a huge amount of useful information in this book (even if you are not a software developer).

Finally

This is not the only way to find an idea and not the easy one, though, because people will not tell you ready-to-develop idea, in most cases they even don't know what they want and your job is to find it out. But eventually, it's a fun process and you'll meet many great and interesting people.

See you next week, peace!

P.S. I personally think that if you're just starting out idea does not matter, just try to implement something that can be barely useful. With that approach, you find your feet rapidly.



Sunday, April 3, 2016

How To Combine Learning And Developing part 2


Read 1'st part of this post where I talk about Learning While Developing.

Hi! Today I'll tell you about the second (and I think the right one) way of combining learning and development. This way I call Developing While Learning.

Oh wait, sounds like it is the same thing as Learning While Developing, isn't it?  Yes, it might sound like the same thing, but in fact, it's opposite. Let me explain what it all means.

The essence of Developing While Learning

As I said Developing While Learning is the opposite to Learning While Developing, so you might already guess the essence by yourself.

Developing While Learning is about creating some product while learning something. But it shouldn't be your dream project. It should be something appropriate for your level. With time, probably your learning projects will be more difficult, but when you're starting out don't go right off the bat. Even most experienced developers start with "Hello world!" app when they start to learn  new technology.

Defining a success project

When you learn something you have to define your success project. Like the end point of learning, the point where you know you learned what you wanted to learn.

This project should be something really specific because when you trying to achieve something blurry and not concrete you still don't know where is the point of success. 

Here's the example of good success project
  • Weather App
    • Fetching forecast data from API
    • 3 activities
      • Weather forecast for the week
      • Details about weather for specific day
      • Settings
This project used in Developing Android Apps course at Udacity (which I encourage you to enroll).
And here's the success project that can actually harm your learning process.
  • An Android app
You'll never find something like this in any course at any University because it's too broad. I can build "Hello World" app and I'll be happy with it as an elephant (it's the Russian phrase, means very happy)  or I can try to build something with 3-5 killing features, bells, whistles and brilliant design and still not be satisfied with it. So be as specific as possible when defining success project.

The other reason why your project should be specific is that you can break it up into subtasks and for each subtask you can find out what you should learn to perform it. It's psychologically easier to perform multiple small tasks than one tremendous one.  

How to define your success project

I think the best way to define your success project for learning is to steal it. Yes, you read it right, just steal the idea from some app. Steal from Gmail, Dropbox, Instagram, Facebook, any app you know. Just take something for your level.  

It's sounds like reinventing a wheel, but it's actually reimplementing a wheel because to learn how to make a good wheel you should make some wheels (probably bad).

With this approach, you will not spend your time on thinking up and sifting ideas to just learn something. 

And who knows, maybe you'll make a better app than one you stealing from.

You also can implement your own idea, of course, just make sure that it's appropriate for your level and for what you want to learn.

Benefits of Developing While Learning

The most evident benefit is an experience. You're facing challenges that you will face in real development, but when you'll face it in real development you'll already have a solution for it.

Another benefit is your very own code. Anything you developed that way is now yours and you can use it any way you want. You can rebuild using your new skills you acquired or improve it some other way and publish it. You can take some parts of your code and make a framework from it or contribute to an open source framework. Now you can use it the way you want it to be used.

And last but not least benefit is that one day you can set your dream project as success project for your learning. With any app you develop your knowledge gets higher and higher, and there will be the moment when your dream project is appropriate for you as a success project so why not to try it?

Learning 4 life

Actually, I think that developer's professional life is about constant learning. Every developer learns something new with every new project (if it is not routine, of course). Some developers just know more than others, but there's plenty thing that they'll learn in their professional life.

So don't be afraid of saying that you just learning, everyone is just learning! 

Overview

So here's what we know from 2 parts

  1. There's 2 ways Learning While Developing and Developing While Learning
  2. Learning While Developing is not as good as may seem (but it's still a way)
  3. Developing While Learning is beneficial and actually fun!
  4. Define your Success Project! (you can steal it, nobody will know ;) )
  5. Make it as specific as possible! 
  6. Have fun learning!

That's pretty all you should know about combining learning and developing.


See you in the next one, peace!