작업을 하다보면 간혹 OS의 오류인지 기기의 문제인지

아래와 같은 현상이 아주 가끔 발생합니다.



수정 코드

android.support.v7.widget.Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);

toolbar.setContentInsetsAbsolute(0, 0);

setSupportActionBar(toolbar);


결과 화면



여러가지 연동 작업을 하다보면 해쉬키를 얻어와야할 경우가 생깁니다.

Google map 이라던지, facebook 연동이라던지 기타등등


사용 코드

try {     // 해시키
    PackageInfo info = getPackageManager().getPackageInfo("your package", PackageManager.GET_SIGNATURES);
    for (Signature signature : info.signatures) {
        MessageDigest md = MessageDigest.getInstance("SHA");
        md.update(signature.toByteArray());
        String sign= Base64.encodeToString(md.digest(), Base64.DEFAULT);
        Log.e("test", "hash key : " + sign);
        //Toast.makeText(getApplicationContext(),sign,     Toast.LENGTH_LONG).show();
    }
} catch (PackageManager.NameNotFoundException e) {
    Log.e("test", "hash key1 : "+e.toString());
} catch (NoSuchAlgorithmException e) {
    Log.e("test", "hash key2 : "+e.toString());
}


ImageView 안에 있는 resource 컬러값 변경

이미지 리소스가 단색일 경우에만 유용하게 사용 할 수 있습니다.

코드 한두줄로 처리가 되니깐, 이미지를 다시 재작업 하는 번거로움을 없앨수 있겠습니다.


작업 전



코드 사용

ImageView iv_icon_map = (ImageView) view.findViewById(R.id.iv_icon_map);

int color = ContextCompat.getColor(getActivity(), R.color.color_red);

iv_icon_map.setColorFilter(color);



작업 후


MapView inside ScrollView (fragment)


프래그멘트 안에 있는 ScrollView 에  맵뷰 달기


fragment_maps.xml 맵뷰의 레이아웃을 정의 합니다.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.google.android.gms.maps.MapView
        android:id="@+id/mapView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>


MapInFragment.java뷰의 클레스를 정의합니다.

public class MapInFragment extends Fragment {

    MapView mMap;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_maps, container, false);
        mMap = (MapView) v.findViewById(R.id.mapView);
        mMap.onCreate(savedInstanceState);
        mMap.getMapAsync(new OnMapReadyCallback() {
            @Override
            public void onMapReady(GoogleMap googleMap) {
                if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                    boolean permission = hasAllPermissionsGranted();
                    if (permission) {
                        Log.e("test","aaaa");
                    }
                    return;
                }
                googleMap.getUiSettings().setMyLocationButtonEnabled(true);
                googleMap.getUiSettings().setZoomControlsEnabled(true);
                googleMap.setMyLocationEnabled(true);

                try {
                    MapsInitializer.initialize(getActivity());
                } catch (Exception e) {

                }

                googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(37.488, 126.891), 15));
            }
        });

        return v;
    }

    @Override
    public void onResume() {
        mMap.onResume();
        super.onResume();
    }

    @Override
    public void onPause() {
        super.onPause();
        mMap.onPause();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mMap.onDestroy();
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        mMap.onLowMemory();
    }

    //권한 추가
    private static final int REQUEST_PERMISSIONS = 1;
    private static final String[] MY_PERMISSIONS = {
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.ACCESS_COARSE_LOCATION
    };
    private boolean hasAllPermissionsGranted() {
        for (String permission : MY_PERMISSIONS) {
            if (ContextCompat.checkSelfPermission(getActivity(), permission) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(getActivity(), MY_PERMISSIONS, REQUEST_PERMISSIONS);
                return false;
            }
        }
        return true;
    }
}


코드 적용 (7.0 버전으로 만들어서 시스템 permission 권한 코드 포함)

Activity layout 에서 ScrollView 안에 정의합니다.

<ScrollView

...

