안드로이드

1 2 3 4 5

'DatagramSocket'을 사용하여 UDP 브로드캐스트 메시지를 수신할 수 있습니다.

DatagramSocket 포트는 송신하는 쪽 포트를 적어주시면 됩니다. 

 

 

  •  AndroidManifest에서 인터넷 사용 권한을 추가.
<uses-permission android:name="android.permission.INTERNET" />

 

  • UdpBroadcastReceiver를 생성하여 메시지를 수신받는 쓰레드를 생성.
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

public class UdpBroadcastReceiver extends Thread {
    private boolean running;
    private DatagramSocket socket;
    private byte[] buf = new byte[256];

    public UdpBroadcastReceiver() {
        try {
            socket = new DatagramSocket(4445); // 4445 포트에서 수신
            socket.setBroadcast(true);
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }

    public void run() {
        running = true;

        while (running) {
            try {
                DatagramPacket packet = new DatagramPacket(buf, buf.length);
                socket.receive(packet);

                InetAddress address = packet.getAddress();
                int port = packet.getPort();
                packet = new DatagramPacket(buf, buf.length, address, port);
                String received = new String(packet.getData(), 0, packet.getLength());

                // 수신된 메시지 처리
                Log.d("UdpBroadcastReceiver", "Received Message: " + received);

                if (received.equals("end")) {
                    running = false;
                    continue;
                }
            } catch (Exception e) {
                e.printStackTrace();
                running = false;
            }
        }
        socket.close();
    }
}

 

  • 메인에서 해당 쓰레드 실행.
UdpBroadcastReceiver receiver = new UdpBroadcastReceiver();
receiver.start();

 

 

 

 

 

 


수신받은 데이터를 메인에서 처리하려면 콜백 인터페이스를 사용하여 쓰레드가 완료했을 때 콜백을 통해 결과를 전달받을 수 있습니다.

 

  • 콜백 인터페이스 정의.
public interface ThreadCompleteListener {
    void onThreadComplete(final String result);
}

 

  • 쓰레드 수정.

쓰레드 작업 완료 시, 콜백 메서드를 호출할 수 있도록 설정.

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

public class UdpBroadcastReceiver extends Thread {
    private ThreadCompleteListener listener;
    private boolean running;
    private DatagramSocket socket;
    private byte[] buf = new byte[256];

    public UdpBroadcastReceiver(ThreadCompleteListener listener) {
        try {
            socket = new DatagramSocket(4445); // 4445 포트에서 수신
            socket.setBroadcast(true);
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }

    public void run() {
        running = true;

        while (running) {
            try {
                DatagramPacket packet = new DatagramPacket(buf, buf.length);
                socket.receive(packet);

                InetAddress address = packet.getAddress();
                int port = packet.getPort();
                packet = new DatagramPacket(buf, buf.length, address, port);
                String received = new String(packet.getData(), 0, packet.getLength());

                // 수신된 메시지 처리
                Log.d("UdpBroadcastReceiver", "Received Message: " + received);

                if (received.equals("end")) {
                    running = false;
                    continue;
                }
            } catch (Exception e) {
                e.printStackTrace();
                running = false;
            }
        }
        socket.close();
    }
}

 

  • 메인에서 쓰레드 호출 수정.
UdpBroadcastReceiver receiver = new UdpBroadcastReceiver(this);
receiver.start();

 

