728x90

Interface 처리에 대한 사항을 정리차원에서 실 사용 예제에서 발췌하여 적어둔다.

3번 객체에 해당하는 부분은 여러 Class 에서 하나의 개발코드에 접근할 수 있도록 인터페이스 상속 처리를 했다.


1. 인터페이스 선언

public interface ISerialListener {
    void onReceive(int msg, int arg0, int arg1, String arg2, Object arg3);
}



2. SerialConnector 코드 발췌

public class SerialConnector {
    private Context mContext;
    private ISerialListener mListener; // 인터페이스 처리
    private Handler mHandler;
    private SerialMonitorThread mSerialThread;

    public SerialConnector(Context context, ISerialListener listener, Handler handler) {
        mContext = context;
        mListener = listener;
        mHandler = handler;
    }

    public void initialize() {
        List<UsbSerialDriver> availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(sUsbManager);
        if (availableDrivers.isEmpty()) {
            mListener.onReceive(Constants.MSG_SERIAL_ERROR, 0, 0, "Error: There is no available device. \n", null);
            return;
        }

        sDriver = availableDrivers.get(0);
        if(sDriver == null) {
            mListener.onReceive(Constants.MSG_SERIAL_ERROR, 0, 0, "Error: Driver is Null \n", null);
            return;
        }

        try {
            sPort.open(mConnection);
            if(BaudRate.isEmpty()){ // 통신 속도 설정값 가져와서 세팅
                sPort.setParameters(9600, 8, 1, 0);  // baudrate:9600, dataBits:8, stopBits:1, parity:N
            } else {
                sPort.setParameters(Integer.parseInt(BaudRate), Integer.parseInt(DataBit), Integer.parseInt(StopBit), Integer.parseInt(Parity));
            }
        } catch (IOException e) {
            mListener.onReceive(Constants.MSG_SERIAL_ERROR, 0, 0, "Error: Cannot open port \n" + e.toString() + "\n", null);
        } finally {
        }

        startThread();
    }

    public void finalize() {
        try {
            sDriver = null;
            stopThread();

            sPort.close();
            sPort = null;
        } catch(Exception ex) {
            mListener.onReceive(Constants.MSG_SERIAL_ERROR, 0, 0, "Error: Cannot finalize serial connector \n" + ex.toString() + "\n", null);
        }
    }

    /*****************************************************
     *    private methods
     ******************************************************/
    // start thread
    private void startThread() {
        mListener.onReceive(Constants.MSG_SERIAL_ERROR, 0, 0, "Start serial monitoring thread \n", null);
        if(mSerialThread == null) {
            mSerialThread = new SerialMonitorThread();
            mSerialThread.start();
        }
    }
    // stop thread
    private void stopThread() {
        if(mSerialThread != null && mSerialThread.isAlive())
            mSerialThread.interrupt();
        if(mSerialThread != null) {
            mSerialThread = null;
        }
    }

    /*****************************************************
     *    Sub classes, Handler, Listener
     ******************************************************/
    public class SerialMonitorThread extends Thread {
        @Override
        public void run() {
            byte readBuffer[] = new byte[4096];

            while(!Thread.interrupted()) {
                if(sPort != null) {
                    Arrays.fill(readBuffer, (byte)0x00);

                    try {
                        // Read and Display to Terminal
                        int numBytesRead = sPort.read(readBuffer, 1000);
                        if(numBytesRead > 0) {

                            // Print message length
                            Message msg = mHandler.obtainMessage(Constants.MSG_READ_DATA_COUNT, numBytesRead, 0, new String(readBuffer));
                            mHandler.sendMessage(msg);

                        } // End of if(numBytesRead > 0)
                    } catch (IOException e) {
                        Message msg = mHandler.obtainMessage(Constants.MSG_SERIAL_ERROR, 0, 0, "Error # run: " + e.toString() + "\n");
                        mHandler.sendMessage(msg);
                    }
                }

                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break;
                }

            }    // End of while() loop
            finalizeThread();
        }    // End of run()
    }    // End of SerialMonitorThread

}


3. 객체 구현

핵심사항만 발췌하여 유사한 코드 구현시 활용 차원으로 적어둔다.

public class AAA extends AppCompatActivity {
    private static final String TAG = "AAA";
    Context mContext;

