6月から始めたAndroidアプリ開発だが、Javaの習得と平行してだったので、
かなりJavaに手を焼き、ソースもシッチャカメッチャカ。
pythonだったらこうするのに(怒)

とりあえず動かすことが最優先だったので、性能以外の効率性は度外視だった。

アプリも無事に公開でき、一段落したので
次のアプリに取り掛かる前に生産性をアップさせたい。

個人的には生産性が格段にアップしたのだが、
Javaもアンドロイドも初心者なので、こんな使い方の善悪の判断がつかない
ライブラリソースを公開してコメントもらうことにした。

ということで誰かコメント下さいな ダメ出し大歓迎!!


今回ライブラリの目的:

本質ではない処理だが、頻繁に使う機能をまとめ、
複雑な準備、手順をハイレベルなメソッドとしてまとめ、
本質的な処理開発に集中できるようにする。

簡素化した機能:


  1. オンラインかどうか確認する
  2. トーストを表示する
  3. Notificationを表示する
  4. SharedPreferenceの値を取得する
  5. Activity一覧の作成
  6. スレッド実行(引数なし、引数あり)
  7. 進捗ダイヤログ付き実行(引数なし、引数あり)
  8. 進捗ダイヤログのセットと、表示

import java.util.Map;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.Toast;

public class CoreActivity extends Activity{
 // 1.オンラインかどうか確認する
 public boolean isOnline() {
  ConnectivityManager cm = (ConnectivityManager) CoreActivity.this.getSystemService(Context.CONNECTIVITY_SERVICE);
  NetworkInfo netInfo = cm.getActiveNetworkInfo();
  if (netInfo != null && netInfo.isConnectedOrConnecting()) {
   return true;
  }
  return false;
 }

 // 2.トーストを表示する
 public void sendToast(String viewtext) {
  Toast toast = Toast.makeText(this, viewtext, Toast.LENGTH_LONG);
  toast.setGravity(Gravity.CENTER, 0, 0);
  toast.show();
 }

 // 3.Notificationを表示する
 public void sendNotification(int icon, String viewtext) {
  String app_name = (String)getApplicationInfo().loadLabel(getPackageManager());
  
  Notification n = new Notification(); // Notificationの生成
  n.icon = icon;
  n.tickerText = viewtext; // メッセージの設定

  Intent i = new Intent(this, CoreActivity.class);
  PendingIntent pi = PendingIntent.getActivity(this, 0, i, 0);

  n.setLatestEventInfo(this, app_name, viewtext, pi);

  // NotificationManagerのインスタンス取得
  NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
  nm.notify(1, n); // 設定したNotificationを通知する
 }
 
 // 4.SharedPreferenceの値を取得する
 public Object getPref(String prefKey, Object defaultValue) {
  SharedPreferences sp = PreferenceManager
    .getDefaultSharedPreferences(this);
  sp.edit().commit();
  Map map = sp.getAll();
  
  if (sp.contains(prefKey)) {
   return map.get(prefKey);
  } else {
   return defaultValue;
  }
 }

 // 5.Activity一覧の作成
 protected void setActivitiesListView(ListView listView, final Object[] activities) {
  CharSequence[] list = new CharSequence[activities.length / 2];
  for (int i = 0; i < list.length; i++) {
   list[i] = (String) activities[i * 2];
  }

  ArrayAdapter adapter = new ArrayAdapter(
    this, android.R.layout.simple_list_item_1, list);

  listView.setAdapter(adapter);

  listView.setOnItemClickListener(new OnItemClickListener() {
   @Override
   public void onItemClick(AdapterView parent, View view,
     int position, long id) {
    Intent intent = new Intent(CoreActivity.this,
      (Class) activities[position * 2 + 1]);
    startActivity(intent);
   }
  });
 }
 
 // 6-1.スレッド実行(引数あり)
 public void runBackGround(final Object object, final String methodName, final Object[] args) {
  // スレッド処理
  Runnable runnable = new Runnable() {
   @Override
   public void run() {
    // 指定メソッド実行
    Refrecter.runMethod(object, methodName, args);
   }
  };

  // スレッド生成・実行
  Thread thread = new Thread(runnable);
  thread.start();
 }
 
 // 6-2.スレッド実行(引数なし)
 public void runBackGround(final Object object, final String methodName) {
  // スレッド処理
  Runnable runnable = new Runnable() {
   @Override
   public void run() {
    // 指定メソッド実行
    Refrecter.runMethod(object, methodName);
   }
  };

  // スレッド生成・実行
  Thread thread = new Thread(runnable);
  thread.start();
 }

