ListFragment では、getWrappedAdapter 不要。。。

先日書いたListView footer を付けた時、リストアダプタを get して、HeaderViewListAdapter cast して
getWrappedAdapter を得てから BaseAdapter に cast して BaseAdapterメソッドを実行していたが、
それは、Activityで、直接 Listview を使っていたからである。

 http://blog.zaq.ne.jp/oboe2uran/article/1006/
 http://blog.zaq.ne.jp/oboe2uran/article/1007/

ListFragment では、footer View を追加しようが、ListFragment 内で
getListAdapter() から
BaseAdapter に cast して BaseAdapterのメソッドを実行でる。

public class SampleFragment extends ListFragment{
     :
     省略
     :
   ItemlistReadTask extends AsyncTask<Void,Item,Integer>{
      @Override
      protected Integer doInBackground(Void...params){
         // publishProgress でリスト表示
         publishProgress(item);
      }
      @Override
      protected void onProgressUpdate(Item...values){
         mList.add(values[0]); // mList追加でリスト表示
         ((BaseAdapter)getListAdapter()).notifyDataSetChanged();
      }
   }
}

publishProgress でリスト要素追加

ListView AsyncTask publishProgress で更新する方法、
いまさらだが、、、
スクロールで最後尾に達したら次を読むリストビューを考えていて書いてみた。

かなり省略してはいるが、以下のようになった。cancelled とか考慮しなくてはならない。。。

publishProgress でリスト追加して、notifyDataSetChanged は、重くなる
変なやり方なのだろうか。。。


ItemreadTask task;
ListView mListview;
View mFooterView;

mListview = (ListView)findViewById(R.id.listView);
// フッタは Adapter セットの前で!
mFooterView = getLayoutInflater().inflate(R.layout.listfooter, null);
  :
   Adapter セット省略
  :
mListview.setOnScrollListener(new AbsListView.OnScrollListener(){
   @Override
   public void onScrollStateChanged(AbsListView view, int scrollState){
   }
   @Override
   public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount){
      if (totalItemCount == firstVisibleItem + visibleItemCount){
         // 最後尾に到達
         if (実行中でなければ!){
            task = new ItemreadTask(mDisplayedCount);
            task.execute();
         }
      }
   }
});
-------
class ItemreadTask extends AsyncTask<Void,Item,Integer>{
   private int mCount;
   @Override
   protected void onPreExecute(){
      mListview.addFooterView(mFooterView);
   }
   @Override
   protected Integer doInBackground(Void...params){
      // cancelled で中断するようにする。

      // publishProgress でリスト表示
      publishProgress(item);

      // カウンタを返す
      return mCount;
   }
   @Override
   protected void onPostExecute(Integer result){
      mListview.removeFooterView(mFooterView);
   }
   @Override
   protected void onCancelled(){
      // cancelled で中断するようにする。
   }
   @Override
   protected void onProgressUpdate(Item...values){
      mList.add(values[0]);
      *1.getWrappedAdapter()).notifyDataSetChanged();
   }

}

