2013년 6월 27일 목요일

FragmentActivity, FragmentTabHost 사용하기

이전 블로그에서 이전 함 (원본 글 2013/06/27 작성)

아래 처럼 FragmentTabHost를 사용하면서 이것저것 하려니 개고생 함..
그냥 Android Project를 하나 만들고 MainActivity를 만들때 Navigation Type을 Scrollable Tabs+Swipe로 선택하여
SectionPagerAdapter + FragmentActivity 예제를 만들어 참고하여 app 만드는게 편함..


--------------------------------------------------------------------------------------------------

TabActivity가 deprecated 되면서 FragmentActivity & FragmentTabHost를 사용하게 되어
보던 중 생각보다 Google documentation이 부실해서 여기저기 찾아보고 정리함.

[Android Support Libraries 다운로드 및 설치]

> 아래 처럼 Android SDK Manager를 통해서 다운로드 하고 개발중인 project의 lib에 복사하고 project libraries로 추가

 Downloading the Support Package

The Support Package is provided as a downloadable package from the Android SDK Manager. To install:
  1. Launch the Android SDK Manager.
    From Eclipse, you can select Window > Android SDK Manager. Or, launch SDK Manager.exe from the <sdk>/ directory (on Windows only) or android from the <sdk>/tools/ directory.
  2. Expand the Android Repository, check Android Support package and click Install selected.
  3. Proceed to install the package.
When done, all files (including source code, samples, and the JAR files) are saved into the<sdk>/extras/android/support/ directory. This directory contains each of the different support libraries, such as the library for API level 4 and up and the library for API level 13 and up, each named with the respective version (such as v4/).

Setting Up a Project to Use a Library


To add one of the libraries to your Android project:

Add the JAR file to your project.
Copy the JAR file for the library you want to use into your Android project. To do this:

  • Create the directory libs/ at the root of your project (next to src/, res/, and so forth).
  • Locate the JAR file for the library you want to use and copy it into the libs/ directory.
    For example, the library that supports API level 4 and up is located at <sdk>/extras/android/support/v4/android-support-v4.jar.
Your build system may expect to find the JAR file in a directory other than libs. Read the documentation for your build system to learn where to put the JAR file.

<dl style="color: rgb(34, 34, 34); font-family: Roboto, sans-serif; font-size: 14px; line-height: 19px; background-color: rgb(249, 249, 249);">
If necessary, add the libs/ directory to your build path.
Read the documentation for your build system to learn how to add the JAR file to the build path.
</dl>


[Fragment 개념] 
> Fragment에 대한 전반적인 tutorial.. 추천

[FragmentTabHost reference]

> 사실 아래 예제가 다임.. 좀 더 자세한 설명은 아래 링크를 참고. 
   TabHost.addTab() 에서 class들은 Fragment를 상속받아 만든 class 들임.

 Here is a simple example of using a FragmentTabHost in an Activity:
import com.example.android.supportv4.R;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTabHost;
/**
 * This demonstrates how you can implement switching between the tabs of a
 * TabHost through fragments, using FragmentTabHost.
 */
public class FragmentTabs extends FragmentActivity {
    private FragmentTabHost mTabHost;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.fragment_tabs);
        mTabHost = (FragmentTabHost)findViewById(android.R.id.tabhost);
        mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);

        mTabHost.addTab(mTabHost.newTabSpec("simple").setIndicator("Simple"),
                FragmentStackSupport.CountingFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("contacts").setIndicator("Contacts"),
                LoaderCursorSupport.CursorLoaderListFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("custom").setIndicator("Custom"),
                LoaderCustomSupport.AppListFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("throttle").setIndicator("Throttle"),
                LoaderThrottleSupport.ThrottledLoaderListFragment.class, null);
    }
}
This can also be used inside of a fragment through fragment nesting:
import com.example.android.supportv4.R;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTabHost;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class FragmentTabsFragmentSupport extends Fragment {
    private FragmentTabHost mTabHost;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        mTabHost = new FragmentTabHost(getActivity());
        mTabHost.setup(getActivity(), getChildFragmentManager(), R.id.fragment1);

        mTabHost.addTab(mTabHost.newTabSpec("simple").setIndicator("Simple"),
                FragmentStackSupport.CountingFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("contacts").setIndicator("Contacts"),
                LoaderCursorSupport.CursorLoaderListFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("custom").setIndicator("Custom"),
                LoaderCustomSupport.AppListFragment.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("throttle").setIndicator("Throttle"),
                LoaderThrottleSupport.ThrottledLoaderListFragment.class, null);

        return mTabHost;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        mTabHost = null;
    }
}

[FragTabHost 사용 상세 예제들]

> 모든 코드(Fragment classes) 포함

> 좀 자세한 설명

[FragTabs를 아래로 위치시키기]