<FrameLayout android:id="@+id/map_container"
	android:layout_width="match_parent"
	android:layout_height="200dp"
	android:layout_marginTop="10dp"/>
...

</ScrollView>

Fragment 내에서의 처리

public class AddMemoFragment extends Fragment {

    FrameLayout map_container;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_add, container, false);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        map_container = (FrameLayout) view.findViewById(R.id.map_container) ;

        MapInFragment map = new MapInFragment();
        FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
        transaction.replace(R.id.map_container, map).commit();
    }
}


결과 화면


   

MapView inside ScrollView (activity)



참고Url

http://www.londatiga.net/it/programming/android/how-to-make-android-map-scrollable-inside-a-scrollview-layout/



리스트뷰안에 맵을 넣는 것을 검색하다가 적용 및 테스트를 해봤습니다.

위의 주소에 있는 코드에서는 ScrollView와 MapView 의 터치 이벤트를 동시에 적용되는 기능도 처리가 되어 있어서

여러모로 쓸모가 많은 코드네요.


fragment_maps.xml 맵뷰의 레이아웃을 정의 합니다.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.google.android.gms.maps.MapView
        android:id="@+id/mapView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>


WorkaroundMapFragment.java의 클레스를 정의합니다.

import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

import com.google.android.gms.maps.SupportMapFragment;

public class WorkaroundMapFragment extends SupportMapFragment {
    private OnTouchListener mListener;

    @Override
    public View onCreateView(LayoutInflater layoutInflater, ViewGroup viewGroup, Bundle savedInstance) {
        View layout = super.onCreateView(layoutInflater, viewGroup, savedInstance);
        TouchableWrapper frameLayout = new TouchableWrapper(getActivity());
        frameLayout.setBackgroundColor(getResources().getColor(android.R.color.transparent));
        ((ViewGroup) layout).addView(frameLayout,
                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        return layout;
    }

    public void setListener(OnTouchListener listener) {
        mListener = listener;
    }

    public interface OnTouchListener {
        public abstract void onTouch();
    }

    public class TouchableWrapper extends FrameLayout {
        public TouchableWrapper(Context context) {
            super(context);
        }
        @Override
        public boolean dispatchTouchEvent(MotionEvent event) {
            if(mListener == null)
                return false;
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    mListener.onTouch();
                    break;
                case MotionEvent.ACTION_UP:
                    mListener.onTouch();
                    break;
            }
            return super.dispatchTouchEvent(event);
        }
    }
}


코드 적용

Activity layout 에서 ScrollView 안에 정의합니다.

<ScrollView ... <fragment android:tag="fragment_map"     android:id="@+id/fragment_map"     android:layout_width="match_parent"     android:layout_height="300dp"     android:layout_marginTop="20dp"     class="your package .WorkaroundMapFragment"/> ... </ScrollView>

Activity 내에서의 처리

public class MainActivity extends AppCompatActivity {

    private GoogleMap mMap;
    private ScrollView mScrollView;

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

        WorkaroundMapFragment mapFrag = (WorkaroundMapFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_map);
        mapFrag.getMapAsync(new OnMapReadyCallback() {
            @Override
            public void onMapReady(GoogleMap googleMap) {
                if (ActivityCompat.checkSelfPermission(getBaseContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getBaseContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                    boolean permission = hasAllPermissionsGranted();
                    if (permission) {
                        Log.e("test","permission "+permission);
                    }
                    return;
                }
                googleMap.setMyLocationEnabled(true);
                googleMap.getUiSettings().setZoomControlsEnabled(true);
            }
        });

        mScrollView = (ScrollView) findViewById(R.id.sv_container);
        mapFrag.setListener(new WorkaroundMapFragment.OnTouchListener() {
            @Override
            public void onTouch() {
                mScrollView.requestDisallowInterceptTouchEvent(true);
            }
        });
    }

