4
\$\begingroup\$

How can I reduce the amount of repetitive code in my Android app? A lot of the code seems to be doing the same thing twice. I think that there is a more compact way to do this.

What are some ways that I can reduce lines of code in this program?
Is there a better way that I could write this program? I think that I am taking more steps than necessary.

The code is for this app.

package com.kerseykyle.easyhash;

import java.security.MessageDigest;

import android.os.Build;
import android.os.Bundle;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends Activity {

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

        Intent intent = getIntent();
        String action = intent.getAction();
        String type = intent.getType();

        if (Intent.ACTION_SEND.equals(action) && type != null) {
            if ("text/plain".equals(type)) {
                handleSendText(intent); // Handle text being sent
            } 
        } 

        EditText myTextBox = (EditText) findViewById(R.id.input);
        myTextBox.setSingleLine(true);
        myTextBox.addTextChangedListener(new TextWatcher() {

            public void afterTextChanged(Editable s) {
            }

            public void beforeTextChanged(CharSequence s, int start, int count,
                    int after) {
            }

            @TargetApi(Build.VERSION_CODES.HONEYCOMB)
            public void onTextChanged(CharSequence s, int start, int before,
                    int count) {

                String md5hash = CreateHash(s.toString(), "MD5");
                TextView md5 = (TextView) findViewById(R.id.md5);
                md5.setText(md5hash);
                md5.setTextIsSelectable(true);

                String sha1hash = CreateHash(s.toString(), "SHA-1");
                TextView sha1 = (TextView) findViewById(R.id.sha1);
                sha1.setText(sha1hash);
                sha1.setTextIsSelectable(true);


                String sha256hash = CreateHash(s.toString(), "SHA-256");
                TextView sha256 = (TextView) findViewById(R.id.sha256);
                sha256.setText(sha256hash);
                sha256.setTextIsSelectable(true);

                String sha512hash = CreateHash(s.toString(), "SHA-512");
                TextView sha512 = (TextView) findViewById(R.id.sha512);
                sha512.setText(sha512hash);
                sha512.setTextIsSelectable(true);
            }
        });

    }

    public static String CreateHash(String data, String function) {
        try {
            MessageDigest digest = MessageDigest.getInstance(function);
            byte[] hash = digest.digest(((String) data).getBytes("UTF-8"));
            StringBuffer hexString = new StringBuffer();

            for (int i = 0; i < hash.length; i++) {
                String hex = Integer.toHexString(0xff & hash[i]);
                if (hex.length() == 1)
                    hexString.append('0');
                hexString.append(hex);
            }

            return hexString.toString();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    public void Share() {

        TextView md5 = (TextView) findViewById(R.id.md5);
        md5.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                EditText myTextBox = (EditText) findViewById(R.id.input);
                String md5hash = CreateHash(myTextBox.getText().toString(),
                        "MD5");
                Intent sendIntent = new Intent();
                sendIntent.setAction(Intent.ACTION_SEND);
                sendIntent.putExtra(Intent.EXTRA_TEXT, md5hash);
                sendIntent.setType("text/plain");
                startActivity(sendIntent);

            }
        });

        TextView sha1 = (TextView) findViewById(R.id.sha1);
        sha1.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                EditText myTextBox = (EditText) findViewById(R.id.input);
                String sha1hash = CreateHash(myTextBox.getText().toString(),
                        "SHA-1");
                Intent sendIntent = new Intent();
                sendIntent.setAction(Intent.ACTION_SEND);
                sendIntent.putExtra(Intent.EXTRA_TEXT, sha1hash);
                sendIntent.setType("text/plain");
                startActivity(sendIntent);
            }
        });

        TextView sha256 = (TextView) findViewById(R.id.sha256);
        sha256.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                EditText myTextBox = (EditText) findViewById(R.id.input);
                String sha256hash = CreateHash(myTextBox.getText().toString(),
                        "SHA-256");
                Intent sendIntent = new Intent();
                sendIntent.setAction(Intent.ACTION_SEND);
                sendIntent.putExtra(Intent.EXTRA_TEXT, sha256hash);
                sendIntent.setType("text/plain");
                startActivity(sendIntent);
            }
        });

        TextView sha512 = (TextView) findViewById(R.id.sha512);
        sha512.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                EditText myTextBox = (EditText) findViewById(R.id.input);
                String sha512hash = CreateHash(myTextBox.getText().toString(),
                        "SHA-512");
                Intent sendIntent = new Intent();
                sendIntent.setAction(Intent.ACTION_SEND);
                sendIntent.putExtra(Intent.EXTRA_TEXT, sha512hash);
                sendIntent.setType("text/plain");
                startActivity(sendIntent);
            }
        });

        {
        }
    }


    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    void handleSendText(Intent intent) {
        String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
        if (sharedText != null) {

            EditText input = (EditText) findViewById(R.id.input);
            input.setText(sharedText);

            String md5hash = CreateHash(sharedText, "MD5");
            TextView md5 = (TextView) findViewById(R.id.md5);
            md5.setText(md5hash);
            md5.setTextIsSelectable(true);

            String sha1hash = CreateHash(sharedText, "SHA-1");
            TextView sha1 = (TextView) findViewById(R.id.sha1);
            sha1.setText(sha1hash);
            sha1.setTextIsSelectable(true);


            String sha256hash = CreateHash(sharedText, "SHA-256");
            TextView sha256 = (TextView) findViewById(R.id.sha256);
            sha256.setText(sha256hash);
            sha256.setTextIsSelectable(true);

            String sha512hash = CreateHash(sharedText, "SHA-512");
            TextView sha512 = (TextView) findViewById(R.id.sha512);
            sha512.setText(sha512hash);
            sha512.setTextIsSelectable(true);

        }
    } 
}
\$\endgroup\$
  • 1
    \$\begingroup\$ You should remove // TODO Auto-generated method stub as soon as you put any code in the method. It's just there to help you to find the method. \$\endgroup\$ – abuzittin gillifirca Dec 27 '13 at 7:51