  • 메인에서 onThreadComplete으로 쓰레드 결과 처리.

implements 추가

public class MainActivity extends AppCompatActivity implements ThreadCompleteListener {

 

onThreadComplete

@Override
    public void onThreadComplete(String result) {
        // 스레드 결과 처리.
        
        runOnUiThread(() -> {
        	// UI수정할 경우 runOnUiThread 사용.
        });
    }

 



IntentFilter를 생성시켜주고, 원하는 액션을 intentFilter에 등록시켜줍니다.

그런다음 BroadcastReceiver를 생성하여 onReceive 안에 다음과 같이 작성해주시면 됩니다.

화면꺼짐(ACTION_SCREEN_OFF)을 예로 했는데 화면켜짐(ACTION_SCREEN_ON)을 사용하시려면

intentFilter에 화면켜짐을 등록하시고 조건문을 통해서 사용해주시면 됩니다.

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
BroadcastReceiver receiver = new BroadcastReceiver() {
	@Override
    public void onReceive(Context context, Intent intent) {
    	if(intent.getAction().equals(Intent.ACTION_SCREEN_OFF)){
    		// 원하는 코드작성
    	}
    }
};
registerReceiver(receiver, intentFilter);​

[Android] 인앱업데이트

2021. 5. 12. 10:20

1. implementation 추가

implementation 'com.google.android.play:core:1.10.0'

 

2. 인앱업데이트 메서드 추가

클래스 내부에 해당 메서드를 추가시켜주시고 onCreate()에서 호출해주시면

앱을 실행했을 때 상위버전이 존재하면 인앤업데이트 화면이 켜지게 됩니다.

아래 메서드에서 AppUpdateType.IMMEDIATE를 이용해서 앱을 강제로 업데이트가 가능합니다.

(강제 업데이트 외에 권장 업데이트 방법도 있습니다.)

인앱업데이트 확인방법은 베타테스트를 이용해서 확인하시면 됩니다.

// 인앱 강제 업데이트
private void updaterequest() {
    AppUpdateManager appUpdateManager = AppUpdateManagerFactory.create(getApplicationContext());
    Task<AppUpdateInfo> appUpdateInfoTask = appUpdateManager.getAppUpdateInfo();

    appUpdateInfoTask.addOnSuccessListener(appUpdateInfo -> {
        if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
                && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
            Log.d("WTF", "updaterequest:업데이트할 수 있음 ");
            try {
                appUpdateManager.startUpdateFlowForResult(
                        appUpdateInfo,
                        AppUpdateType.IMMEDIATE,
                        this,
                        UPDATE_REQUEST_CODE);
                Log.d("WTF", "updaterequest:업데이트 요청함 ");
            } catch (IntentSender.SendIntentException e) {
                e.printStackTrace();
            }
        }else{
            Log.d("WTF", "updaterequest:업데이트할 것이 없음 ");
        }
    });
}

 



앱 다시 실행하기


설정이 바뀌거나 기타 여러가지 경우에 앱을 다시 실행해야할 때가 있습니다.

public void restart(){
    Intent intent = getBaseContext().getPackageManager().
            getLaunchIntentForPackage(getBaseContext().getPackageName());
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(intent);
    getActivity().finishAffinity();
}

FLAG_ACTIVITY_CLEAR_TASK와 FLAG_ACTIVITY_NEW_TASK를 함께 사용하면

백그라운드에 남지 않고 다시 시작됩니다.

 

 



URL 유효성 체크(마켓에 유효한 앱인지 확인)


안드로이드 제작 중에 마켓에 등록되지 않은 앱을 intent를 통해 이동하게 되면

무한로딩이 걸리게 됩니다.

이런 예외처리를 어떻게 할지 생각해봤는데, URL 유효성 체크를 통해 유효한 페이지인지 확인하고

유효하지 않으면 조건문을 통해 걸러내도록 했습니다.

 

// 마켓에 앱 존재여부 확인
public static boolean checkAvailUrl(String url){
        boolean check = false;

        try{
            URL tempUrl  = new URL(url);
            HttpURLConnection connection = (HttpURLConnection)tempUrl.openConnection();
            connection.setRequestMethod("GET");
            connection.connect();

            if(200 == connection.getResponseCode()) check = true;
        }catch(IOException e){
            return false;
        }
        return check;
}

위 코드를 사용하면 마켓에 존재하지 않는 앱은 false를 리턴받아 처리할 수 있게 됩니다.

네트워크에 접속하게 되는데 바로 접속하게 되면 android.os.NetworkOnMainThreadException 에러가 발생합니다.

이를 해결하기 위해서는 Thread를 이용하시면 됩니다.

 

Thread workingThread = new Thread(() -> {
	isAppStoreAvail = checkAvailUrl(
	"https://play.google.com/store/apps/details?id=패키지명");
});
        
workingThread.start();

try {
	workingThread.join();
} catch (InterruptedException e) {
	e.printStackTrace();
}

if (isAppStoreAvail) {
	// 구글플레이에 해당 앱이 있을 경우
}

이런식으로 Thread에 넣어서 정상적으로 작동이 됩니다.

그냥 new Thread(() -> { }).start(); 를 사용해도 되지만 그럴 경우 Thread가 끝나기 전에 이미 다른 코드가 실행되기 때문에 Thread가 다 끝나고 다음코드가 진행될 수 있도록 join()을 사용해주시면 됩니다.



Handler mHandler = new Handler(Looper.getMainLooper());

 

mHandler.postDelayed((Runnable) () -> /*원하는 작업*/), /*시간*/);

Hanlder postDelayed를 이용해서 원하는 시간이 지난 후 실행이 되도록 설정이 가능합니다.

뒤에 딜레이 시간을 입력하면 됩니다. 1초는 1000으로 입력하시면 됩니다.

 

여러 개의 뷰에 동시에 사용할 경우에는 딜레이 시간이 다른 뷰에 간섭이 생길 수 있으므로

mHandler.removeMessages(0);

or

mHandler.removeCallbacksAndMessages(null);

이와 같이 초기화 해주시면 됩니다.



view.getResources().getResourceEntryName(view.getId())

getResourceEntryName을 이용해 위 코드를 사용하면

R.id.xxxx 에서 xxxx값만 가져올 수 있습니다.

 

 

 

 

 



EditText 천단위 콤마(,)설정하기

 


EditText를 작성할 때, TextWatcher를 이용해 천단위마다 콤마(,)를 찍을 수 있습니다.

여러 개의 EditText에 콤마(,) 설정을 하기위해서는 콤마설정을 하는 커스텀을 만들어주면 됩니다.

 

CustomTextWathcer 클래스

public class CustomTextWatcher implements TextWatcher {