 // 7-1.進捗ダイヤログ付き実行(引数あり)
 @SuppressLint("android.view.WindowLeaked")
 public void runWithProgressDialog(final Object object, final String methodName, final Object[] args) {
  // スレッド処理
  Runnable runnable = new Runnable() {
   @Override
   public void run() {
    // Javaリフレクション使用(別の自作ライブラリ)
    Refrecter.runMethod(object, methodName, args);
    
    android.os.Message msg = new android.os.Message();
    msg.arg1 = 0;
    handler.sendMessage(msg);
   }
  };

  // スレッド生成・実行
  Thread thread = new Thread(runnable);
  thread.start();
  // ダイアログ表示
  mProgressDialog.show();
 }
 
 // 7-2.進捗ダイヤログ付き実行(引数なし)
 @SuppressLint("android.view.WindowLeaked")
 public void runWithProgressDialog(final Object object, final String methodName) {
  // スレッド処理
  Runnable runnable = new Runnable() {
   @Override
   public void run() {
    // // Javaリフレクション使用(別の自作ライブラリ)
    Refrecter.runMethod(object, methodName);
    
    android.os.Message msg = new android.os.Message();
    msg.arg1 = 0;
    handler.sendMessage(msg);
   }
  };

  // スレッド生成・実行
  Thread thread = new Thread(runnable);
  thread.start();
  // ダイアログ表示
  mProgressDialog.show();
 }
 
 // スレッドの終了を受信するハンドラ
 @SuppressLint("HandlerLeak")
 private final Handler handler = new Handler() {
  @Override
  public void handleMessage(android.os.Message msg) {
   mProgressDialog.dismiss();
  };
 };

 protected ProgressDialog mProgressDialog;
 // 水平バーを動かすときにはこの変数を処理内で弄り倒す
 protected int MAX_PROGRESS;
 protected int mProgress;
 
 // 8.進捗ダイヤログのセット(水平バーの場合)
 public ProgressDialog setProgressDialogHorizontal(String title, String message) {
  setProgressDialogBase(title, message);
  mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
  return mProgressDialog;
 }

 // 8.進捗ダイヤログのセット(グルグルマークの場合)
 public ProgressDialog setProgressDialogSpinner(String title, String message) {
  setProgressDialogBase(title, message);
  mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
  return mProgressDialog;
 }
 
 private void setProgressDialogBase(String title, String message) {
  mProgress = 0;
  mProgressDialog = new ProgressDialog(this);
  mProgressDialog.setTitle(title);
  mProgressDialog.setMessage(message);
  mProgressDialog.setMax(MAX_PROGRESS);
 }
}

使い方:

Activityを作る上でライブラリを継承するだけ。


public class MainActivity extends CoreActivity{
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

                sendToast("Hello World"); //みたいな、、
}


Javaは多重継承ができないからActivityを親クラスとして継承して、
更にそれをサブクラスに継承させるデイジーチェーン的な継承は善か悪か?
インタフェースを作ることで幸せになれそうな気がしたが、作り方がわからない。
サブクラスでは継承するだけで、他の一切の余計な手続きはしたくない。

結局わからなかったこと:多重継承!

Javaでは多重継承ができないが、似たようなことをインタフェースを使ってできる内容も見たが、さっぱり意味がわからない。
インタフェース使っても、楽になるのは関数名の記述たった2行程度のもので、
処理をサブクラスに記述するのでは目的とは異なる。

同様のメソッドを備えたServiceの定義

Serviceを継承したクラスを作って中身はActivityのメソッドを焼き直しただけ。。。
醜いだけでなく、様々な弊害が
・ボイラーコード。。
・メンテナンス性最悪。。
・バグの温床。。
・テストの負担が増える。。

ActivityとService共通のメソッド群をわかりやすく共通管理する方法がわからなかった。ここはinterfaceが活躍する場のような気がするのですが、どうやればいいのか分からない。

public class CoreService extends Service{
 // 1.オンラインかどうか確認する
 public boolean isOnline() {
  ConnectivityManager cm = (ConnectivityManager) CoreActivity.this.getSystemService(Context.CONNECTIVITY_SERVICE);
  NetworkInfo netInfo = cm.getActiveNetworkInfo();
  if (netInfo != null && netInfo.isConnectedOrConnecting()) {
   return true;
  }
  return false;
 }
        // 。。。Activityと同様なメソッドを冗長に繰り返し記述しているだけなので、メンテナンス性が悪い。
}

0 コメント:

コメントを投稿