4
\$\begingroup\$

This type of problem is conveniently solved with a Strategy Pattern. But, first things first:

  • you should search for efficient ways to convert bytes to hexadecimal-string values. This is a great solution I like....
  • Unless you have no choice (you are using Patterns/Matchers) you should always use StringBuilder instead of StringBuffer
  • The method CreateHash should not have a capital-letter to start with, it should rather be createHash

As for the Strategy Pattern.... In this case, you can create a class that listens for the text change, and updates the signature in the linked TextView. The same class listens for on-click on the TextView too. The class could have the signature

public abstract class HashDigestDisplay implements TextWatcher, OnClickListener {
    private final TextView view;
    private final MessageDigest digest;

    public HashDigestDisplay (TextView target, String digestName) throws NoSuchAlgorithmException {
        this.view = target;
        this.digest = MessageDigest.getInstance(digestName);
        this.view.setOnClickListener(this);
    }

    public void afterTextChanged(Editable s) {
    }

    public void beforeTextChanged(CharSequence s, int start, int count,
            int after) {
    }

    private String myDigest(String input) {
        digest.reset(); 
        byte[] hash = digest.digest(input.getBytes("UTF-8"));
        return bytesToHex(hash);
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public void onTextChanged(CharSequence s, int start, int before, int count) {
            view.setText(myDigest(s.toString()));
            view.setTextIsSelectable(true);
    }

    @Override
    public void onClick(View v) {
            // TODO Auto-generated method stub
            EditText myTextBox = (EditText) findViewById(R.id.input);
            String hash = myDigest(myTextBox.getText().toString());
            Intent sendIntent = new Intent();
            sendIntent.setAction(Intent.ACTION_SEND);
            sendIntent.putExtra(Intent.EXTRA_TEXT, hash);
            sendIntent.setType("text/plain");
            startActivity(sendIntent);

    }
}

You can see the pattern that is emerging above. Obviously there are issues in the onClick method, but this is from copy/pasting your code.

Now, what you do in your onCreate() setup method is simply:

myTextBox.addTextChangedListener(
    new HashDigestDisplay((TextView) findViewById(R.id.md5), "MD5"));
myTextBox.addTextChangedListener(
    new HashDigestDisplay((TextView) findViewById(R.id.sha1), "SHA-1"));
....

After that, the system should be self-managing.

You only have one copy of the code, and the only things different about it are the name of the Digest and the target of the TextView.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.