    private EditText editText;
    String strAmount = "";

    CustomTextWatcher(EditText et) {
        editText = et;
    }

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

    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        if(!TextUtils.isEmpty(s.toString()) && !s.toString().equals(strAmount)) {
            strAmount = makeStringComma(s.toString().replace(",", ""));
            editText.setText(strAmount);
            Editable editable = editText.getText();
            Selection.setSelection(editable, strAmount.length());
        }
    }

    @Override
    public void afterTextChanged(Editable s) {

    }

    protected String makeStringComma(String str) {    // 천단위 콤마설정.
        if (str.length() == 0) {
            return "";
        }
        long value = Long.parseLong(str);
        DecimalFormat format = new DecimalFormat("###,###");
        return format.format(value);
    }
}

makeStringComma는 천단위마다 콤마설정을 합니다.

그리고 onTextChanged에서 EditText에 값이 입력될 때마다 천단위에 콤마를 찍어줍니다.

 

 

edittext.addTextChangedListener(new CustomTextWathcher(edittext));

addTextChangedListener로 커스텀(CustomTextWatcher)을 사용하면 됩니다.



앱 내에서 구글플레이로 이동방법


안드로이드 앱 내부에서 현재 앱이나 기타 앱의 구글플레이 정보로 이동하게 되는 경우가 있습니다.

주로 앱 설정창에서 앱에 대한 평가를 하기 위해 이동처리를 해줍니다.

 

 

 

앱 내에서 연결할 때는

market://details?id=<패키지명>

을 사용하시면 됩니다.

 

패키지명은 일일이 입력하실 필요없이 getPackageName()을 이용하시면 해당 프로젝트의 패키지를 가져오게 됩니다.

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("market://details?id=" + getPackageName()));
startActivity(intent);
uri = Uri.parse("market://details?id=" + getPackageName());
startActivity(new Intent(Intent.ACTION_VIEW, uri));

둘 중에 편하신거 사용하시면 됩니다.

 

 

 

+ 구글플레이 해당 앱으로 이동하는 링크입니다.

http://play.google.com/store/apps/details?id=<패키지명>

 