    private ActivityHandler mHandler = null;
    private SerialListener mSerialListener = null;
    private SerialConnector mSerialConnector = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tam_ss);
        mContext = AAA.this;
        initView();
    }

    private void initView() {
        connectUsb();
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        connectUsb();
    }

    @Override
    protected void onDestroy() {
        releaseUsb();
        super.onDestroy();
    }

    private void connectUsb() {
        searchEndPoint();
        if (usbInterfaceFound != null) {
            setupUsbComm();
        }
    }

    private void releaseUsb() {
        textStatus.setText("releaseUsb()");
        mSerialConnector.finalize();
    }

    private boolean setupUsbComm() {
        boolean success = false;

        UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
        Boolean permitToRead = manager.hasPermission(deviceFound);

        if (permitToRead) {
            usbDeviceConnection = manager.openDevice(deviceFound);
            if (usbDeviceConnection != null) {
                // Initialize
                mSerialListener = new SerialListener();
                mHandler = new ActivityHandler();

                // Initialize Serial connector and starts Serial monitoring thread.
                mSerialConnector = new SerialConnector(mContext, mSerialListener, mHandler);
                mSerialConnector.initialize();
            }
        } else {
            manager.requestPermission(deviceFound, mPermissionIntent);
            textStatus.setText("Permission: " + permitToRead);
        }
        return success;
    }

    public class SerialListener implements ISerialListener {
        public void onReceive(int msg, int arg0, int arg1, String arg2, Object arg3) {
            switch(msg) {
                case Constants.MSG_DEVICD_INFO:
                    updateReceivedData(arg2);
                    break;
                case Constants.MSG_DEVICE_COUNT:
                    updateReceivedData(Integer.toString(arg0) + " device(s) found \n");
                    break;
                case Constants.MSG_READ_DATA_COUNT:
                    updateReceivedData(Integer.toString(arg0) + " buffer received \n");
                    break;
                case Constants.MSG_READ_DATA:
                    if(arg3 != null) {
                        updateReceivedData((String)arg3);
                    }
                    break;
                case Constants.MSG_SERIAL_ERROR:
                    updateReceivedData(arg2);
                    break;
                case Constants.MSG_FATAL_ERROR_FINISH_APP:
                    finish();
                    break;
            }
        }
    }

    public class ActivityHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch(msg.what) {
                case Constants.MSG_DEVICD_INFO:
                    updateReceivedData((String)msg.obj);
                    break;
                case Constants.MSG_DEVICE_COUNT:
                    updateReceivedData(Integer.toString(msg.arg1) + " device(s) found \n");
                    break;
                case Constants.MSG_READ_DATA_COUNT:
                    updateReceivedData(((String)msg.obj));
                    break;
                case Constants.MSG_READ_DATA:
                    if(msg.obj != null) {
                        updateReceivedData((String)msg.obj);
                    }
                    break;
                case Constants.MSG_INPUT_READ:
                    updateReceivedData((String)msg.obj);
                    mDumpTextView.setTextColor(Color.BLUE);
                    break;
                case Constants.MSG_SERIAL_ERROR:
                    updateReceivedData((String)msg.obj);
                    break;
            }
        }
    }
}


'안드로이드 > Interface' 카테고리의 다른 글

Java Interface 예제  (0) 2019.11.18
Android Interface AsyncTask 예제  (0) 2019.11.05
Java Interface Example  (0) 2019.09.05
Java 인터페이스(interface) 개요  (0) 2019.08.20
Android Interface 예제 ★★★  (0) 2018.08.22
블로그 이미지

Link2Me

,
728x90

이것이 자바다 유투브 강좌에 나온 내용중에서 인터페이스 부분을 정리해서 적어둔다.

https://www.youtube.com/watch?v=UPWiPIROG-k

 

 

인터페이스 선언

- 추상메서드의 집합

- 구현된 것이 전혀 없는 설계도

- 모든 멤버가 public 이라 생략 가능 (메서드는 public abstract, 상수는 public static final 생략 가능)

- 변수, 생성자를 가질 수 없다.

interface 인터페이스이름 {

    public abstract 메서드이름(매개변수목록);

}

 

인터페이스 구현 (→ 미완성 설계도 완성하기)

- 인터페이스에 정의된 추상 메서드를 완성시키는 것

class 클래스이름 implements 인터페이스이름 {

     // 인터페이스에 정의된 추상메서드를 모두 구현해야 한다.

}

- 만약 일부만 구현하는 경우, 클래스 앞에 abstract를 붙여야 한다.

 

특정한 Class 내에서만 사용하는 인터페이스를 정의한 걸 중첩 인터페이스라고 한다.

main 메서드에서 Button 클래스 객체를 생성하고 setOnClickListener() 메소드를 호출할 때 해당 인터페이스를 구현하는 자식 클래스로 값을 넘겨 준다. 그러면 다형성의 효과로 onClick() 메소드가 override한 결과로 나오게 된다.

 

public class Button {
    OnClickListener listener; // 중첩 인터페이스 타입으로 선언
   
    interface OnClickListener {
        void onClick(); // 추상 메소드
    }
   
    void setOnClickListener(OnClickListener listener) {
        this.listener = listener;
        // 외부에서 구현 객체를 받아서 필드에 저장한다.
    }
   
    void touch() {
        listener.onClick();
    }
   
}

import InterfaceEX.Button.OnClickListener;
public class CallListener implements OnClickListener {
    @Override
    public void onClick() {
        System.out.println("전화를 겁니다.");
    }
}

import InterfaceEX.Button.OnClickListener;
public class MessageListener implements OnClickListener {
    @Override
    public void onClick() {
        System.out.println("메시지를 보냅니다.");
    }
}

public class ButtonEx {

    public static void main(String[] args) {

        Button btn = new Button();
       
        btn.setOnClickListener(new CallListener()); // 내부 인터페이스 객체 생성
        btn.touch();
       
        btn.setOnClickListener(new MessageListener());
        btn.touch();

        Button.OnClickListener listener = new Button.OnClickListener() {
            @Override
            public void onClick() {
                System.out.println("사진을 찍습니다.");
            }
        };
        btn.setOnClickListener(listener);
        btn.touch();
       
        btn.setOnClickListener(new Button.OnClickListener() { // 익명 구현 객체
            // 익명 객체는 클래스를 상속하거나 인터페이스를 구현해야만 생성할 수 있다.
            // UI 이벤트 처리 객체나, 쓰레드 객체를 간편하게 생성할 목적으로 주로 사용한다.   
            // 익명 객체는 부모 타입 변수에 대입되므로 부모 타입에 선언된 것만 사용할 수 있다.
            // 외부에서는 익명 객체의 필드와 메소드에 접근할 수 없다.
            @Override // 부모 클래스(Button)의 메소드 재정의
            public void onClick() {
                System.out.println("이미지를 클릭합니다.");
            }
        });
        btn.touch();
    }
}

 

 

