雷って幻想的だよね?

宗教:C#、ラノベ好きの戯言です。※Google Analytics 埋め込みを利用しています。

Visual StudioでのXamarin.Androidのデバッグ

自分が今のところチェックをするところのデバッグのメッセージなどの設定です。

利用するクラス

public static class DebugLog
{
	/// <summary>
	/// ひとつ前の関数の情報を出力する
	/// </summary>
	/// <param name="memberName">基本設定不要</param>
	/// <param name="sourceFilePath">基本設定不要</param>
	/// <param name="sourceLineNumber">基本設定不要</param>
	[Conditional("DEBUG")]
	public static void TraceMessage([System.Runtime.CompilerServices.CallerMemberName] string memberName = "",
		[System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "",
		[System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
	{
		var i = sourceFilePath.LastIndexOf("\\");
		var s = sourceFilePath.Substring(i + 1);

		OutPut(memberName, "ファイル名:" + s + "\t:" + sourceLineNumber + "行");
	}
	/// <summary>
	/// 処理固有の出力を記述する
	/// ※処理ごとに継承して利用する
	/// </summary>
	/// <param name="message"></param>
	[Conditional("DEBUG")]
	private static void OutPut(string fancName, string message)
	{
		Log.Info("プロジェクト名"+ "." + fancName, message);
	}
}

これで出力されたログを表示する
※Debugログが多いのでInfoを設定したほうがいいと思われる。

ツール
Android
デバッグログ

表示した、デバイスログの右側に検索キーワードが存在するので、ここにプロジェクト名を入れると、、、
プロジェクトで絞られる。

その後、より細かくフィルタリングしたい場合は、グリッドのフィルタ機能を利用する。


以上。
とりあえず、全部の関数にログメッセージを仕込んでおけばちょっとしたときに調べやすいかな?と。

Xamarin.Android FileProvider エラー

Java.Lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.ProviderInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference

が表示された場合、以下を行うと、解消されます。 ※Xamarin.Android Android8.0想定

1:Properties/AndroidManifest.xmlに以下を追記する ※ ここに以下を追加

  <provider android:name="android.support.v4.content.FileProvider" 
            android:authorities="${applicationId}.fileprovider" 
            android:exported="false" 
            android:grantUriPermissions="true">

        <meta-data android:name="android.support.FILE_PROVIDER_PATHS" 
                       android:resource="@xml/file_paths"></meta-data>
  </provider>

2:Resourceフォルダに以下のフォルダを追加 ・xml

3:上記で追加したフォルダに以下のファイルを作成し、内容を記述する

3-1:ファイル名

file_paths.xml

3-2:内容

<?xml version="1.0" encoding="utf-8"?> <external-files-path name="my_images" path="Pictures" /> <external-files-path name="my_movies" path="Movies" />

以上。 場合によって、それ以外のエラーが出ると思いますが、それは対処が違うため、再度検索などお願いします。(私は次のエラーが出たのでそれの対処を行うためです)

Xamarin.Androidで更新されたテキストを内部データに連携する方法(外部のMVVMなどを利用しない方法)

Xamarin.Androidで更新されたテキストを内部データに連携する方法
で、かなり詰まったので、同じ人がいないようにとの願いのメモです。

初心者なので、ご指摘あればいただけるとうれしいです。

最後に、クラス全体を載せていますので、説明が不要な方はそちらをご覧ください。

【手順】

  1. BeforeTextChangedでテキスト変更開始を検知
  2. TextChangedで変更することを確定させる
  3. AfterTextChangedで上記を満たした場合に、変更とみて更新を行う
    ※ただし、複数回流れることがあります。
  4. 保存時の動作
    1. フォーカスがある場合のみの保存とする(しないとなんかすごく更新がかかる。恐らくなんか実装が変)
    2. GetViewで保存した、EditTextに紐づけたタグ情報を元に対象のデータを特定
    3. 更新する。
    4. isEdittingはActivityで、保存ボタンを押したときにこのフラグを基準に1度のみ保存動作をさせるため指定

動作したAdapterのまとめです。

public class ListItemDetailAdapter : BaseAdapter<ViewArticleItem>
{
#region メンバ変数
private Activity _activity;
private List<ViewArticleItem> _items;
private DbContext dbContext;
/// <summary>
/// EditTextを変更したかどうか
/// </summary>
private bool isEditting = false;
#endregion

#region 必須処理

public ListItemDetailAdapter(Activity activity, List<ViewArticleItem> items)
{
this._activity = activity;
this._items = items;
dbContext = Common.ConnectDB.GetDBContext();
}

public override long GetItemId(int position) => position;


public override View GetView(int position, View convertView, ViewGroup parent)
{
View view = convertView ?? _activity.LayoutInflater.Inflate(Resource.Layout.ListItemDetailLayout, null);

//対応するプロパティの割り当て
EditText editText = view.FindViewById<EditText>(Resource.Id.editText);
ViewArticleItem item = _items[position];
editText.Text = item.Text;
setTagItemId(editText, item.ItemId);
SetEditEvent(editText);

return view;
}

public override int Count => _items.Count;
public override ViewArticleItem this[int position] => throw new NotImplementedException();

#endregion

#region タグ:ItemIdを設定する

private void setTagItemId(EditText editText, int itemId)
{
editText.SetTag(Resource.Id.editText, itemId);
}

private int getTagItemId(EditText editText)
{
return (int)editText.GetTag(Resource.Id.editText);
}

#endregion

#region イベント処理

private void SetEditEvent(EditText editText)
{
//重複しないようにイベント削除
editText.TextChanged -= EditTextOnTextChanged;
editText.BeforeTextChanged -= EditTextOnBeforeTextChanged;
editText.AfterTextChanged -= TextViewOnAfterTextChanged;
editText.FocusChange -= EditTextOnFocusChange;

//イベント再登録
editText.TextChanged += EditTextOnTextChanged;
editText.BeforeTextChanged += EditTextOnBeforeTextChanged;
editText.AfterTextChanged += TextViewOnAfterTextChanged;
editText.FocusChange += EditTextOnFocusChange;
}

/// <summary>
/// フォーカスが変わった場合
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void EditTextOnFocusChange(object sender, View.FocusChangeEventArgs e)
{
if (isEditting)
{
//変更時にデータを保存する
dbContext.SaveViewArticleItems(GetArticleItems());
DebugMessage.ShowDebugToastShort(Application.Context, "Itemsを保存しました");

isEditting = false;
}
}

private bool isChange = false;
private bool isChanging = false;
private void EditTextOnBeforeTextChanged(object sender, TextChangedEventArgs e)
{
if (isChange == false)isChange = true;
}


private void EditTextOnTextChanged(object sender, TextChangedEventArgs e)
{
if (isChange && e.BeforeCount != e.AfterCount)isChanging = true;
}

/// <summary>
/// 文字変更入力後処理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void TextViewOnAfterTextChanged(object sender, AfterTextChangedEventArgs e)
{
if (false == (isChange && isChanging))return;

//描画中の文字に更新文字を設定する
SaveChangeText((EditText)sender);

isChange = false;
isChanging = false;

}

#endregion

#region 外部利用処理

public List<ViewArticleItem> GetArticleItems()
{
return _items;
}

#endregion

#region 内部処理

/// <summary>
/// 変更を保持データに反映する
/// </summary>
/// <param name="editText">変更データを持つEditText</param>
private void SaveChangeText(EditText editText)
{
if (editText.HasFocus == false) return;//これがないと、アクション時などに、一覧表が更新されてしまう

//更新対象を特定するために、ItemIdを取得する
var itemId = getTagItemId(editText);

//データに反映する
var item = _items.First(x => x.ItemId == itemId);
item.Text = editText.Text;
isEditting = true;
}

#endregion

}

 

 

Visual Studio かっこの色を階層ごとにそろえる

本日、TwitterVSCodeで鍵かっこで、色をそろえる、拡張機能があるというのを見て、すごくいい! と思った。

Bracket Pair Colorizer - Visual Studio Marketplace

そのツイートにVisualStudio版の名前 Viasforaが乗っていてさっそく入れた。

が、すごく残念なことに、かっこ以外の色も変わるため、とってもカラフルになりすぎて、エラーなのか、階層なのかさパリわからなくなってしまった。 設定いじってどうにかできないか試行錯誤…

背景が黒の場合、の設定ができたので、自分用にアップしておく もっといい設定があったら知りたいな

Dropbox - 拡張機能Viasfora - Simplify your life

Xamarin.Androidで想定外の動作をした時にすること

もし、仮に、これを見た人がいたら気に留めていただきたいことを記述させていただきます。

Xamarin.Androidを開発していて、実装とエミュレーターの動作が違った場合、ソースコードを戻す前にしていただきたいことがあります。

それは

エミュレーターAndroidの再起動です。

私は、はまりました。(T-T)

画面表示の右側の電源ボタンを長押しするとReStartが表示されます。

これを行って、端末を再起動してください。

私の場合は、クリック関連のイベントがイメージ通りにいかなかったのでソース戻しましたが、再起動したところ、治りました。

同じ悲しみを負う方が少ないことを祈ります。

orz

Xamarin.AndroidのListViewで下線を削除する

調べても適切なのが見つからなかったので…

一般的にonCreateで生成される場合に、ListViewを取得すると思うのでその直後で変更してあげれば問題が無かった

初期宣言

private ListView mainListView;

バインド

mainListView = FindViewById(Resource.Id.listView1);

下線削除

mainListView.DividerHeight = 0;

戻すときは以下を変数に保存しておく(型:Android.Graphics.Drawables.GradientDrawable)

(GradientDrawable)mainListView.Divider

以上です。 私と同じ苦しみの方の目に留まれば幸いです。

Xamarin.AndroidでSQLiteの中身を確認する

以下の方法でもよいですが、より良い方法に出会いました。
生成したSqliteのファイルをDropboxに上げる方法が、バージョンに依存せずに利用できるため、良いと考えております。
気になる方はどうブログの別記事をご参照ください。

確認環境
VisualStudio 2017 15.7.5
Androidエミュレータ
 デフォルトの KitKat4.4

※以下のコピーはOreo8.0で確認したところPermissionErrorでしたのでご注意ください。(自分がはまった)

ツール
Android
 →Android adb コマンドプロンプト

コマンド

コマンド 意味
-e エミュレータへコマンドを送る
-d 端末にコマンドを送る
-s 端末指定
--help ヘルプ

https://developer.android.com/studio/command-line/adb?hl=ja

SQLiteBackUp

コピーコマンド

run-as プロジェクト名 cat file/DB名.db3 > /sdcard/DB名.db3

Windowsへの配置コマンド

adb -e pull sdcard/DB名.db3 d:\AndroidDebug

情報がいろいろあって、自分の環境に合うのが見つからなかったので作成。


以下、コマンドのまとめ。

adb -e shell
run-as プロジェクト名 cat file/DB名.db3 > /sdcard/DB名.db3
exit
adb -e pull sdcard/DB名.db3 d:\AndroidDebug

※AndroidDebugはコピー先のフォルダ名(適当)