안드로이드 액티비티 세로고정


androidmanifest.xml에서 고정하고자하는 activity를 찾아서 태그 안에

android:screenOrientation="portrait"

을 추가해주시면 됩니다. (가로모드: landscape)

 

 

java 코드에서 적용을 하시려면

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

를 사용하시면 됩니다. setRequestedOrientation은 setContentView가 호출되기 이전에 작성을 해주셔야 합니다.

 

 

 

 

+ 기타 방향 설정

원하시는 설정을 적용하시면 됩니다. 아래값들은 안드로이드 가이드(바로가기) android:screenOrientation에서 확인하실 수 있습니다.

"unspecified" 기본값입니다. 시스템이 방향을 선택합니다. 시스템이 사용하는 정책과 특정 컨텍스트에서 이루어지는 선택은 기기마다 다를 수 있습니다.
"behind" 액티비티 스택에서 바로 아래에 있는 액티비티와 동일한 방향입니다.
"landscape" 가로 방향입니다(디스플레이의 높이보다 너비가 더 긺).
"portrait" 세로 방향입니다(디스플레이의 너비보다 높이가 더 긺).
"reverseLandscape" 정상적인 가로 방향에서 반대 방향인 가로 방향입니다. API 레벨 9에서 추가되었습니다.
"reversePortrait" 정상적인 세로 방향에서 반대 방향인 세로 방향입니다. API 레벨 9에서 추가되었습니다.
"sensorLandscape" 기기 센서에 따라 정상적인 가로 방향 또는 반전된 가로 방향이 될 수 있습니다. 사용자가 센서 기반 회전을 잠갔더라도 센서가 사용됩니다. API 레벨 9에서 추가되었습니다.
"sensorPortrait" 기기 센서에 따라 정상적인 세로 방향 또는 반전된 세로 방향이 될 수 있습니다. 사용자가 센서 기반 회전을 잠갔더라도 센서가 사용됩니다. API 레벨 9에서 추가되었습니다.
"userLandscape" 기기 센서 및 사용자의 기본 설정에 따라 정상적인 가로 방향 또는 반전된 가로 방향이 될 수 있습니다. API 레벨 18에서 추가되었습니다.
"userPortrait" 기기 센서 및 사용자의 기본 설정에 따라 정상적인 세로 방향 또는 반전된 세로 방향이 될 수 있습니다. API 레벨 18에서 추가되었습니다.
"sensor" 기기 방향 센서가 방향을 결정합니다. 디스플레이 방향은 사용자가 기기를 잡고 있는 방법에 따라 다르며 사용자가 기기를 회전할 때 변경됩니다. 그러나 일부 기기는 기본적으로 4개의 모든 방향으로 회전하지 않습니다. 4개의 모든 방향을 허용하려면 "fullSensor"를 사용합니다. 사용자가 센서 기반 회전을 잠근 상태라도 센서가 사용됩니다.
"fullSensor" 기기 방향 센서가 4개의 방향을 결정합니다. 이는 4개의 화면 방향을 허용한다는 것을 제외하면 기기가 정상적으로 수행하는 것과 상관없이 "sensor"와 유사합니다. (예를 들어, 일부 기기는 세로 반전 또는 가로 반전을 정상적으로 사용하지 않지만 이 특성은 정상적으로 사용합니다.) API 레벨 9에서 추가되었습니다.
"nosensor" 물리적 방향 센서를 참조하지 않고 방향을 결정합니다. 센서가 무시되므로 사용자가 기기를 이동하는 방법에 따라 디스플레이가 회전하지 않습니다.
"user" 사용자의 현재 기본 설정 방향입니다.
"fullUser" 사용자가 센서 기반 회전을 잠금 설정한 경우 user와 동일하게 작동하고, 잠금 설정을 하지 않은 경우 fullSensor와 동일하게 작동하며 4개의 화면 방향을 허용합니다. API 레벨 18에서 추가되었습니다.
"locked" 현재 회전 방향을 잠금 설정합니다. API 레벨 18에서 추가되었습니다.

+ Recent posts