    //권한 추가
    private static final int REQUEST_PERMISSIONS = 1;
    private static final String[] MY_PERMISSIONS = {
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.ACCESS_FINE_LOCATION
    };
    private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
    private boolean hasAllPermissionsGranted() {
        for (String permission : MY_PERMISSIONS) {
            if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, MY_PERMISSIONS, REQUEST_PERMISSIONS);
                return false;
            }
        }
        return true;
    }
}



결과 화면




참고 Url

https://developer.android.com/reference/android/app/Fragment.html#getChildFragmentManager()


fragment 안에 fragment 집어 넣기

작업을 하다보면 프레그멘트 안에 프레그멘트를 집어 넣어야 할경우가 생깁니다.

예를 들어 MapFragment 라던지..


주의사항! 

getChildFragmentManager() 는 api 17 부터 사용이 가능하다고 되어있어서,

최소버전의 조정이라든지, 아니면 옛날 support-v4 라이브러리를 수동으로 import 해서 사용할수도 있지만

Dex문제라던지(Multi dex 필요) 여러모로 번거로움이 생기드라구요




방법1. XML 내에서의 정의

<fragment
    android:id="@+id/frame"
    android:name="your package name.SubFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="20dp"
    android:tag="info_sub"/>

방법2. Java code 로 정의

Override method 추가 해준뒤에


@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    Fragment sub2 = new SubFragment2();
    FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
    transaction.replace(R.id.frame_container2, sub2).commit();
}

}

처음 새 프로젝트를 만들게 되면 아래에 같은 모양이 됩니다.
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ... 중략 ...
    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
        this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
    drawer.setDrawerListener(toggle);
    toggle.syncState();

    NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
    navigationView.setNavigationItemSelectedListener(this);
}

ActionBarDrawerToggle 에서는 이미 DrawerLayout.DrawerListener 를 가지고 있으므로 아래와 같이 추가를 해주시면 되겠습니다.

(Android Studio) 메뉴 > Code > Ovrride Methods .... 선택후

onDrawerSlide

onDrawerOpened

onDrawerClosed

onDrawerStateChanged 원하는 것을 추가하면 됩니다.


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ... 중략 ...
    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
        this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);

DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
        this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) {

    @Override
    public void onDrawerSlide(View drawerView, float slideOffset) {
        super.onDrawerSlide(drawerView, slideOffset);
    }

    @Override
    public void onDrawerOpened(View drawerView) {
        super.onDrawerOpened(drawerView);
    }

    @Override
    public void onDrawerClosed(View drawerView) {
        super.onDrawerClosed(drawerView);
    }

    @Override
    public void onDrawerStateChanged(int newState) {
        super.onDrawerStateChanged(newState);
    }
};

    //drawer.setDrawerListener(toggle); // 이건 Deprecated 되었다니깐 아래와 같이 바꿔줍니다.
    drawer.addDrawerListener(toggle);
    toggle.syncState();

    NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
    navigationView.setNavigationItemSelectedListener(this);
}

추가적으로
Fragment 교체 등 에서 Actionbar 의 홈 버튼을 화살표 이미지로 바꿨을 경우에 

손가락으로 밀었을때 좌측메뉴(DrawerLayout) 가 나오면 안되니깐


막기

drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);


풀기

drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);


minifyEnabled (코드 축소)

shrinkResource(리소스 축소)


장점

- 안쓰는 코드를 줄여서 축소 빌드를 할 수 있게 도와준다.

- 용량이 줄어듬

- 난독처리


단점 (true 선택시)

- 유지할 코드 충분히 확인시 proguard에 적용 시켜줘야 하는 번거로움

- 빌드속도가 느려지기 때문에 Debug 모두에선 false가 좋음


참조 url

https://developer.android.com/studio/build/shrink-code.html?hl=ko



테스트 - 원본사이즈




테스트 - 코드 축소 (반 이상이 줄어들음...)




테스트 - 리소스 축소 (리소스에서 변환이 없어서 확인해본 결과 대부분 사용중인 것으로...)


+ Recent posts