아래 코드는 자바의 정석 동영상 강좌를 듣고 구글링 여러 예제를 하나의 파일로 조합하여 작성한 것인다.

 

interface Printable {
    int x=10;
    void print(); // 추상메소드
}
 
interface Drawable {
    void draw(); // 추상메소드
    default void msg(){ // Java 1.8 이상에서 제공
        System.out.println("Drawable default method");
    }
}
 
interface Showable extends Printable {
    // 인터페이스 상속(Inheritance)
    void show(); // 추상메소드
}
 
class Parent {
    public void method2() {
        System.out.println("This is method2() in Parent Class");
    }
}
 
class Child extends Parent implements Printable, Drawable {
    @Override
    public void print() { // 인터페이스(추상 메소드) 구현
        System.out.println("Hello");
    }
 
    @Override
    public void draw() { // 인터페이스(추상 메소드) 구현
        System.out.println("drawing rectangle");
    }
}
 
class CustomDialog {
    // 특정한 Class 내에서만 사용하는 인터페이스를 정의한 걸 중첩 인터페이스라고 한다.
    interface CustomDialogListener {
        void onAgreeButtonClicked(String smsotp); // 추상 메소드
    }
 
    private CustomDialogListener customDialogListener;
    public void setCustomDialogListener(CustomDialogListener listener){
        customDialogListener = listener;
        // 외부에서 구현 객체를 받아서 변수에 저장한다.
    }
 
    String smsotp;
 
    public void Cick(){
        smsotp = "123456";
        customDialogListener.onAgreeButtonClicked(smsotp);
    }
}
 
public class Interface_EX implements Showable {
    @Override
    public void print() {
        System.out.println("print interface method implemented.");
    }
 
    @Override
    public void show() {
        System.out.println("show interface method implemented.");
    }
 
    public static void main(String[] args) {
 
        // 객체  생성 1
        Child child = new Child();
        child.print();
        child.draw();
        child.msg();
        child.method2();
 
        System.out.println(Printable.x);
 
        // 객체  생성 2
        Interface_EX interface_ex = new Interface_EX();
        interface_ex.print();
        interface_ex.show();
 
        // 객체  생성 3
        CustomDialog dialog = new CustomDialog();
        dialog.setCustomDialogListener(new CustomDialog.CustomDialogListener() { // 익명 구현 객체
            // 익명 객체는 클래스를 상속하거나 인터페이스를 구현해야만 생성할 수 있다.
            // 익명 객체는 부모 타입 변수에 대입되므로 부모 타입에 선언된 것만 사용할 수 있다.
            // 외부에서는 익명 객체의 변수와 메소드에 접근할 수 없다.
            @Override
            public void onAgreeButtonClicked(String smsotp) {
                System.out.println("customdialog result : "+smsotp);
            }
        });
        dialog.Cick();
 
    }
}
 

 

 

블로그 이미지

Link2Me

,
728x90

안드로이드 인터페이스 처리하는 걸 많이 다뤄보지 않아서 그런지 인터페이스 사용을 자유롭게 하지 못한다.


"이것이 자바다" 를 유투브에서 인터페이스 강좌를 찾아서 들어보면 설명을 참 잘 해준다.

https://www.youtube.com/watch?v=8GcOYOd67KY


구글 검색으로 블로그에 적혀 있는 내용만으로 손쉽게 인터페이스 처리 코드를 만들줄 알면 고민되지 않겠지만 대게는 단순한 구현 예시만 나와 아직 초보를 탈출하지 못한 나에겐 어렵다.


로그인한 세션 정보를 받아서 다음 단계를 처리해야 하는 어플을 테스트하다보니 인터페이스 부분이 너무 약해서 막힌다.


가장 먼저 인터페이스를 정의한다.

OnCallbackListener.java

public interface OnCallbackListener<T> {
    void onSuccess(T object);
    void onFailure(Exception e);
}
 


두번째 단계는 위 그림에서 개발코드에 해당되는 SessionProcessTask.java 파일을 구현한다.

import android.content.Context;
import android.os.AsyncTask;

public class SessionProcessTask extends AsyncTask<Void, Void, String> {
    private Context mContext;
    private OnCallbackListener<String> mCallBack;
    public Exception mException;


    // 변수를 먼저 선언하고 ALT+ Insert 키를 생성자 생성시 아래와 같은 순서로 생성자 자동 생성 가능

    public SessionProcessTask(Context mContext, OnCallbackListener<String> mCallBack) {
        this.mContext = mContext;
        this.mCallBack = mCallBack;
    }

    @Override
    protected String doInBackground(Void... params) {

        try {
            // 백그라운드 작업할 코드를 여기에서 구현한다.
            return "Welcome to my blog.";

        } catch (Exception e) {
            mException = e;
        }
        return null;
    }

    @Override
    protected void onPostExecute(String result) {
        if (mCallBack != null) {
            if (mException == null) {
                mCallBack.onSuccess(result);
            } else {
                mCallBack.onFailure(mException);
            }
        }
    }
}