> 웹상에서는 Relative를 사용하거나 Linear의 weight를 사용하는 방법 아니면 Custom tab을 사용하는 방법이 있지만 위에서는 간단하게 해결 함. 아래는 살짝 수정한 코드
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:weightSum="1" >

    <FrameLayout
        android:id="@+id/realtabcontent"
        android:layout_width="match_parent"
        android:layout_height="0dip"
        android:layout_weight="1" />

    <android.support.v4.app.FragmentTabHost
        android:id="@android:id/tabhost"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <FrameLayout
            android:id="@android:id/tabcontent"
            android:layout_width="0dp"
            android:layout_height="0dp" />

        <TabWidget
            android:id="@android:id/tabs"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />
    </android.support.v4.app.FragmentTabHost>

</LinearLayout>


[Fragment Tab 간 data 전달]
> Android Developers site의 Fragment 관련 내용에서 나오는 내용.

> 좀 더 상세한 내용, 사실 Fragment의 Tag를 알아내는 방법을 몰라 좀 고생했었음.
   Activity에 Tag를 받는 함수를 만들고 각 Fragment Tab이 생성 되었을 때 Activity의 함수를 통해 Tag을 등록
   좀 나이스 한 방법은 아니지만.. 일단 뭐...
 public class MyFragmentB extends Fragment {

 TextView b_received;
 
 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container,
   Bundle savedInstanceState) {
  View myFragmentView = inflater.inflate(R.layout.fragment_b, container, false);
  
  b_received = (TextView)myFragmentView.findViewById(R.id.b_received);
  String myTag = getTag();
  
  ((AndroidViewPagerActivity)getActivity()).setTabFragmentB(myTag);


[기타]
> 코드가 좀 이상하네...

2013년 6월 22일 토요일

Ubuntu 설치용 bootable USB 만들기

이전 블로그에서 이전 함 (원본 글 2013/06/22 작성)

CD 만들기는 귀찮고 남아도는 USB를 Ubuntu 설치를 위해 사용하는 방법 

- 준비물 : 2G 이상 USB 메모리

절차
1. pendrivelinux.com에서 Universial USB Installer(bootable USB 생성 프로그램) 다운로드
2. ubuntu.com에서 설치하고자 하는 ubuntu 버전 다운로드 (프로그램에서도 다운로드 가능하지만 혹시나..)
3. Universial USB Installer에서 설치하고자 하는 ubuntu iso의 버전 선택 후 만들기 (포멧 체크 추천-USB내에 별것 없다면)



How to create a bootable USB
stick on Windows

To run Ubuntu from a USB stick, the first thing you need to do is insert a USB stick with at least 2GB of free space into your PC.
The easiest way to put Ubuntu onto your stick is to use the USB installer provided atpendrivelinux.com. You’ll need to download and install and follow the instructions.
  1. 1
    Select Ubuntu Desktop Edition from the dropdown list.
  2. 2
    Click 'Browse' and open the downloaded ISO file.
     
  3. 3
    Choose the USB drive and click 'Create'.

2013년 6월 21일 금요일

(Link) SQL query 관련 링크

이전 블로그에서 이전 함 (원본 글 2013/06/21 작성)

SQL 다시 보니 새록새록 기억도 나지만 모든게 새롭군 ㅜㅜ


SQLite 관련 내용 정리 : http://imhallower.blog.me/90177383065

SQLite In 5 Minutes Or Less

SQLite Documentation

MySQL tutorial
: 영어가 쉽고 예제가 풍부해서 천천히 전체를 볼만함.

MySQL Quick reference card (PDF)
: 간단하게 뽑아두고 쓰기엔 좋을듯.

Database Programming

2013년 6월 18일 화요일

Android Jersey 사용 시 WebResource type 설정 시 NullPointerException

이전 블로그에서 이전 함 (원본 글 2013/06/18 작성)

Android 상에서 Jersey(버전은 1.17.1)를 사용하여 REST를 처리 시
WebResoruce의 type을 설정하는데 NullPointerException이 발생하여 찾다 보니
아래와 같은 article 검색

Android 의 APK packaging 문제로 META-INF/service 들을 못찾는다는 얘기... 사실 잘 모르겠다.. :(

Reply | Threaded | More     star

Re: java.lang.NullPointerException on Android

Lucas Ventura
6 posts
Paul Sandoz wrote
On May 28, 2010, at 11:21 AM, Lucas Ventura wrote: I would be surprised if ClassLoader.getResources ceased to function correctly to load resources (that method is used to load the META-INF/ services files). But a quick search does indicate others are having similar issues with packaging and META-INF/services.
The problem after inspecting a little bit, is that the ClassLoader created by Google neither can't find services files, nor the class implementations.
Paul Sandoz wrote
There might be a way. It is possible to override the META-INF/services lookup by using the following method: https://jersey.dev.java.net/nonav/apidocs/latest/jersey/com/sun/jersey/spi/service/ServiceFinder.html #setIteratorProvider %28com.sun.jersey.spi.service.ServiceFinder.ServiceIteratorProvider%29 So you could provide your own implementation. Paul.
So I've provided a hardcoded implementation with the names of the classes indicateds in the META-INF/services files. The question is: when I should do this call to serIteratorProvider()? Because if I do before the Client creation it is looking for servicejersey-client-components. If I do after, it works, but... will be called again with a that kind of serviceName? Thanks a lot :)


암튼 해결책이 위쪽 thread와 아래 link에 있어 일단 추가하여 수정
그리고 추가로 아래 해결책의 update 사항에 Android maven plugin에서는 해결되어 있다니.. 나중에 참고해 보자..



up vote12down voteaccepted
Paul's suggestion is correct. I got a little bit deeper in that subject and found a reason.
Android apk packaging tool (APKBuilder class from sdklib.jar) ignores different folders while it creates the package (source). One of those folders is META-INF - no matter if its in the attached library or in the project's source folder.
Workaround for version 1.8 (and probably other also, but I didn't test it) of Jersey is to provide custom (default one looks up META-INF/services/ which is not present in android apk) implementation forServiceFinder$ServiceIteratorProvider which has hard coded provider class names. I based my implementation on this implementation proposed by Lucas:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import android.util.Log;

import com.sun.jersey.spi.service.ServiceFinder.ServiceIteratorProvider;

public class AndroidServiceIteratorProvider<T> extends ServiceIteratorProvider<T> {

    private static final String TAG = AndroidServiceIteratorProvider.class.getSimpleName();
    private static final String MESSAGE = "Unable to load provider";

    private static final HashMap<String, String[]> SERVICES = new HashMap<String, String[]>();

    private static final String[] com_sun_jersey_spi_HeaderDelegateProvider = {
            "com.sun.jersey.core.impl.provider.header.MediaTypeProvider",
            "com.sun.jersey.core.impl.provider.header.StringProvider"
    };

    private static final String[] com_sun_jersey_spi_inject_InjectableProvider = { 
    };

    private static final String[] javax_ws_rs_ext_MessageBodyReader = {
            "com.sun.jersey.core.impl.provider.entity.StringProvider",
            "com.sun.jersey.core.impl.provider.entity.ReaderProvider"
    };

    private static final String[] javax_ws_rs_ext_MessageBodyWriter = {
            "com.sun.jersey.core.impl.provider.entity.StringProvider",
            "com.sun.jersey.core.impl.provider.entity.ReaderProvider"
    };

    static {
        SERVICES.put("com.sun.jersey.spi.HeaderDelegateProvider",
                com_sun_jersey_spi_HeaderDelegateProvider);
        SERVICES.put("com.sun.jersey.spi.inject.InjectableProvider",
                com_sun_jersey_spi_inject_InjectableProvider);
        SERVICES.put("javax.ws.rs.ext.MessageBodyReader",
                javax_ws_rs_ext_MessageBodyReader);
        SERVICES.put("javax.ws.rs.ext.MessageBodyWriter",
                javax_ws_rs_ext_MessageBodyWriter);
        SERVICES.put("jersey-client-components", new String[]{});
        SERVICES.put("com.sun.jersey.client.proxy.ViewProxyProvider", new String[]{});
    }

    @SuppressWarnings("unchecked")
    @Override
    public Iterator<Class<T>> createClassIterator(Class<T> service,
            String serviceName, ClassLoader loader,
            boolean ignoreOnClassNotFound) {

        String[] classesNames = SERVICES.get(serviceName);
        int length = classesNames.length;
        ArrayList<Class<T>> classes = new ArrayList<Class<T>>(length);
        for (int i = 0; i < length; i++) {
            try {
                classes.add((Class<T>) Class.forName(classesNames[i]));
            } catch (ClassNotFoundException e) {
                Log.v(TAG, MESSAGE,e);
            }
        }
        return classes.iterator();
    }

    @Override
    public Iterator<T> createIterator(Class<T> service, String serviceName,
            ClassLoader loader, boolean ignoreOnClassNotFound) {

        String[] classesNames = SERVICES.get(serviceName);
        int length = classesNames.length;
        ArrayList<T> classes = new ArrayList<T>(length);
            for (int i = 0; i &lt; length; i++) {
            try {
                classes.add(service.cast(Class.forName(classesNames[i])
                        .newInstance()));
            } catch (IllegalAccessException e) {
                Log.v(TAG, MESSAGE,e);
            } catch (InstantiationException e) {
                Log.v(TAG, MESSAGE,e);
            } catch (ClassNotFoundException e) {
                Log.v(TAG, MESSAGE,e);
            }
        }

        return classes.iterator();
    }
}
I removed most of the classes since I didn't use them and also they were causing verification errors on dalvik vm...
The above code should be used as follows:
ServiceFinder.setIteratorProvider(new AndroidServiceIteratorProvider());
Client client = Client.create();
EDIT:
It seems that the problem have been fixed in android-maven-plugin.
mosa...@gmail.com wrote:
The pull request with the fix was merged into master and will be released with 3.2.1:
share|improve this answer