*1:BaseAdapter)((HeaderViewListAdapter)mListview.getAdapter(

ListView に、ヘッダやフッタを付加する場合、

ListView に、addHeaderView addFooterView を使用してヘッダ、フッタに View を追加した場合、
注意がひつようで、以下の様な場合、ListView#getAdapter を実行すると、HeaderViewListAdapter を取得することになる。
以下のようにコードでは、、

ListView mListview;
  :
mListview.addFooterView(mFooterView);;

mListview.setAdapter(new ArrayAdapter<FooItem>(this, 0, mList){
   LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
   @Override
   public View getView(int position, View convertView, ViewGroup parent){
      View = 
         :
      // 省略
         :
      return view;

   }
});
----
*1.notifyDataSetChanged()
というコードは成立しない。

ClassCastException : HeaderViewListAdapter cannot be cast to android.widget.BaseAdapter

となる。

以下のようにする必要がある。

HeaderViewListAdapter headerViewListAdapter = (HeaderViewListAdapter)mListview.getAdapter();
((BaseAdapter)headerViewListAdapter.getWrappedAdapter()).notifyDataSetChanged();

1行で書くなら、、、

(BaseAdapter)*2.getWrappedAdapter()).notifyDataSetChanged();


*1:BaseAdapter)mListview.getAdapter(

*2:HeaderViewListAdapter)mListview.getAdapter(

JSONだけを応答レスポンスとして返すWebシステム

JSONだけを応答レスポンスとして返すWebシステム構築を考えた時、
HTTPリクエストから、JSON だけを応答することに
というコンセプトを持てば、、
Tomcat等のWebコンテナの他に必要なものとして、
有名なWebフレームワークの多くは、余計な機能があり過ぎて必要がない。
Servlet-APIと、JSON生成の為のライブラリ、他は文字列操作やログ出力等、今まで
Jakartaプロジェクトで使ってた便利API、せいぜい、Google-guice でもあれば、充分である。

import javax.servlet.http.HttpServletRequest;
/**
 * JsonResponder JSONレスポンス応答インターフェース.
 */

public interface JsonResponder{
   /**
    * HttpServletRequest→JSON.
    * @param request javax.servlet.http.HttpServletRequest
    * @return JSON文字列データ、null を返却すると HTTPレスポンスを返さない。
    */

   public String answer(HttpServletRequest request);
}

public abstract class JacobApplication{
   public abstract JsonResponder init();
}

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * フィルタ.
 */

public final class JacobFilter implements Filter{
   private Logger logger = LoggerFactory.getLogger(this.getClass());

   private JsonResponder jsonResponder;

   @Override
   public void init(FilterConfig config) throws ServletException{

      String applicationClassName = config.getInitParameter("applicationClassName");
      ClassLoader loader = Thread.currentThread().getContextClassLoader();
      try{
         JacobApplication application = (JacobApplication)loader.loadClass(applicationClassName).getConstructor(new Class<?>{}).newInstance();
         jsonResponder = application.init();
      }catch(Exception e){
         logger.error(e.getMessage(), e);
      }
   }
   @Override
   public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,ServletException{

      HttpServletRequest httpServletRequest = (HttpServletRequest)request;
      String method = httpServletRequest.getMethod();
      if (!method.equals("GET") && !method.equals("POST")) return;
      String content = jsonResponder.answer(httpServletRequest);
      if (content != null){
         HttpServletResponse httpres = (HttpServletResponse)response;
         httpres.addHeader("Content-Type", "application/json; charset=utf-8");
         httpres.addHeader("Access-Control-Allow-Origin", "*");
         httpres.addHeader("Access-Control-Allow-Headers", "X-Requested-With");
         byte
 b = content.getBytes();
         httpres.addHeader("Content-Length", Integer.toString(b.length));
         response.setCharacterEncoding("UTF-8");
         response.getOutputStream().write(content.getBytes());
      }
   }
   @Override
   public void destroy(){
   }
}


web.xml が以外にも鍵であり、、、、

  <filter>
    <filter-name>JacobFilter</filter-name>
    <filter-class>xxx.xxx.JacobFilter</filter-class>
    <init-param>
      <param-name>applicationClassName</param-name>
      <param-value>sample.SampleApplication</param-value>
    </init-param>
  </filter>

SampleApplication extends JacobApplication を
如何に用意して、
この JsonResponder 実装、即ち、HTTP要求に対して、如何に!?
JSON 文字列を作成していくかという作業に注力していくことになる。


ローカルPCのMavenリポジトリへの登録

Maven で取得していないJARを、ローカルPCのMavenリポジトリに入れる方法

以下のコマンドで登録する。

mvn install:install-file -Dfile={jarファイルフルパス} -DgroupId={パッケージ} -DartifactId={名前} -Dversion={バージョン番号} -Dpackaging=jar -DgeneratePom=true

参照の pom.xml は、、、

 <dependency>
    <groupId>パッケージ</groupId>
    <artifactId>名前</artifactId>
    <version>バージョン番号</version>
 </dependency>

Access-Control-Allow-Origin error

簡単なWebアプリを作っていて、AJAX通信で以下のエラーが出たら、

No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'null' is therefore not allowed access


返すHTTPレスポンスヘッダに、以下を付ければ良い。

Access-Control-Allow-Origin 属性値として、'*' を指定

JavaServter-API なら、
 HttpServletResponse#addHeader("Access-Control-Allow-Origin","*");


ということ。

JSON データ→jquery.handsontable

JSONデータを jquery.handsontable プラグインで表示することを試してみる。

単純にシンプルなデータ配列のJSONデータは、サイトのデモを見れば解ってることなので、
特に、Key-Valueペアの関係にあるケースがどうなるか?である。


var data = {"a":"1","b":"2"};
$('#example').handsontable({
   data: data,
   contextMenu: true,
   stretchH: 'all',
   readOnly: true
});

<div id="example" class="handsontable" style="width: 400px; height: 140px; overflow: auto"></div>


この表示は、以下のようになる。

f:id:posturan:20160313192106j:plain



では、データが以下のケースの場合、、、
var data = [
   {"a":"1","b":"2"},
   {"c":"3","c":"4"},
];


表示は、以下のようになり、期待に反する。

f:id:posturan:20160313192011j:plain



更に、次のようなデータの場合、
var data = [
   {"alpha":{"a":"1","b":"2"}},
   {"beta" :{"c":"3","d":"4"}}
];

これも結果は、上と同じ表示になる。

Key が表示されないことと、上の結果を踏まえて JavaのオブジェクトからJSONを
生成してこのプラグインで表を表示させることを検討した場合、
Mapの場合、Keyを無視するという前提で、、
Mapの配列は使えないけど、Mapそのものは使える。
Listや、2次元配列は使える。