객체를 구현할 MainActivity.java 파일의 구현 내용이다.

import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    Context mContext;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = MainActivity.this;

        // 객체 생성
        SessionProcessTask processTask = new SessionProcessTask(mContext, new OnCallbackListener<String>() {
            @Override
            public void onSuccess(String object) {
                Toast.makeText(mContext, "SUCCESS: "+object, Toast.LENGTH_LONG).show();
                ActionActivity android = new ActionActivity(mContext);
                android.btnTouch();
            }

            @Override
            public void onFailure(Exception e) {
                Toast.makeText(mContext, "ERROR: " + e.getMessage(), Toast.LENGTH_LONG).show();
            }
        });
        processTask.execute();
    }

}


onSuccess 결과를 받으면 후속으로 

ActionActivity android = new ActionActivity(mContext);

android.btnTouch();

를 실행하도록 했다.


이제 이와 관련된 코드를 또다른 인터페이스를 통해 처리되도록 구현했다.

// OnLoadListener.java 파일

public interface OnLoadListener { 
    public void onLoadFinish();
}

// ImageLoader.java 파일

import android.content.Context;
import android.widget.Toast;

public class ImageLoader {
    private Context mContext;
    private OnLoadListener loadListener;

    public ImageLoader(Context context, OnLoadListener loadListener) {
        mContext = context;
        this.loadListener = loadListener;
    }

    public void start(){
        try {
            System.out.println("이미지를 로딩합니다.");
            Toast.makeText(mContext, "이미지를 로딩합니다.", Toast.LENGTH_LONG).show();
            Thread.sleep(1000);
            loadListener.onLoadFinish();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

// ActionActivity.java 파일

import android.content.Context;
import android.widget.Toast;

public class ActionActivity implements OnLoadListener {
    private Context mContext;

    public ActionActivity(Context mContext) {
        this.mContext = mContext;
    }

    public void btnTouch(){
        ImageLoader imageLoader = new ImageLoader(mContext,this);
        imageLoader.start();
    }

    @Override
    public void onLoadFinish() {
        Toast.makeText(mContext, "토스트 팝업을 띄웁니다.", Toast.LENGTH_LONG).show();
        System.out.println("토스트 팝업을 띄웁니다.");
    }
}


Log 메시지를 통해서 확인할 수도 있지만, Toast 메시지 창을 띄워서 순차적으로 실행되는 결과를 확인할 수 있게 했다.

아직 응용력이 떨어지는 나를 위해 테스트하고 적어둔다.

구글링하다가 발견한 좋은 글이 와 닿는다.

인터넷에서 짜집기한 것만 읽지 말고, 책을 읽어라. 같은 책을 여러 번 읽어라. 꾸준히 해라.

하지만, 요즈음에는 "유투브 강좌를 열심히 봐라" 라고 하는게 더 맞을 거 같다.

좋은 강좌들이 너무 많이 오픈되어 있다.


테스트에 사용한 코드

Interface_src.zip


'안드로이드 > Interface' 카테고리의 다른 글

Android 인터페이스 상속 ISerialListener 예제  (0) 2019.12.12
Java Interface 예제  (0) 2019.11.18
Java Interface Example  (0) 2019.09.05
Java 인터페이스(interface) 개요  (0) 2019.08.20
Android Interface 예제 ★★★  (0) 2018.08.22
블로그 이미지

Link2Me

,
728x90

유투브 강좌를 보고 따라서 코드 적어가며 테스트하고 적어둔다.

유투브 동영상 : https://www.youtube.com/watch?v=OTNuxe_ihtM&t=774s

 

 

각각 서로 다른 파일로 생성하여 테스트 해야 하는데 하나의 파일로 작성하여 테스트했다.

- 인터페이스 타입의 변수로 인터페이스를 구현한 클래스의 인스턴스를 참조할 수 있다.

- 인터페이스를 메소드의 매개변수 타입으로 지정할 수 있다.

interface OnFoundListener {
    // 1. Create a callback interface.
    void onFound(String result);
}
 
class ClassA {
    // 2. Create a class as a worker.
    public void findAGirl(OnFoundListener onFoundListener ) {
        for(int i=0; i < 5; i++) {
            try {
                Thread.sleep(100);
                System.out.println("A is trying find a girl for you " + i);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        onFoundListener.onFound("A found a girl for you.");
        // A found nothing, so that assign this job for B.
        //ClassB classB = new ClassB();
        //classB.findACuteGirl(onFoundListener);
    }
 
}
 
public class InerfaceWorld {
    public static void main(String[] args) {
        ClassA classA = new ClassA();
        classA.findAGirl(new OnFoundListener() {
            @Override
            public void onFound(String result) {
                System.out.println(result);
            }
        });
    }
}
 

메소드를 호출하는 쪽에서는 메소드의 내용에 관계없이 선언부만 알면 되기 때문에 이를 이용하여 프로그램을 작성할 수 있다. 동시에 다른 한 쪽에서는 인터페이스를 구현하는 클래스를 작성하도록 하여, 인터페이스를 구현하는 클래스가 작성될 때까지 기다리지 않고도 양쪽에서 동시에 개발을 진행할 수 있다.

 

 

 

 

 

interface OnFoundListener {
    // 1. Create a callback interface.
    void onFound(String result);
}
 
class ClassA {
    // 2. Create a class as a worker.
    public void findAGirl(OnFoundListener onFoundListener ) {
        for(int i=0; i < 5; i++) {
            try {
                Thread.sleep(100);
                System.out.println("A is trying find a girl for you " + i);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //onFoundListener.onFound("A found a girl for you.");
        // A found nothing, so that assign this job for B.
        ClassB classB = new ClassB();
        classB.findACuteGirl(onFoundListener);
    }
}
 
class ClassB {
    public void findACuteGirl(OnFoundListener onFoundListener ) {
        for(int i=0; i < 5; i++) {
            try {
                Thread.sleep(100);
                //System.out.println("A is trying find a girl for you " + i);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        onFoundListener.onFound("A found a cute girl for you.");
    }
}
 
public class InterfaceWorld2 {
    public static void main(String[] args) {
        ClassA classA = new ClassA();
        classA.findAGirl(new OnFoundListener() {
            @Override
            public void onFound(String result) {
                System.out.println(result);
            }
        });
    }
}
 
 

 

 

'안드로이드 > Interface' 카테고리의 다른 글

Java Interface 예제  (0) 2019.11.18
Android Interface AsyncTask 예제  (0) 2019.11.05
Java 인터페이스(interface) 개요  (0) 2019.08.20
Android Interface 예제 ★★★  (0) 2018.08.22
Android Interface 예제 1  (0) 2018.08.20
블로그 이미지

Link2Me

,
728x90

Java는 다중상속을 지원하지 않는다. (C++은 다중 상속을 지원한다.)

두 조상으로부터 상속받는 멤버 중에서 멤버변수의 이름이 같거나 메서드의 선언부가 일치하고 구현 내용이 다르다면 이 두 조상으로부터 상속받는 자손클래스는 어느 조상의 것을 상속받게 되는 것인지 알 수 없다. 어느 한 쪽으로부터의 상속을 포기하던가, 이름이 충돌하지 않도록 조상클래스를 변경하는 수 밖에는 없다.
자바에서는 이러한 충돌문제를 해결하기 위해서 단일 상속만을 허용하고, 인터페이스를 이용해서 단일 상속의 단점을 보완하도록 하였다.

 

Java 인터페이스
- 인터페이스는 추상메서드, 상수 만을 가질 수 있으며, 이를 직접 구현하지 않는다.
- 인터페이스는 필드(변수)를 포함할 수 없다.
- 정의부분만 표현하고, 구현 부분은 상속받은 클래스에서 구현한다. (구현이라 함은 {}가 포함된 거)
- 클래스가 인터페이스를 가지는 경우 해당 인터페이스의 모든 멤버에 대한 구현(implementation)을 제공해야 한다.
- 여러개의 인터페이스를 부모로 둘 수 있다. (다중 상속 가능)
- 인터페이스로 객체를 생성할 수는 없다.
- 접근 제어자로 public 또는 default를 사용한다. (private 접근제한자는 사용할 수 없다.)
- 모든 멤버 변수는 public static final 이어야 하며, 이를 생략할 수 있다.
- 모든 메서드는 public abstract 이어야 하며, 이를 생략할 수 있다.

- 인터페이스의 구현은 extends가 아닌 implements를 사용한다.

- 인터페이스는 둘 이상을 동시에 구현 가능하다.(다중 상속 효과)

- 인터페이스간 상속이 가능한데 이때는 extends를 사용한다.

 

Android에서는 한 프로세스가 다른 프로세스의 메모리에 정상적으로 액세스할 수 없다.

 

interface 인터페이스이름 {
      public static final 타입 상수이름 = 값;
      public abstract 메서드이름(매개변수목록);
}



- interface 내에 선언된 변수는 public static final 로 선언되고 이를 생략할 수 있다.
- interface 내에 선언된 메소드는 public abstract 로 선언되고 이를 생략할 수 있다.
- interface 도 참조변수 선언 가능하고, 메소드 오버라이딩 원칙도 그대로 적용된다.

 

인터페이스에 정의된 모든 멤버 변수는 예외없이 적용되는 사항이기 때문에 제어자를 생략할 수 있는 것이며, 편의상 생략하는 경우가 많다. 생략된 제어자는 컴파일 시에 컴파일러가 자동으로 추가해준다.
 
 

예제

 

import java.util.Scanner;
 
interface IEmployee {
    // 멤버 앞에 접근제한자 생략 가능
    // 컴파일러에 의해 public abstract 가 붙음
    String getName();
    void setName(String n);
    int getCounter();
}
 
class Staff implements IEmployee {
 
    private String name;
    private int counter;
    public static int NOofEmployees;
 
    public Staff() { // 생성자
        counter = ++counter + NOofEmployees;
    }
 
    @Override
    public String getName() {
        return name;
    }
 
    @Override
    public void setName(String name) {
        this.name = name;
    }
 
    @Override
    public int getCounter() {
        return counter;
    }
}
 
public class IEmployeeEx {
    private static Scanner kb;
 
    public static void main(String[] args) {
        String name;
        kb = new Scanner(System.in);
        System.out.print("직원 수 입력: ");
        Staff.NOofEmployees = Integer.parseInt(kb.next());
 
        Staff my = new Staff();
        System.out.print("신입 직원의 이름을 입력하세요: ");
        name = kb.next();
        my.setName(name);
 
        System.out.println("▷ 직원 정보 ◁");
        System.out.println(String.format("직원 번호 : %d, 직원이름 : %s", my.getCounter(),my.getName()));
 
    }
}
 
 

 

본 예제는 C# 강의를 들으면서 정리한 예제를 Java 로 구현한 것이다.

인터페이스에 대한 개념 이해가 부족해서 Android 에서 인터페이스 구현을 쉽게 못했는데 이제는 할 수 있을 거 같다.

C# 인터페이스 예제와 비교해서 보면 좀 더 이해가 빠를 수도 있다.

좀 더 심도있는 것은 구현해보면서 예제를 추가해볼 생각이다.

 

참고하면 좋은 자료

https://blog.naver.com/sensate1024/221232506713

 

블로그 이미지

Link2Me

,
728x90



안드로이드 스튜디오에서 Interface CallbackEvent를 생성하고 나서 EventRegistration Class 에서 CallbackEvent  변수를 선언하고 생성자 만들기를 하면 자동으로 생성자가 만들어지는 걸 볼 수 있다.


public interface CallbackEvent {
    // 1 Step 인터페이스 정의
    public void callbackMethod();
}

 public class EventRegistration {
    // 2 Step 변수 선언
    CallbackEvent callbackEvent;

    // 3 Step 생성자 생성
    public EventRegistration(CallbackEvent callbackEvent) {
        System.out.println("2. EventRegistration Constructor");
        this.callbackEvent = callbackEvent;
    }

    public void doWork(){
        System.out.println("4. doWork 메소드");
        callbackEvent.callbackMethod();
    }
}

 public class MainActivity extends AppCompatActivity {

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

        System.out.println("1. MainActivity");
        CallbackEvent callbackEvent = new CallbackEvent() {
            @Override
            public void callbackMethod() {
                System.out.println("5. call callback method from callee");
            }
        };

        EventRegistration eventRegistration = new EventRegistration(callbackEvent);
        System.out.println("3. eventRegistration.doWork()");
        eventRegistration.doWork();
    }
}


생성자 생성과 동시에 EventRegistration(CallbackEvent callbackEvent) 를 지정하는 방법과

별도 setCallbackEvent(CallbackEvent callbackEvent) 를 하는 방법으로 구분해서 해보고 있다.


public interface CallbackEvent {
    // 1 Step 인터페이스 정의
    public void callbackMethod();
}

 public class EventRegistration {
    Context mContext;
    // 2 Step 변수 선언
    CallbackEvent callbackEvent;

    // 3 Step 생성자 선언
    public EventRegistration(Context context) {
        System.out.println("3. EventRegistration Constructor");
        mContext = context;
    }

    // 4 Step CallbackEvent Set
    public void setCallbackEvent(CallbackEvent callbackEvent){
        System.out.println("5. setCallbackEvent");
        this.callbackEvent = callbackEvent;
    }

    public void doWork(){
        System.out.println("7. doWork 메소드 응답");
        callbackEvent.callbackMethod();
    }
}

 public class MainActivity extends AppCompatActivity {
    Context context;

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

        System.out.println("1. MainActivity 실행");

        System.out.println("2. EventRegistration 생성자 호출");
        EventRegistration eventRegistration = new EventRegistration(context);

        System.out.println("4. setCallbackEvent 연동");
        eventRegistration.setCallbackEvent(new CallbackEvent() {
            @Override
            public void callbackMethod() {
                System.out.println("8. call callback method from callee");
            }
        });

        System.out.println("6. eventRegistration.doWork() 실행");
        eventRegistration.doWork();
    }
}


예제3.

안드로이드에서 보편적으로 사용되는 예제이다.

public interface CallbackEvent {
    void callbackMethod();
}

import android.content.Context;

public class NewClass {
    private Context mContext;
    private CallbackEvent callbackEvent;

    public NewClass(Context mContext) {
        System.out.println("2. NewClass Constructor");
        this.mContext = mContext;
    }

    public void setCallbackEvent(CallbackEvent callbackEvent){
        System.out.println("3. setCallbackEvent");
        this.callbackEvent = callbackEvent;
    }

    public void doWork(){
        //Do somthing...

        //call back main
        callbackEvent.callbackMethod();
        System.out.println("5. doWork 메소드 응답");
    }
}

import android.content.Context;
import android.os.Bundle;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity implements CallbackEvent {
    Context mContext;
    NewClass newClass;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = MainActivity.this;
        System.out.println("1. MainActivity 실행");
        doSomething();
    }

    private void doSomething(){
        newClass = new NewClass(mContext);
        newClass.setCallbackEvent(this);
        newClass.doWork();
        System.out.println("6. newClass.doWork()");
    }

    @Override
    public void callbackMethod() {
        System.out.println("4. callbackMethod from callee.");
    }
}



블로그 이미지

Link2Me

,
728x90

초급 단계를 벗어나고자 Interface 에 대해 공부하고 있는데 생각만큼 이해가 잘 안된다.



https://guides.codepath.com/android/Creating-Custom-Listeners 를 보고 테스트 해본 걸 적어둔다.


import android.view.View;

class MyCustomObject {
    // Step 1 - 인터페이스 정의
    public interface MyCustomObjectListener {
        // These methods are the different events and
        // need to pass relevant arguments related to the event triggered
        public void onObjectReady(String title);
        // or when data has been loaded
        void onItemClick(View view, int position);
    }

    // Step 2 - This variable represents the listener passed in by the owning object
    // The listener must implement the events interface and passes messages up to the parent.
    private MyCustomObjectListener listener;

    // Constructor where listener events are ignored
    public MyCustomObject() {
        // set null or default listener or accept as argument to constructor
        this.listener = null;
    }

    // Step 3 - Assign the listener implementing events interface that will receive the events
    public void setCustomObjectListner(MyCustomObjectListener listner){
        this.listener = listner;
    }
}


import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;

public class MyParentActivity extends AppCompatActivity {

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

        // Create the custom object
        MyCustomObject childObject = new MyCustomObject();

        // Step 4 - Setup the listener for this object
        childObject.setCustomObjectListner(new MyCustomObject.MyCustomObjectListener() {
            @Override
            public void onObjectReady(String title) {

            }

            @Override
            public void onItemClick(View view, int position) {

            }

        });
    }
}




Recyclerview 에서 Apdater를 만들어서 Interface 를 통해 데이터를 주고 받은 걸 해보고 싶은데 이해를 못한 부분이 있는지 예제를 보고 따라해보고 막상 적용해보려고 하면 막힌다.


public void setOnItemClickListener(OnItemClickListener listener){
   this.listener = listener;
}

를 통해서 데이터를 주고 받은 걸 해보고 싶은데 전혀 동작이 안된다.


생성자에 값을 넘겨서 처리하면 동작되는데 분리해서 접근하면 안되네.

뭔가 가능한 방법이 있을 거 같은데 실력이 미천해서 완벽한 해결을 못하고 Inner Class 로 처리를 하고 있다.

아래와 같이 생성자를 통해서 값을 넘기면 원하는 결과를 얻을 수는 있다.


public class StaffListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>  {
    public interface OnItemClickListener {
        void onItemClick(View view, int position);
    }

    public OnItemClickListener listener;

    public StaffListAdapter(Context mContext, ArrayList<Group_Item> items, OnItemClickListener listener) {
        this.mContext = mContext;
        IvList = items;
        this.listener = listener;
    }

}

public class StaffList extends AppCompatActivity {
    Context context;
    private ArrayList<Group_Item> staffItemList = new ArrayList<>();
    RecyclerView.Adapter staffListAdapter;

    staffListAdapter = new StaffListAdapter(this, staffItemList, new StaffListAdapter.OnItemClickListener() {
        @Override
        public void onItemClick(View view, int position) {
            if(staffItemList.get(position).getIsFolder().equals("1")){
            } else if(staffItemList.get(position).getIsFolder().equals("0")){
            }
        }
    });
    listView.setAdapter(staffListAdapter); // 어댑터를 리스트뷰에 세팅
}

블로그 이미지

Link2Me

,
728x90

RecyclerView Adapter 를 별도 Adapter 파일로 만들어서 Activity 간 데이터 처리를 해보고 기록해둔다.

그동안 Inner Class 로 하나의 Activity 내에서 처리하는 것만 해봤는데 Activity간 처리하는 것이라 고려할 사항이 좀 된다.


RecyclerView 는 android.support.v7.widget.CardView 와 같이 사용하면 깔끔한 화면을 볼 수 있다.

또한, view 를 두개 이상 선택적으로 보여주는 것도 편하더라.

Intent 로 화면 전환 처리하는 걸 ContentAdapter 에서 처리하는 걸 문제없이 처리하기 위해 구글링으로 여러 자료를 참조하고 완성된 결과를 얻었다.


두 파일간에 Interface 를 통해 처리를 한다.

OnItemClickListene 를 인터페이스라고 하며 class 가 아닌 interface 라는 키워드를 이용하여 작성한다.

onItemClick함수를 인터페이스 함수라고 한다.

public interface OnItemClickListener { // Class 처럼 상속받아올 인터페이스명
    void onItemClick(View v, int position); // 추상 메소드명
}


자바의 인터페이스 개념 이해를 위해서 구글링을 해보니 기본적인 Interface 개념만 나온다.

안드로이드 인터페이스 예제로 검색해야 원하는 걸 얻을 수 있다.

http://yujuwon.tistory.com/entry/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A6%AC%EC%8A%A4%EB%84%88-%EB%A7%8C%EB%93%A4%EA%B8%B0

http://codeasy.tistory.com/2?category=751348


안드로이드 인터페이스 구성요소 : https://kairo96.gitbooks.io/android/content/ch3.1.html 참조


안드로이드 Interface 를 사용한 예제 중에서 https://gist.github.com/riyazMuhammad/1c7b1f9fa3065aa5a46f 를 참조하면 도움된다. 단, mViewHolder.getPosition() 는 테스트해보니 deprecated 되었다고 동작이 되지 않는다.

position 은 getAdapterPosition() 로 넘기면 정상적으로 원하는 결과를 얻을 수 있다.


본 게시글에서는 Content_Item.java, XML 파일은 모두 생략되어 있으니 구현 로직만 참고하면 많은 도움된다.


Custom View 또는 RecyclerView

public class ContentAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>  {
    private static final int TYPE_ONE = 1;
    private static final int TYPE_TWO = 2;
    Context mContext;
    private ArrayList<Content_Item> IvList;
    Content_Item cItem;
    private OnItemClickListener listener; // 이벤트 리스너를 변수로 선언

    public interface OnItemClickListener { // 인터페이스 정의
        void onItemClick(View v, int position);
    }

    public ContentAdapter(Context mContext, ArrayList<Content_Item> items, OnItemClickListener mOnClickListener) {
        this.mContext = mContext;
        IvList = items;
        this.listener = mOnClickListener;
    }

    // determine which layout to use for the row
    @Override
    public int getItemViewType(int position) {
        Content_Item item = IvList.get(position);
        if (item.getIsFolder().equals("1")) {
            return TYPE_ONE;
        } else if (item.getIsFolder().equals("0")) {
            return TYPE_TWO;
        } else {
            return -1;
        }
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // 새로운 뷰를 만든다.
        if (viewType == TYPE_ONE) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.group_item, parent, false);
            return new ViewHolder1(view);
        } else if (viewType == TYPE_TWO) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.person_item, parent, false);
            return new ViewHolder2(view);
        } else {
            throw new RuntimeException("The type has to be ONE or TWO");
        }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        // ListView의 getView 부분을 담당하는 메소드
        switch (holder.getItemViewType()) {
            case TYPE_ONE:
                ((ViewHolder1) holder).bind(IvList.get(position), listener);
                break;
            case TYPE_TWO:
                ((ViewHolder2) holder).bind(IvList.get(position), listener);
                break;
            default:
                break;
        }
    }

    @Override
    public int getItemCount() {
        return IvList.size(); // 데이터 개수 리턴
    }

    public class ViewHolder1 extends RecyclerView.ViewHolder {
        public ImageView mImage;
        public TextView mTitle;

        public ViewHolder1(View itemView) {
            super(itemView);
            // 화면에 표시될 View 로부터 위젯에 대한 참조 획득
            mImage = (ImageView) itemView.findViewById(R.id.cell_image);
            mTitle = (TextView) itemView.findViewById(R.id.cell_text);
        }

        public void bind(Content_Item item, final OnItemClickListener listener) {
            cItem = item;
            if(cItem.getIsFolder().equals("1")){
                // 아이템 내 각 위젯에 데이터 반영
                mImage.setImageResource(R.drawable.group_btn);
                mTitle.setText(cItem.getName());
                itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        listener.onItemClick(view,getAdapterPosition());
                    }
                });
            }
        }

    }

    public class ViewHolder2 extends RecyclerView.ViewHolder {
        public ImageView mImage;
        public TextView mTitle;
        public TextView msubTitle1;
        public TextView msubTitle2;

        public ViewHolder2(View itemView) {
            super(itemView);
            mImage = (ImageView) itemView.findViewById(R.id.cell_image);
            mTitle = (TextView) itemView.findViewById(R.id.cell_text);
            msubTitle1 = (TextView) itemView.findViewById(R.id.cell_text_sub1);
            msubTitle2 = (TextView) itemView.findViewById(R.id.cell_text_sub2);
        }

        public void bind(Content_Item item, final OnItemClickListener listener) {
            cItem = item;
            if(cItem.getIsFolder().equals("0")){
                // 아이템 내 각 위젯에 데이터 반영
                String imageUri = cItem.getPhoto();
                if (imageUri.equals("")) {
                    mImage.setImageBitmap(R.drawable.photo_base);
                } else {
                    Glide.with(itemView.getContext()).load(imageUri).into(mImage);
                }
                mTitle.setText(cItem.getName());
                msubTitle1.setText(cItem.getCode());
                msubTitle2.setText(cItem.getPosition());

                itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        listener.onItemClick(view,getAdapterPosition());
                    }
                });
            }
        }
    }
}

public class RecyclerviewList extends AppCompatActivity implements View.OnClickListener {
    Context context;

    private RecyclerView listView; // 리스트뷰
    private ArrayList<Content_Item> cItemList = new ArrayList<>();
    RecyclerView.Adapter contentListAdapter;
    RecyclerView.LayoutManager layoutManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.orglistview);
        context = this.getBaseContext();

        // Adapter에 추가 데이터를 저장하기 위한 ArrayList
        listView = (RecyclerView) findViewById(R.id.recyclerview);
        listView.setHasFixedSize(true);
        // Set Layout Manager
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        listView.setLayoutManager(layoutManager);

        contentListAdapter = new ContentAdapter(getApplicationContext(),cItemList, new ContentAdapter.OnItemClickListener(){

            @Override
            public void onItemClick(View v, int position) {
                if(cItemList.get(position).getIsFolder().equals("1")){
                    Toast.makeText(context, "Item Clicked" + position, Toast.LENGTH_LONG).show();
                } else if(cItemList.get(position).getIsFolder().equals("0")){
                    Intent intent = new Intent(RecyclerviewList.this, StaffView.class);
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
                    intent.putExtra("idx", cItemList.get(position).getIdx());
                    intent.putExtra("title", cItemList.get(position).getName());
                    startActivity(intent);
                }
            }
        }); // Adapter 생성
        listView.setAdapter(contentListAdapter); // 어댑터를 리스트뷰에 세팅

        // 서버에서 데이터 가져오기
        getJSONData();
    }

}


검색으로 찾은 자료들이 대부분 개념만 설명되어 완성된 결과를 얻을 수가 없어 삽질을 한참 했다.

'안드로이드 > Interface' 카테고리의 다른 글

Android Interface AsyncTask 예제  (0) 2019.11.05
Java Interface Example  (0) 2019.09.05
Java 인터페이스(interface) 개요  (0) 2019.08.20
Android Interface 예제 ★★★  (0) 2018.08.22
Android Interface 예제 1  (0) 2018.08.20
블로그 이미지

Link2Me

,